Enable WASI tests on Windows CI (#2699)

Most of the WASI filesystem tests require at least creating/deleting a
file to test filesystem functionality so some additional filesystem APIs
have been implemented on Windows so we can test what has been
implemented so far. For those WASI functions which haven't been
implemented, we skip the tests. These will be implemented in a future PR
after which we can remove the relevant filters.

Additionally, in order to run the WASI socket and thread tests, we need
to install the wasi-sdk in CI and build the test source code prior to
running the tests.
This commit is contained in:
zoraaver
2023-11-06 11:24:06 +00:00
committed by GitHub
parent 3624895204
commit 13875f43c6
9 changed files with 726 additions and 30 deletions

View File

@ -146,8 +146,19 @@ typedef enum windows_access_mode {
windows_access_mode_write = 1 << 1
} windows_access_mode;
// These enum values are defined to be the same as the corresponding WASI
// fdflags so they can be used interchangeably.
typedef enum windows_fdflags {
windows_fdflags_append = 1 << 0,
windows_fdflags_dsync = 1 << 1,
windows_fdflags_nonblock = 1 << 2,
windows_fdflags_rsync = 1 << 3,
windows_fdflags_sync = 1 << 4
} windows_fdflags;
typedef struct windows_handle {
windows_handle_type type;
windows_fdflags fdflags;
windows_access_mode access_mode;
union {
HANDLE handle;

View File

@ -7,6 +7,10 @@
#include "libc_errno.h"
#include "win_util.h"
#include "PathCch.h"
#pragma comment(lib, "Pathcch.lib")
#define CHECK_VALID_HANDLE_WITH_RETURN_VALUE(win_handle, ret) \
do { \
if ((win_handle) == NULL \
@ -188,6 +192,79 @@ get_handle_filepath(HANDLE handle, wchar_t *buf, DWORD buf_size)
return __WASI_ESUCCESS;
}
static __wasi_errno_t
convert_hresult_error_code(HRESULT error_code)
{
switch (error_code) {
case E_OUTOFMEMORY:
return __WASI_ENOMEM;
case E_INVALIDARG:
default:
return __WASI_EINVAL;
}
}
// Returns the absolute filepath from the relative path to the directory
// associated with the provided handle.
static __wasi_errno_t
get_absolute_filepath(HANDLE handle, const char *relative_path,
wchar_t *absolute_path, size_t buf_len)
{
wchar_t handle_path[PATH_MAX];
__wasi_errno_t error = get_handle_filepath(handle, handle_path, PATH_MAX);
if (error != __WASI_ESUCCESS)
return error;
wchar_t relative_wpath[PATH_MAX];
error = convert_to_wchar(relative_path, relative_wpath, PATH_MAX);
if (error != __WASI_ESUCCESS)
return error;
HRESULT ret =
PathCchCombine(absolute_path, buf_len, handle_path, relative_wpath);
if (ret != S_OK)
error = convert_hresult_error_code(ret);
return error;
}
static bool
has_directory_attribute(DWORD attributes)
{
if (attributes == INVALID_FILE_ATTRIBUTES)
return false;
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
static bool
is_directory(const wchar_t *path)
{
DWORD attributes = GetFileAttributesW(path);
return has_directory_attribute(attributes);
}
static bool
has_symlink_attribute(DWORD attributes)
{
if (attributes == INVALID_FILE_ATTRIBUTES)
return false;
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
}
static bool
is_symlink(const wchar_t *path)
{
DWORD attributes = GetFileAttributesW(path);
return has_symlink_attribute(attributes);
}
static void
init_dir_stream(os_dir_stream dir_stream, os_file_handle handle)
{
@ -275,17 +352,17 @@ create_handle(wchar_t *path, bool is_dir, bool follow_symlink, bool readonly)
DWORD desired_access = GENERIC_READ;
if (!readonly) {
if (!readonly)
desired_access |= GENERIC_WRITE;
else
create_params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
}
return CreateFile2(path, desired_access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
OPEN_EXISTING, &create_params);
}
#if WINAPI_PARTITION_DESKTOP
#if WINAPI_PARTITION_DESKTOP == 0
// Modifies the given path in place and replaces it with the filename component
// (including the extension) of the path.
static __wasi_errno_t
@ -387,6 +464,7 @@ get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf)
windows_handle dir_handle = { .access_mode = windows_access_mode_read,
.raw = { .handle = raw_dir_handle },
.fdflags = 0,
.type = windows_handle_type_file };
windows_dir_stream dir_stream;
init_dir_stream(&dir_stream, &dir_handle);
@ -484,7 +562,7 @@ get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf)
return error;
}
#endif /* end of !WINAPI_PARTITION_DESKTOP */
#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */
static __wasi_errno_t
get_file_information(os_file_handle handle, __wasi_filestat_t *buf)
@ -536,7 +614,8 @@ os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
{
CHECK_VALID_HANDLE(handle);
return __WASI_ENOSYS;
*flags = handle->fdflags;
return __WASI_ESUCCESS;
}
__wasi_errno_t
@ -605,6 +684,7 @@ os_open_preopendir(const char *path, os_file_handle *out)
(*out)->type = windows_handle_type_file;
(*out)->raw.handle = dir_handle;
(*out)->fdflags = 0;
(*out)->access_mode = windows_access_mode_read;
return error;
@ -616,8 +696,135 @@ os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
wasi_libc_file_access_mode access_mode, os_file_handle *out)
{
CHECK_VALID_FILE_HANDLE(handle);
*out = BH_MALLOC(sizeof(windows_handle));
return __WASI_ENOSYS;
if (*out == NULL)
return __WASI_ENOMEM;
(*out)->type = windows_handle_type_file;
(*out)->fdflags = fs_flags;
(*out)->raw.handle = INVALID_HANDLE_VALUE;
DWORD attributes = FILE_FLAG_BACKUP_SEMANTICS;
if ((fs_flags & (__WASI_FDFLAG_SYNC | __WASI_FDFLAG_RSYNC)) != 0)
attributes |= (FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING);
if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0)
attributes |= FILE_FLAG_WRITE_THROUGH;
if ((oflags & __WASI_O_DIRECTORY) != 0) {
attributes |= FILE_ATTRIBUTE_DIRECTORY;
oflags &= ~(__WASI_O_DIRECTORY);
}
// Use async operations on the handle if it's not a directory
else {
attributes |= FILE_FLAG_OVERLAPPED;
}
__wasi_errno_t error = __WASI_ESUCCESS;
DWORD access_flags = 0;
if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) {
if ((attributes & (FILE_FLAG_NO_BUFFERING)) != 0) {
// FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually
// exclusive - CreateFile2 returns 87 (invalid parameter) when they
// are combined.
error = __WASI_ENOTSUP;
goto fail;
}
access_flags |= FILE_APPEND_DATA;
}
switch (access_mode) {
case WASI_LIBC_ACCESS_MODE_READ_ONLY:
access_flags |= GENERIC_READ;
(*out)->access_mode = windows_access_mode_read;
break;
case WASI_LIBC_ACCESS_MODE_WRITE_ONLY:
access_flags |= GENERIC_WRITE;
(*out)->access_mode = windows_access_mode_write;
break;
case WASI_LIBC_ACCESS_MODE_READ_WRITE:
access_flags |= GENERIC_WRITE | GENERIC_READ;
(*out)->access_mode =
windows_access_mode_read | windows_access_mode_write;
break;
}
DWORD creation_disposition = 0;
switch (oflags) {
case __WASI_O_CREAT | __WASI_O_EXCL:
case __WASI_O_CREAT | __WASI_O_EXCL | __WASI_O_TRUNC:
creation_disposition = CREATE_NEW;
break;
case __WASI_O_CREAT | __WASI_O_TRUNC:
creation_disposition = CREATE_ALWAYS;
break;
case __WASI_O_CREAT:
creation_disposition = OPEN_ALWAYS;
break;
case 0:
case __WASI_O_EXCL:
creation_disposition = OPEN_EXISTING;
break;
case __WASI_O_TRUNC:
case __WASI_O_EXCL | __WASI_O_TRUNC:
creation_disposition = TRUNCATE_EXISTING;
// CreateFile2 requires write access if we truncate the file upon
// opening
access_flags |= GENERIC_WRITE;
break;
}
wchar_t absolute_path[PATH_MAX];
error = get_absolute_filepath(handle->raw.handle, path, absolute_path,
PATH_MAX);
if (error != __WASI_ESUCCESS)
goto fail;
if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0)
attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
// Check that we're not trying to open an existing file as a directory.
// Windows doesn't seem to throw an error in this case so add an
// explicit check.
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0
&& creation_disposition == OPEN_EXISTING
&& !is_directory(absolute_path)) {
error = __WASI_ENOTDIR;
goto fail;
}
CREATEFILE2_EXTENDED_PARAMETERS create_params;
create_params.dwSize = sizeof(create_params);
create_params.dwFileAttributes = attributes & 0xFFF;
create_params.dwFileFlags = attributes & 0xFFF00000;
create_params.dwSecurityQosFlags = 0;
create_params.lpSecurityAttributes = NULL;
create_params.hTemplateFile = NULL;
(*out)->raw.handle =
CreateFile2(absolute_path, access_flags,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
creation_disposition, &create_params);
if ((*out)->raw.handle == INVALID_HANDLE_VALUE) {
error = convert_windows_error_code(GetLastError());
goto fail;
}
return error;
fail:
if (*out != NULL) {
if ((*out)->raw.handle != INVALID_HANDLE_VALUE)
CloseHandle((*out)->raw.handle);
BH_FREE(*out);
}
return error;
}
__wasi_errno_t
@ -656,13 +863,79 @@ os_close(os_file_handle handle, bool is_stdio)
return __WASI_ESUCCESS;
}
static __wasi_errno_t
read_data_at_offset(HANDLE handle, const struct __wasi_iovec_t *iov, int iovcnt,
__wasi_filesize_t offset, size_t *nwritten)
{
OVERLAPPED *read_operations =
BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt));
if (read_operations == NULL)
return __WASI_ENOMEM;
ULARGE_INTEGER query_offset = { .QuadPart = offset };
__wasi_errno_t error = __WASI_ESUCCESS;
size_t total_bytes_read = 0;
const __wasi_iovec_t *current = iov;
int successful_read_count = 0;
for (int i = 0; i < iovcnt; ++i, ++current) {
read_operations[i].Internal = 0;
read_operations[i].InternalHigh = 0;
read_operations[i].Offset = query_offset.LowPart;
read_operations[i].OffsetHigh = query_offset.HighPart;
read_operations[i].hEvent = NULL;
if (!ReadFileEx(handle, current->buf, (DWORD)current->buf_len,
&read_operations[i], NULL)) {
DWORD win_error = GetLastError();
if (win_error != ERROR_IO_PENDING) {
error = convert_windows_error_code(win_error);
break;
}
}
++successful_read_count;
query_offset.QuadPart += (DWORD)current->buf_len;
}
// Get the result of all the asynchronous read operations
for (int i = 0; i < successful_read_count; ++i) {
DWORD bytes_transferred = 0;
if (!GetOverlappedResult(handle, &read_operations[i],
&bytes_transferred, true)) {
DWORD win_error = GetLastError();
if (win_error != ERROR_HANDLE_EOF)
error = convert_windows_error_code(win_error);
else
total_bytes_read += (size_t)bytes_transferred;
CancelIo(handle);
for (int j = i + 1; j < iovcnt; ++j) {
GetOverlappedResult(handle, &read_operations[j],
&bytes_transferred, true);
}
break;
}
total_bytes_read += (size_t)bytes_transferred;
}
*nwritten = total_bytes_read;
BH_FREE(read_operations);
return error;
}
__wasi_errno_t
os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
__wasi_filesize_t offset, size_t *nread)
{
CHECK_VALID_FILE_HANDLE(handle);
return __WASI_ENOSYS;
return read_data_at_offset(handle->raw.handle, iov, iovcnt, offset, nread);
}
__wasi_errno_t
@ -671,7 +944,90 @@ os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
{
CHECK_VALID_HANDLE(handle);
return __WASI_ENOSYS;
LARGE_INTEGER current_offset = { .QuadPart = 0 };
// Seek to the current offset before reading
int ret = SetFilePointerEx(handle->raw.handle, current_offset,
&current_offset, FILE_CURRENT);
if (ret == 0)
return convert_windows_error_code(GetLastError());
__wasi_errno_t error =
read_data_at_offset(handle->raw.handle, iov, iovcnt,
(__wasi_filesize_t)current_offset.QuadPart, nread);
if (error != __WASI_ESUCCESS)
return error;
current_offset.QuadPart += (LONGLONG)(*nread);
// Update the current offset to match how many bytes we've read
ret =
SetFilePointerEx(handle->raw.handle, current_offset, NULL, FILE_BEGIN);
if (ret == 0)
error = convert_windows_error_code(GetLastError());
return error;
}
static __wasi_errno_t
write_data_at_offset(HANDLE handle, const struct __wasi_ciovec_t *iov,
int iovcnt, __wasi_filesize_t offset, size_t *nwritten)
{
OVERLAPPED *write_operations =
BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt));
if (write_operations == NULL)
return __WASI_ENOMEM;
ULARGE_INTEGER query_offset = { .QuadPart = offset };
__wasi_errno_t error = __WASI_ESUCCESS;
size_t total_bytes_written = 0;
const __wasi_ciovec_t *current = iov;
int successful_write_count = 0;
for (int i = 0; i < iovcnt; ++i, ++current) {
write_operations[i].Internal = 0;
write_operations[i].InternalHigh = 0;
write_operations[i].Offset = query_offset.LowPart;
write_operations[i].OffsetHigh = query_offset.HighPart;
write_operations[i].hEvent = NULL;
if (!WriteFileEx(handle, current->buf, (DWORD)current->buf_len,
&write_operations[i], NULL)) {
DWORD win_error = GetLastError();
if (win_error != ERROR_IO_PENDING) {
error = convert_windows_error_code(win_error);
break;
}
}
++successful_write_count;
query_offset.QuadPart += (DWORD)current->buf_len;
}
// Get the result of all the asynchronous writes
for (int i = 0; i < successful_write_count; ++i) {
DWORD bytes_transferred = 0;
if (!GetOverlappedResult(handle, &write_operations[i],
&bytes_transferred, true)) {
error = convert_windows_error_code(GetLastError());
CancelIo(handle);
for (int j = i + 1; j < iovcnt; ++j) {
GetOverlappedResult(handle, &write_operations[j],
&bytes_transferred, true);
}
break;
}
total_bytes_written += (size_t)bytes_transferred;
}
*nwritten = total_bytes_written;
BH_FREE(write_operations);
return error;
}
__wasi_errno_t
@ -680,7 +1036,8 @@ os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
{
CHECK_VALID_FILE_HANDLE(handle);
return __WASI_ENOSYS;
return write_data_at_offset(handle->raw.handle, iov, iovcnt, offset,
nwritten);
}
__wasi_errno_t
@ -689,7 +1046,31 @@ os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
{
CHECK_VALID_HANDLE(handle);
return __WASI_ENOSYS;
bool append = (handle->fdflags & windows_fdflags_append) != 0;
LARGE_INTEGER write_offset = { .QuadPart = 0 };
DWORD move_method = append ? FILE_END : FILE_CURRENT;
int ret = SetFilePointerEx(handle->raw.handle, write_offset, &write_offset,
move_method);
if (ret == 0)
return convert_windows_error_code(GetLastError());
__wasi_errno_t error = write_data_at_offset(
handle->raw.handle, iov, iovcnt,
(__wasi_filesize_t)write_offset.QuadPart, nwritten);
if (error != __WASI_ESUCCESS)
return error;
write_offset.QuadPart += (LONGLONG)(*nwritten);
// Update the write offset to match how many bytes we've written
ret = SetFilePointerEx(handle->raw.handle, write_offset, NULL, FILE_BEGIN);
if (ret == 0)
error = convert_windows_error_code(GetLastError());
return error;
}
__wasi_errno_t
@ -735,7 +1116,151 @@ os_readlinkat(os_file_handle handle, const char *path, char *buf,
{
CHECK_VALID_FILE_HANDLE(handle);
return __WASI_ENOSYS;
wchar_t symlink_path[PATH_MAX];
__wasi_errno_t error =
get_absolute_filepath(handle->raw.handle, path, symlink_path, PATH_MAX);
if (error != __WASI_ESUCCESS)
return error;
DWORD symlink_attributes = GetFileAttributesW(symlink_path);
if (!has_symlink_attribute(symlink_attributes))
return __WASI_EINVAL;
HANDLE link_handle = create_handle(
symlink_path, has_directory_attribute(symlink_attributes), false, true);
if (link_handle == INVALID_HANDLE_VALUE)
return convert_windows_error_code(GetLastError());
#if WINAPI_PARTITION_DESKTOP != 0
// MinGW32 already has a definition for REPARSE_DATA_BUFFER
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
// See
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer
// for more details.
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#endif
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)buffer;
if (!DeviceIoControl(link_handle, FSCTL_GET_REPARSE_POINT, NULL, 0, &buffer,
sizeof(buffer), NULL, NULL)) {
error = convert_windows_error_code(GetLastError());
goto fail;
}
int wbufsize = 0;
wchar_t *wbuf = NULL;
// The following checks are taken from the libuv windows filesystem
// implementation,
// https://github.com/libuv/libuv/blob/v1.x/src/win/fs.c#L181-L244. Real
// symlinks can contain pretty much anything, but the only thing we really
// care about is undoing the implicit conversion to an NT namespaced path
// that CreateSymbolicLink will perform on absolute paths.
if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
wbuf = reparse_data->SymbolicLinkReparseBuffer.PathBuffer
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset
/ sizeof(wchar_t));
wbufsize = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength
/ sizeof(wchar_t);
if (wbufsize >= 4 && wbuf[0] == L'\\' && wbuf[1] == L'?'
&& wbuf[2] == L'?' && wbuf[3] == L'\\') {
// Starts with \??\
if (wbufsize >= 6
&& ((wbuf[4] >= L'A' && wbuf[4] <= L'Z')
|| (wbuf[4] >= L'a' && wbuf[4] <= L'z'))
&& wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\'))
{
// \??\<drive>:\
wbuf += 4;
wbufsize -= 4;
}
else if (wbufsize >= 8 && (wbuf[4] == L'U' || wbuf[4] == L'u')
&& (wbuf[5] == L'N' || wbuf[5] == L'n')
&& (wbuf[6] == L'C' || wbuf[6] == L'c')
&& wbuf[7] == L'\\')
{
// \??\UNC\<server>\<share>\ - make sure the final path looks like \\<server>\<share>\
wbuf += 6;
wbuf[0] = L'\\';
wbufsize -= 6;
}
}
}
else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
// Junction
wbuf = reparse_data->MountPointReparseBuffer.PathBuffer
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset
/ sizeof(wchar_t));
wbufsize = reparse_data->MountPointReparseBuffer.SubstituteNameLength
/ sizeof(wchar_t);
// Only treat junctions that look like \??\<drive>:\ as a symlink.
if (!(wbufsize >= 6 && wbuf[0] == L'\\' && wbuf[1] == L'?'
&& wbuf[2] == L'?' && wbuf[3] == L'\\'
&& ((wbuf[4] >= L'A' && wbuf[4] <= L'Z')
|| (wbuf[4] >= L'a' && wbuf[4] <= L'z'))
&& wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\'))) {
error = __WASI_EINVAL;
goto fail;
}
/* Remove leading \??\ */
wbuf += 4;
wbufsize -= 4;
}
else {
error = __WASI_EINVAL;
goto fail;
}
if (wbuf != NULL)
*nread = (size_t)WideCharToMultiByte(CP_UTF8, 0, wbuf, wbufsize, buf,
(int)bufsize, NULL, NULL);
if (*nread == 0 && wbuf != NULL) {
DWORD win_error = GetLastError();
if (win_error == ERROR_INSUFFICIENT_BUFFER)
*nread = bufsize;
else
error = convert_windows_error_code(win_error);
}
#else
error = __WASI_ENOTSUP;
#endif
fail:
CloseHandle(link_handle);
return error;
}
__wasi_errno_t
@ -762,7 +1287,19 @@ os_mkdirat(os_file_handle handle, const char *path)
{
CHECK_VALID_FILE_HANDLE(handle);
return __WASI_ENOSYS;
wchar_t absolute_path[PATH_MAX];
__wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path,
absolute_path, PATH_MAX);
if (error != __WASI_ESUCCESS)
return error;
bool success = CreateDirectoryW(absolute_path, NULL);
if (!success)
error = convert_windows_error_code(GetLastError());
return error;
}
__wasi_errno_t
@ -780,7 +1317,28 @@ os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
{
CHECK_VALID_FILE_HANDLE(handle);
return __WASI_ENOSYS;
wchar_t absolute_path[PATH_MAX];
__wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path,
absolute_path, PATH_MAX);
if (error != __WASI_ESUCCESS)
return error;
DWORD attributes = GetFileAttributesW(absolute_path);
if (has_symlink_attribute(attributes)) {
// Override is_dir for symlinks. A symlink to a directory counts
// as a directory itself in Windows.
is_dir = has_directory_attribute(attributes);
}
int ret =
is_dir ? RemoveDirectoryW(absolute_path) : DeleteFileW(absolute_path);
if (ret == 0)
error = convert_windows_error_code(GetLastError());
return error;
}
__wasi_errno_t
@ -822,6 +1380,7 @@ create_stdio_handle(HANDLE raw_stdio_handle, DWORD stdio)
stdio_handle->type = windows_handle_type_file;
stdio_handle->access_mode =
windows_access_mode_read | windows_access_mode_write;
stdio_handle->fdflags = 0;
if (raw_stdio_handle == INVALID_HANDLE_VALUE)
raw_stdio_handle = GetStdHandle(stdio);

View File

@ -70,6 +70,7 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
(*sock)->type = windows_handle_type_socket;
(*sock)->access_mode = windows_access_mode_read | windows_access_mode_write;
(*sock)->fdflags = 0;
if (is_ipv4) {
af = AF_INET;
@ -174,6 +175,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
(*sock)->type = windows_handle_type_socket;
(*sock)->access_mode = windows_access_mode_read | windows_access_mode_write;
(*sock)->fdflags = 0;
(*sock)->raw.socket =
accept(server_sock->raw.socket, (struct sockaddr *)&addr_tmp, &len);