From 2636f2811d816244756c57e8fe0c200e8ec15e4f Mon Sep 17 00:00:00 2001 From: Zoraaver Singh Date: Wed, 27 Sep 2023 23:07:32 +0100 Subject: [PATCH] Implement remaining Windows filesystem functions Now that the filesystem implementation is now complete, the previous test filters on Windows can be removed. Some of the tests only pass when certain environment variables have been set on Windows so an extra step has been added in the wasi test runner script to modify the test config files before the tests begin. --- core/shared/platform/windows/win_file.c | 505 +++++++++++++++--- core/shared/platform/windows/win_util.c | 22 +- core/shared/platform/windows/win_util.h | 3 + .../windows/wasi_filtered_tests.json | 30 +- .../wasi-test-script/run_wasi_tests.sh | 15 + 5 files changed, 462 insertions(+), 113 deletions(-) diff --git a/core/shared/platform/windows/win_file.c b/core/shared/platform/windows/win_file.c index 2c4e19f8bc..63dfb5b5f6 100644 --- a/core/shared/platform/windows/win_file.c +++ b/core/shared/platform/windows/win_file.c @@ -213,19 +213,18 @@ has_symlink_attribute(DWORD attributes) return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } -static bool -is_symlink(const wchar_t *path) +static void +init_dir_stream(os_dir_stream dir_stream, os_file_handle handle) { - DWORD attributes = GetFileAttributesW(path); - - return has_symlink_attribute(attributes); + dir_stream->cursor = 0; + dir_stream->handle = handle; + dir_stream->cookie = 0; } static void -init_dir_stream(os_dir_stream dir_stream, os_file_handle handle) +reset_dir_stream(os_dir_stream dir_stream) { dir_stream->cursor = 0; - dir_stream->handle = handle; dir_stream->cookie = 0; } @@ -562,7 +561,32 @@ os_fstatat(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; + + windows_handle resolved_handle = { + .type = windows_handle_type_file, + .fdflags = 0, + .raw = { .handle = create_handle( + absolute_path, is_directory(absolute_path), + ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0), + true) }, + .access_mode = windows_access_mode_read + }; + + if (resolved_handle.raw.handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + + error = get_file_information(&resolved_handle, buf); + + CloseHandle(resolved_handle.raw.handle); + + return error; } __wasi_errno_t @@ -579,7 +603,33 @@ os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) { CHECK_VALID_HANDLE(handle); - return __WASI_ENOSYS; + if (handle->type == windows_handle_type_socket + && (((handle->fdflags ^ flags) & __WASI_FDFLAG_NONBLOCK) != 0)) { + u_long non_block = flags & __WASI_FDFLAG_NONBLOCK; + + int ret = ioctlsocket(handle->raw.socket, (long)FIONBIO, &non_block); + + if (ret != 0) + return convert_winsock_error_code(WSAGetLastError()); + + if (non_block) + handle->fdflags |= __WASI_FDFLAG_NONBLOCK; + else + handle->fdflags &= ~__WASI_FDFLAG_NONBLOCK; + return __WASI_ESUCCESS; + } + + // It's not supported setting FILE_FLAG_WRITE_THROUGH or + // FILE_FLAG_NO_BUFFERING via SetFileAttributes so __WASI_FDFLAG_APPEND is + // the only flags we can do anything with. + if (((handle->fdflags ^ flags) & __WASI_FDFLAG_APPEND) != 0) { + if ((flags & __WASI_FDFLAG_APPEND) != 0) + handle->fdflags |= __WASI_FDFLAG_APPEND; + else + handle->fdflags &= ~__WASI_FDFLAG_APPEND; + } + + return __WASI_ESUCCESS; } __wasi_errno_t @@ -599,12 +649,21 @@ os_file_get_access_mode(os_file_handle handle, return __WASI_ESUCCESS; } +static __wasi_errno_t +flush_file_buffers_on_handle(HANDLE handle) +{ + bool success = FlushFileBuffers(handle); + + return success ? __WASI_ESUCCESS + : convert_windows_error_code(GetLastError()); +} + __wasi_errno_t os_fdatasync(os_file_handle handle) { CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + return flush_file_buffers_on_handle(handle->raw.handle); } __wasi_errno_t @@ -612,7 +671,7 @@ os_fsync(os_file_handle handle) { CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + return flush_file_buffers_on_handle(handle->raw.handle); } __wasi_errno_t @@ -680,16 +739,6 @@ os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags, __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: @@ -743,14 +792,30 @@ os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags, 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; + // Windows doesn't seem to throw an error for the following cases where the + // file/directory already exists so add explicit checks. + if (creation_disposition == OPEN_EXISTING) { + DWORD file_attributes = GetFileAttributesW(absolute_path); + + if (file_attributes != INVALID_FILE_ATTRIBUTES) { + bool is_dir = file_attributes & FILE_ATTRIBUTE_DIRECTORY; + bool is_symlink = file_attributes & FILE_ATTRIBUTE_REPARSE_POINT; + // Check that we're not trying to open an existing file/symlink as a + // directory. + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 + && (!is_dir || is_symlink)) { + error = __WASI_ENOTDIR; + goto fail; + } + + // Check that we're not trying to open an existing symlink with + // O_NOFOLLOW. + if ((file_attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 + && (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) { + error = __WASI_ELOOP; + goto fail; + } + } } CREATEFILE2_EXTENDED_PARAMETERS create_params; @@ -1035,7 +1100,31 @@ os_fallocate(os_file_handle handle, __wasi_filesize_t offset, { CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + LARGE_INTEGER current_file_size; + int ret = GetFileSizeEx(handle->raw.handle, ¤t_file_size); + + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + if (offset > INT64_MAX || length > INT64_MAX || offset + length > INT64_MAX) + return __WASI_EINVAL; + + // The best we can do here is to increase the size of the file if it's less + // than the offset + length. + const LONGLONG requested_size = (LONGLONG)(offset + length); + + FILE_END_OF_FILE_INFO end_of_file_info; + end_of_file_info.EndOfFile.QuadPart = requested_size; + + if (requested_size <= current_file_size.QuadPart) + return __WASI_ESUCCESS; + + bool success = + SetFileInformationByHandle(handle->raw.handle, FileEndOfFileInfo, + &end_of_file_info, sizeof(end_of_file_info)); + + return success ? __WASI_ESUCCESS + : convert_windows_error_code(GetLastError()); } __wasi_errno_t @@ -1043,7 +1132,42 @@ os_ftruncate(os_file_handle handle, __wasi_filesize_t size) { CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + FILE_END_OF_FILE_INFO end_of_file_info; + end_of_file_info.EndOfFile.QuadPart = (LONGLONG)size; + + bool success = + SetFileInformationByHandle(handle->raw.handle, FileEndOfFileInfo, + &end_of_file_info, sizeof(end_of_file_info)); + + return success ? __WASI_ESUCCESS + : convert_windows_error_code(GetLastError()); +} + +static __wasi_errno_t +set_file_times(HANDLE handle, __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags) +{ + FILETIME atim = { 0, 0 }; + FILETIME mtim = { 0, 0 }; + + if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) { + atim = convert_wasi_timestamp_to_filetime(access_time); + } + else if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) { + GetSystemTimePreciseAsFileTime(&atim); + } + + if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) { + mtim = convert_wasi_timestamp_to_filetime(modification_time); + } + else if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) { + GetSystemTimePreciseAsFileTime(&mtim); + } + + bool success = SetFileTime(handle, NULL, &atim, &mtim); + + return success ? __WASI_ESUCCESS + : convert_windows_error_code(GetLastError()); } __wasi_errno_t @@ -1052,7 +1176,8 @@ os_futimens(os_file_handle handle, __wasi_timestamp_t access_time, { CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + return set_file_times(handle->raw.handle, access_time, modification_time, + fstflags); } __wasi_errno_t @@ -1063,7 +1188,26 @@ os_utimensat(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; + + HANDLE resolved_handle = create_handle( + absolute_path, is_directory(absolute_path), + (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0, false); + + if (resolved_handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + + error = set_file_times(resolved_handle, access_time, modification_time, + fstflags); + + CloseHandle(resolved_handle); + + return error; } __wasi_errno_t @@ -1213,7 +1357,7 @@ os_readlinkat(os_file_handle handle, const char *path, char *buf, } #else error = __WASI_ENOTSUP; -#endif +#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */ fail: CloseHandle(link_handle); return error; @@ -1224,18 +1368,96 @@ os_linkat(os_file_handle from_handle, const char *from_path, os_file_handle to_handle, const char *to_path, __wasi_lookupflags_t lookup_flags) { +#if WINAPI_PARTITION_DESKTOP == 0 + return __WASI_ENOSYS; +#else CHECK_VALID_FILE_HANDLE(from_handle); CHECK_VALID_FILE_HANDLE(to_handle); - return __WASI_ENOSYS; + wchar_t absolute_from_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath( + from_handle->raw.handle, from_path, absolute_from_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + wchar_t absolute_to_path[PATH_MAX]; + error = get_absolute_filepath(to_handle->raw.handle, to_path, + absolute_to_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + size_t to_path_len = strlen(to_path); + + // Windows doesn't throw an error in the case that the new path has a + // trailing slash but the target to link to is a file. + if (to_path[to_path_len - 1] == '/' + || to_path[to_path_len - 1] == '\\' + && !is_directory(absolute_from_path)) { + return __WASI_ENOENT; + } + + int ret = CreateHardLinkW(absolute_to_path, absolute_from_path, NULL); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */ } __wasi_errno_t os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path) { +#if WINAPI_PARTITION_DESKTOP == 0 + return __WASI_ENOSYS; +#else CHECK_VALID_FILE_HANDLE(handle); - return __WASI_ENOSYS; + wchar_t absolute_new_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, new_path, + absolute_new_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + DWORD target_type = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + + wchar_t old_wpath[PATH_MAX]; + size_t old_path_len = 0; + + error = convert_to_wchar(old_path, old_wpath, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + wchar_t absolute_old_path[PATH_MAX]; + error = get_absolute_filepath(handle->raw.handle, old_path, + absolute_old_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + if (is_directory(absolute_old_path)) + target_type |= SYMBOLIC_LINK_FLAG_DIRECTORY; + + bool success = + CreateSymbolicLinkW(absolute_new_path, old_wpath, target_type); + + if (!success) { + DWORD win_error = GetLastError(); + + // Return a more useful error code if a file/directory already exists at + // the symlink location. + if (win_error == ERROR_ACCESS_DENIED || win_error == ERROR_INVALID_NAME) + error = __WASI_ENOENT; + else + error = convert_windows_error_code(GetLastError()); + } +fail: + return error; +#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */ } __wasi_errno_t @@ -1265,56 +1487,28 @@ os_renameat(os_file_handle old_handle, const char *old_path, CHECK_VALID_FILE_HANDLE(old_handle); CHECK_VALID_FILE_HANDLE(new_handle); - return __WASI_ENOSYS; -} - -__wasi_errno_t -os_unlinkat(os_file_handle handle, const char *path, bool is_dir) -{ - CHECK_VALID_FILE_HANDLE(handle); - - wchar_t absolute_path[PATH_MAX]; - __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, - absolute_path, PATH_MAX); + wchar_t old_absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath( + old_handle->raw.handle, old_path, old_absolute_path, PATH_MAX); if (error != __WASI_ESUCCESS) return error; - DWORD attributes = GetFileAttributesW(absolute_path); + wchar_t new_absolute_path[PATH_MAX]; + error = get_absolute_filepath(new_handle->raw.handle, new_path, + new_absolute_path, PATH_MAX); - 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 (error != __WASI_ESUCCESS) + return error; + int ret = MoveFileExW(old_absolute_path, new_absolute_path, + MOVEFILE_REPLACE_EXISTING); if (ret == 0) error = convert_windows_error_code(GetLastError()); return error; } -__wasi_errno_t -os_lseek(os_file_handle handle, __wasi_filedelta_t offset, - __wasi_whence_t whence, __wasi_filesize_t *new_offset) -{ - CHECK_VALID_FILE_HANDLE(handle); - - return __WASI_ENOSYS; -} - -__wasi_errno_t -os_fadvise(os_file_handle handle, __wasi_filesize_t offset, - __wasi_filesize_t length, __wasi_advice_t advice) -{ - CHECK_VALID_FILE_HANDLE(handle); - - return __WASI_ENOSYS; -} - __wasi_errno_t os_isatty(os_file_handle handle) { @@ -1364,10 +1558,115 @@ os_convert_stderr_handle(os_raw_file_handle raw_stderr) return create_stdio_handle(raw_stderr, STD_ERROR_HANDLE); } +__wasi_errno_t +os_unlinkat(os_file_handle handle, const char *path, bool is_dir) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, + absolute_path, PATH_MAX); + + DWORD attributes = GetFileAttributesW(absolute_path); + + if (attributes != INVALID_FILE_ATTRIBUTES + && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + // Override is_dir for symlinks. A symlink to a directory counts as a + // directory itself in Windows. + is_dir = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + + if (error != __WASI_ESUCCESS) + return error; + + int ret = + is_dir ? RemoveDirectoryW(absolute_path) : DeleteFileW(absolute_path); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_lseek(os_file_handle handle, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *new_offset) +{ + CHECK_VALID_FILE_HANDLE(handle); + DWORD sys_whence = 0; + + switch (whence) { + case __WASI_WHENCE_SET: + sys_whence = FILE_BEGIN; + break; + case __WASI_WHENCE_END: + sys_whence = FILE_END; + break; + case __WASI_WHENCE_CUR: + sys_whence = FILE_CURRENT; + break; + default: + return __WASI_EINVAL; + } + + LARGE_INTEGER distance_to_move = { .QuadPart = offset }; + LARGE_INTEGER updated_offset = { .QuadPart = 0 }; + + int ret = SetFilePointerEx(handle->raw.handle, distance_to_move, + &updated_offset, sys_whence); + + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + *new_offset = (__wasi_filesize_t)updated_offset.QuadPart; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fadvise(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length, __wasi_advice_t advice) +{ + CHECK_VALID_FILE_HANDLE(handle); + // Advisory information can be safely ignored if not supported + switch (advice) { + case __WASI_ADVICE_DONTNEED: + case __WASI_ADVICE_NOREUSE: + case __WASI_ADVICE_NORMAL: + case __WASI_ADVICE_RANDOM: + case __WASI_ADVICE_SEQUENTIAL: + case __WASI_ADVICE_WILLNEED: + return __WASI_ESUCCESS; + default: + return __WASI_EINVAL; + } +} + __wasi_errno_t os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream) { - return __WASI_ENOSYS; + CHECK_VALID_FILE_HANDLE(handle); + + // Check the handle is a directory handle first + DWORD windows_filetype = GetFileType(handle->raw.handle); + + __wasi_filetype_t filetype = __WASI_FILETYPE_UNKNOWN; + __wasi_errno_t error = + convert_windows_filetype(handle, windows_filetype, &filetype); + + if (error != __WASI_ESUCCESS) + return error; + + if (filetype != __WASI_FILETYPE_DIRECTORY) + return __WASI_ENOTDIR; + + *dir_stream = BH_MALLOC(sizeof(windows_dir_stream)); + + if (*dir_stream == NULL) + return __WASI_ENOMEM; + + init_dir_stream(*dir_stream, handle); + + return error; } __wasi_errno_t @@ -1375,7 +1674,9 @@ os_rewinddir(os_dir_stream dir_stream) { CHECK_VALID_WIN_DIR_STREAM(dir_stream); - return __WASI_ENOSYS; + reset_dir_stream(dir_stream); + + return __WASI_ESUCCESS; } __wasi_errno_t @@ -1383,7 +1684,25 @@ os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position) { CHECK_VALID_WIN_DIR_STREAM(dir_stream); - return __WASI_ENOSYS; + if (dir_stream->cookie == position) + return __WASI_ESUCCESS; + + if (dir_stream->cookie > position) { + reset_dir_stream(dir_stream); + } + + while (dir_stream->cookie < position) { + __wasi_errno_t error = read_next_dir_entry(dir_stream, NULL); + + if (error != __WASI_ESUCCESS) + return error; + + // We've reached the end of the directory. + if (dir_stream->cookie == 0) { + break; + } + } + return __WASI_ESUCCESS; } __wasi_errno_t @@ -1392,7 +1711,23 @@ os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry, { CHECK_VALID_WIN_DIR_STREAM(dir_stream); - return __WASI_ENOSYS; + FILE_ID_BOTH_DIR_INFO *file_id_both_dir_info = NULL; + + __wasi_errno_t error = + read_next_dir_entry(dir_stream, &file_id_both_dir_info); + + if (error != __WASI_ESUCCESS || file_id_both_dir_info == NULL) + return error; + + entry->d_ino = (__wasi_inode_t)file_id_both_dir_info->FileId.QuadPart; + entry->d_namlen = (__wasi_dirnamlen_t)(file_id_both_dir_info->FileNameLength + / (sizeof(wchar_t) / sizeof(char))); + entry->d_next = (__wasi_dircookie_t)dir_stream->cookie; + entry->d_type = get_disk_filetype(file_id_both_dir_info->FileAttributes); + + *d_name = dir_stream->current_entry_name; + + return __WASI_ESUCCESS; } __wasi_errno_t @@ -1400,7 +1735,19 @@ os_closedir(os_dir_stream dir_stream) { CHECK_VALID_WIN_DIR_STREAM(dir_stream); - return __WASI_ENOSYS; + bool success = CloseHandle(dir_stream->handle->raw.handle); + + if (!success) { + DWORD win_error = GetLastError(); + + if (win_error = ERROR_INVALID_HANDLE) + BH_FREE(dir_stream); + return convert_windows_error_code(win_error); + } + + BH_FREE(dir_stream); + + return __WASI_ESUCCESS; } os_dir_stream diff --git a/core/shared/platform/windows/win_util.c b/core/shared/platform/windows/win_util.c index ee0e82fb9a..58987fa004 100644 --- a/core/shared/platform/windows/win_util.c +++ b/core/shared/platform/windows/win_util.c @@ -6,19 +6,31 @@ #include "platform_common.h" #include "win_util.h" +// From 1601-01-01 to 1970-01-01 there are 134774 days. +static const uint64_t NT_to_UNIX_epoch_in_ns = + 134774ull * 86400ull * 1000ull * 1000ull * 1000ull; + __wasi_timestamp_t convert_filetime_to_wasi_timestamp(LPFILETIME filetime) { - // From 1601-01-01 to 1970-01-01 there are 134774 days. - static const uint64_t NT_to_UNIX_epoch = - 134774ull * 86400ull * 1000ull * 1000ull * 1000ull; - ULARGE_INTEGER temp = { .HighPart = filetime->dwHighDateTime, .LowPart = filetime->dwLowDateTime }; // WASI timestamps are measured in nanoseconds whereas FILETIME structs are // represented in terms 100-nanosecond intervals. - return (temp.QuadPart * 100ull) - NT_to_UNIX_epoch; + return (temp.QuadPart * 100ull) - NT_to_UNIX_epoch_in_ns; +} + +FILETIME +convert_wasi_timestamp_to_filetime(__wasi_timestamp_t timestamp) +{ + ULARGE_INTEGER temp = { .QuadPart = + (timestamp + NT_to_UNIX_epoch_in_ns) / 100ull }; + + FILETIME ret = { .dwLowDateTime = temp.LowPart, + .dwHighDateTime = temp.HighPart }; + + return ret; } __wasi_errno_t diff --git a/core/shared/platform/windows/win_util.h b/core/shared/platform/windows/win_util.h index 3960fe946f..033c393b59 100644 --- a/core/shared/platform/windows/win_util.h +++ b/core/shared/platform/windows/win_util.h @@ -12,6 +12,9 @@ __wasi_timestamp_t convert_filetime_to_wasi_timestamp(LPFILETIME filetime); +FILETIME +convert_wasi_timestamp_to_filetime(__wasi_timestamp_t timestamp); + /* Convert a Windows error code to a WASI error code */ __wasi_errno_t convert_windows_error_code(DWORD windows_error_code); diff --git a/product-mini/platforms/windows/wasi_filtered_tests.json b/product-mini/platforms/windows/wasi_filtered_tests.json index 492a746eb0..63910435c8 100644 --- a/product-mini/platforms/windows/wasi_filtered_tests.json +++ b/product-mini/platforms/windows/wasi_filtered_tests.json @@ -1,34 +1,6 @@ { - "WASI C tests": { - "fdopendir-with-access": "Not implemented", - "lseek": "Not implemented" - }, "WASI Rust tests": { - "dangling_symlink": "Not implemented", - "directory_seek": "Not implemented", - "dir_fd_op_failures": "Not implemented", - "fd_advise": "Not implemented", - "fd_fdstat_set_rights": "Not implemented", - "fd_filestat_set": "Not implemented", - "fd_flags_set": "Not implemented", - "fd_readdir": "Not implemented", - "file_allocate": "Not implemented", - "file_seek_tell": "Not implemented", - "file_truncation": "Not implemented", - "nofollow_errors": "Not implemented", - "path_exists": "Not implemented", - "path_filestat": "Not implemented", - "path_link": "Not implemented", - "path_open_preopen": "Not implemented", - "path_rename": "Not implemented", - "path_rename_dir_trailing_slashes": "Not implemented", - "path_symlink_trailing_slashes": "Not implemented", - "poll_oneoff_stdio": "Not implemented", - "readlink": "Not implemented (path_symlink)", - "symlink_create": "Not implemented", - "symlink_filestat": "Not implemented", - "symlink_loop": "Not implemented", - "truncation_rights": "Not implemented" + "poll_oneoff_stdio": "Not implemented" }, "WASI threads proposal": { "wasi_threads_exit_main_wasi_read": "Blocking ops not implemented", diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index 4cfe6c29be..9ea733c3ff 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -41,6 +41,12 @@ readonly THREAD_INTERNAL_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-wasi-thread readonly THREAD_STRESS_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/stress-test/" readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/" +add_env_key_to_test_config_file() { + filepath="tests/$2/testsuite/$3.json" + modified_contents=$(jq ".env.$1 = 1" "$filepath") + echo "$modified_contents" > "$filepath" +} + run_aot_tests () { local -n tests=$1 local -n excluded_tests=$2 @@ -95,6 +101,15 @@ if [[ $MODE != "aot" ]];then export TEST_RUNTIME_EXE="${IWASM_CMD}" + # Some of the WASI test assertions can be controlled via environment + # variables. The following ones are set on Windows so that the tests pass. + if [ "$PLATFORM" == "windows" ]; then + add_env_key_to_test_config_file NO_DANGLING_FILESYSTEM rust symlink_loop + add_env_key_to_test_config_file NO_DANGLING_FILESYSTEM rust dangling_symlink + add_env_key_to_test_config_file ERRNO_MODE_WINDOWS rust path_open_preopen + add_env_key_to_test_config_file NO_RENAME_DIR_TO_EMPTY_DIR rust path_rename + fi + TEST_OPTIONS="-r adapters/wasm-micro-runtime.py \ -t \ ${C_TESTS} \