mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 06:55:07 +00:00
Implement the remaining Windows filesystem functions (#3166)
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.
This commit is contained in:
parent
4f6d70bc52
commit
92bd3ba17d
|
@ -213,14 +213,6 @@ has_symlink_attribute(DWORD attributes)
|
||||||
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
|
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
|
static void
|
||||||
init_dir_stream(os_dir_stream dir_stream, os_file_handle handle)
|
init_dir_stream(os_dir_stream dir_stream, os_file_handle handle)
|
||||||
{
|
{
|
||||||
|
@ -229,6 +221,13 @@ init_dir_stream(os_dir_stream dir_stream, os_file_handle handle)
|
||||||
dir_stream->cookie = 0;
|
dir_stream->cookie = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reset_dir_stream(os_dir_stream dir_stream)
|
||||||
|
{
|
||||||
|
dir_stream->cursor = 0;
|
||||||
|
dir_stream->cookie = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Advances to the next directory entry and optionally reads into to the
|
// Advances to the next directory entry and optionally reads into to the
|
||||||
// provided buffer if not NULL.
|
// provided buffer if not NULL.
|
||||||
static __wasi_errno_t
|
static __wasi_errno_t
|
||||||
|
@ -562,7 +561,32 @@ os_fstatat(os_file_handle handle, const char *path,
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
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
|
__wasi_errno_t
|
||||||
|
@ -579,7 +603,33 @@ os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
|
||||||
{
|
{
|
||||||
CHECK_VALID_HANDLE(handle);
|
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
|
__wasi_errno_t
|
||||||
|
@ -599,12 +649,21 @@ os_file_get_access_mode(os_file_handle handle,
|
||||||
return __WASI_ESUCCESS;
|
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
|
__wasi_errno_t
|
||||||
os_fdatasync(os_file_handle handle)
|
os_fdatasync(os_file_handle handle)
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
CHECK_VALID_FILE_HANDLE(handle);
|
||||||
|
|
||||||
return __WASI_ENOSYS;
|
return flush_file_buffers_on_handle(handle->raw.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
__wasi_errno_t
|
__wasi_errno_t
|
||||||
|
@ -612,7 +671,7 @@ os_fsync(os_file_handle handle)
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
CHECK_VALID_FILE_HANDLE(handle);
|
||||||
|
|
||||||
return __WASI_ENOSYS;
|
return flush_file_buffers_on_handle(handle->raw.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
__wasi_errno_t
|
__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;
|
__wasi_errno_t error = __WASI_ESUCCESS;
|
||||||
|
|
||||||
DWORD access_flags = 0;
|
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) {
|
switch (access_mode) {
|
||||||
case WASI_LIBC_ACCESS_MODE_READ_ONLY:
|
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)
|
if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0)
|
||||||
attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
|
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 for the following cases where the
|
||||||
// Windows doesn't seem to throw an error in this case so add an
|
// file/directory already exists so add explicit checks.
|
||||||
// explicit check.
|
if (creation_disposition == OPEN_EXISTING) {
|
||||||
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0
|
DWORD file_attributes = GetFileAttributesW(absolute_path);
|
||||||
&& creation_disposition == OPEN_EXISTING
|
|
||||||
&& !is_directory(absolute_path)) {
|
if (file_attributes != INVALID_FILE_ATTRIBUTES) {
|
||||||
error = __WASI_ENOTDIR;
|
bool is_dir = file_attributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||||
goto fail;
|
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;
|
CREATEFILE2_EXTENDED_PARAMETERS create_params;
|
||||||
|
@ -1035,7 +1100,31 @@ os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
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
|
__wasi_errno_t
|
||||||
|
@ -1043,7 +1132,42 @@ os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
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
|
__wasi_errno_t
|
||||||
|
@ -1052,7 +1176,8 @@ os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
CHECK_VALID_FILE_HANDLE(handle);
|
||||||
|
|
||||||
return __WASI_ENOSYS;
|
return set_file_times(handle->raw.handle, access_time, modification_time,
|
||||||
|
fstflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
__wasi_errno_t
|
__wasi_errno_t
|
||||||
|
@ -1063,7 +1188,26 @@ os_utimensat(os_file_handle handle, const char *path,
|
||||||
{
|
{
|
||||||
CHECK_VALID_FILE_HANDLE(handle);
|
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
|
__wasi_errno_t
|
||||||
|
@ -1213,7 +1357,7 @@ os_readlinkat(os_file_handle handle, const char *path, char *buf,
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
error = __WASI_ENOTSUP;
|
error = __WASI_ENOTSUP;
|
||||||
#endif
|
#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */
|
||||||
fail:
|
fail:
|
||||||
CloseHandle(link_handle);
|
CloseHandle(link_handle);
|
||||||
return error;
|
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,
|
os_file_handle to_handle, const char *to_path,
|
||||||
__wasi_lookupflags_t lookup_flags)
|
__wasi_lookupflags_t lookup_flags)
|
||||||
{
|
{
|
||||||
|
#if WINAPI_PARTITION_DESKTOP == 0
|
||||||
|
return __WASI_ENOSYS;
|
||||||
|
#else
|
||||||
CHECK_VALID_FILE_HANDLE(from_handle);
|
CHECK_VALID_FILE_HANDLE(from_handle);
|
||||||
CHECK_VALID_FILE_HANDLE(to_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
|
__wasi_errno_t
|
||||||
os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
|
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);
|
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
|
__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(old_handle);
|
||||||
CHECK_VALID_FILE_HANDLE(new_handle);
|
CHECK_VALID_FILE_HANDLE(new_handle);
|
||||||
|
|
||||||
return __WASI_ENOSYS;
|
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);
|
||||||
__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);
|
|
||||||
|
|
||||||
if (error != __WASI_ESUCCESS)
|
if (error != __WASI_ESUCCESS)
|
||||||
return error;
|
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)) {
|
if (error != __WASI_ESUCCESS)
|
||||||
// Override is_dir for symlinks. A symlink to a directory counts
|
return error;
|
||||||
// as a directory itself in Windows.
|
|
||||||
is_dir = has_directory_attribute(attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret =
|
|
||||||
is_dir ? RemoveDirectoryW(absolute_path) : DeleteFileW(absolute_path);
|
|
||||||
|
|
||||||
|
int ret = MoveFileExW(old_absolute_path, new_absolute_path,
|
||||||
|
MOVEFILE_REPLACE_EXISTING);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
error = convert_windows_error_code(GetLastError());
|
error = convert_windows_error_code(GetLastError());
|
||||||
|
|
||||||
return error;
|
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
|
__wasi_errno_t
|
||||||
os_isatty(os_file_handle handle)
|
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);
|
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
|
__wasi_errno_t
|
||||||
os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
|
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
|
__wasi_errno_t
|
||||||
|
@ -1375,7 +1674,9 @@ os_rewinddir(os_dir_stream dir_stream)
|
||||||
{
|
{
|
||||||
CHECK_VALID_WIN_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
|
__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);
|
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
|
__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);
|
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
|
__wasi_errno_t
|
||||||
|
@ -1400,7 +1735,19 @@ os_closedir(os_dir_stream dir_stream)
|
||||||
{
|
{
|
||||||
CHECK_VALID_WIN_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
|
os_dir_stream
|
||||||
|
|
|
@ -6,19 +6,31 @@
|
||||||
#include "platform_common.h"
|
#include "platform_common.h"
|
||||||
#include "win_util.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
|
__wasi_timestamp_t
|
||||||
convert_filetime_to_wasi_timestamp(LPFILETIME filetime)
|
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,
|
ULARGE_INTEGER temp = { .HighPart = filetime->dwHighDateTime,
|
||||||
.LowPart = filetime->dwLowDateTime };
|
.LowPart = filetime->dwLowDateTime };
|
||||||
|
|
||||||
// WASI timestamps are measured in nanoseconds whereas FILETIME structs are
|
// WASI timestamps are measured in nanoseconds whereas FILETIME structs are
|
||||||
// represented in terms 100-nanosecond intervals.
|
// 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
|
__wasi_errno_t
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
__wasi_timestamp_t
|
__wasi_timestamp_t
|
||||||
convert_filetime_to_wasi_timestamp(LPFILETIME filetime);
|
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 */
|
/* Convert a Windows error code to a WASI error code */
|
||||||
__wasi_errno_t
|
__wasi_errno_t
|
||||||
convert_windows_error_code(DWORD windows_error_code);
|
convert_windows_error_code(DWORD windows_error_code);
|
||||||
|
|
|
@ -1,34 +1,6 @@
|
||||||
{
|
{
|
||||||
"WASI C tests": {
|
|
||||||
"fdopendir-with-access": "Not implemented",
|
|
||||||
"lseek": "Not implemented"
|
|
||||||
},
|
|
||||||
"WASI Rust tests": {
|
"WASI Rust tests": {
|
||||||
"dangling_symlink": "Not implemented",
|
"poll_oneoff_stdio": "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"
|
|
||||||
},
|
},
|
||||||
"WASI threads proposal": {
|
"WASI threads proposal": {
|
||||||
"wasi_threads_exit_main_wasi_read": "Blocking ops not implemented",
|
"wasi_threads_exit_main_wasi_read": "Blocking ops not implemented",
|
||||||
|
|
|
@ -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 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/"
|
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 () {
|
run_aot_tests () {
|
||||||
local -n tests=$1
|
local -n tests=$1
|
||||||
local -n excluded_tests=$2
|
local -n excluded_tests=$2
|
||||||
|
@ -95,6 +101,15 @@ if [[ $MODE != "aot" ]];then
|
||||||
|
|
||||||
export TEST_RUNTIME_EXE="${IWASM_CMD}"
|
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 \
|
TEST_OPTIONS="-r adapters/wasm-micro-runtime.py \
|
||||||
-t \
|
-t \
|
||||||
${C_TESTS} \
|
${C_TESTS} \
|
||||||
|
|
Loading…
Reference in New Issue
Block a user