diff --git a/deps/uvwasi/include/fd_table.h b/deps/uvwasi/include/fd_table.h index 5380502a1e4e5f..fa8a44e7468d41 100644 --- a/deps/uvwasi/include/fd_table.h +++ b/deps/uvwasi/include/fd_table.h @@ -31,26 +31,39 @@ uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_s* uvwasi, uint32_t init_size); void uvwasi_fd_table_free(struct uvwasi_s* uvwasi, struct uvwasi_fd_table_t* table); +uvwasi_errno_t uvwasi_fd_table_insert(struct uvwasi_s* uvwasi, + struct uvwasi_fd_table_t* table, + uv_file fd, + const char* mapped_path, + const char* real_path, + uvwasi_filetype_t type, + uvwasi_rights_t rights_base, + uvwasi_rights_t rights_inheriting, + int preopen, + struct uvwasi_fd_wrap_t** wrap); uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_s* uvwasi, struct uvwasi_fd_table_t* table, const uv_file fd, const char* path, const char* real_path); -uvwasi_errno_t uvwasi_fd_table_insert_fd(struct uvwasi_s* uvwasi, - struct uvwasi_fd_table_t* table, - const uv_file fd, - const int flags, - const char* path, - uvwasi_rights_t rights_base, - uvwasi_rights_t rights_inheriting, - struct uvwasi_fd_wrap_t* wrap); -uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table, +uvwasi_errno_t uvwasi_fd_table_get(struct uvwasi_fd_table_t* table, const uvwasi_fd_t id, struct uvwasi_fd_wrap_t** wrap, uvwasi_rights_t rights_base, uvwasi_rights_t rights_inheriting); -uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_s* uvwasi, - struct uvwasi_fd_table_t* table, - const uvwasi_fd_t id); +uvwasi_errno_t uvwasi_fd_table_get_nolock(struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id, + struct uvwasi_fd_wrap_t** wrap, + uvwasi_rights_t rights_base, + uvwasi_rights_t rights_inheriting); +uvwasi_errno_t uvwasi_fd_table_remove_nolock(struct uvwasi_s* uvwasi, + struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id); +uvwasi_errno_t uvwasi_fd_table_renumber(struct uvwasi_s* uvwasi, + struct uvwasi_fd_table_t* table, + const uvwasi_fd_t dst, + const uvwasi_fd_t src); +uvwasi_errno_t uvwasi_fd_table_lock(struct uvwasi_fd_table_t* table); +uvwasi_errno_t uvwasi_fd_table_unlock(struct uvwasi_fd_table_t* table); #endif /* __UVWASI_FD_TABLE_H__ */ diff --git a/deps/uvwasi/include/uvwasi.h b/deps/uvwasi/include/uvwasi.h index e32c335b101bf3..9ca30459e23a73 100644 --- a/deps/uvwasi/include/uvwasi.h +++ b/deps/uvwasi/include/uvwasi.h @@ -11,7 +11,7 @@ extern "C" { #define UVWASI_VERSION_MAJOR 0 #define UVWASI_VERSION_MINOR 0 -#define UVWASI_VERSION_PATCH 4 +#define UVWASI_VERSION_PATCH 5 #define UVWASI_VERSION_HEX ((UVWASI_VERSION_MAJOR << 16) | \ (UVWASI_VERSION_MINOR << 8) | \ (UVWASI_VERSION_PATCH)) diff --git a/deps/uvwasi/src/fd_table.c b/deps/uvwasi/src/fd_table.c index f3855d4da54dbe..bc32f4dd28bbce 100644 --- a/deps/uvwasi/src/fd_table.c +++ b/deps/uvwasi/src/fd_table.c @@ -9,183 +9,21 @@ #include "uv.h" #include "fd_table.h" #include "wasi_types.h" +#include "wasi_rights.h" #include "uv_mapping.h" #include "uvwasi_alloc.h" -#define UVWASI__RIGHTS_ALL (UVWASI_RIGHT_FD_DATASYNC | \ - UVWASI_RIGHT_FD_READ | \ - UVWASI_RIGHT_FD_SEEK | \ - UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - UVWASI_RIGHT_FD_SYNC | \ - UVWASI_RIGHT_FD_TELL | \ - UVWASI_RIGHT_FD_WRITE | \ - UVWASI_RIGHT_FD_ADVISE | \ - UVWASI_RIGHT_FD_ALLOCATE | \ - UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \ - UVWASI_RIGHT_PATH_CREATE_FILE | \ - UVWASI_RIGHT_PATH_LINK_SOURCE | \ - UVWASI_RIGHT_PATH_LINK_TARGET | \ - UVWASI_RIGHT_PATH_OPEN | \ - UVWASI_RIGHT_FD_READDIR | \ - UVWASI_RIGHT_PATH_READLINK | \ - UVWASI_RIGHT_PATH_RENAME_SOURCE | \ - UVWASI_RIGHT_PATH_RENAME_TARGET | \ - UVWASI_RIGHT_PATH_FILESTAT_GET | \ - UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ - UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ - UVWASI_RIGHT_FD_FILESTAT_GET | \ - UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \ - UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \ - UVWASI_RIGHT_PATH_SYMLINK | \ - UVWASI_RIGHT_PATH_UNLINK_FILE | \ - UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \ - UVWASI_RIGHT_POLL_FD_READWRITE | \ - UVWASI_RIGHT_SOCK_SHUTDOWN) - -#define UVWASI__RIGHTS_BLOCK_DEVICE_BASE UVWASI__RIGHTS_ALL -#define UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING UVWASI__RIGHTS_ALL - -#define UVWASI__RIGHTS_CHARACTER_DEVICE_BASE UVWASI__RIGHTS_ALL -#define UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING UVWASI__RIGHTS_ALL - -#define UVWASI__RIGHTS_REGULAR_FILE_BASE (UVWASI_RIGHT_FD_DATASYNC | \ - UVWASI_RIGHT_FD_READ | \ - UVWASI_RIGHT_FD_SEEK | \ - UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - UVWASI_RIGHT_FD_SYNC | \ - UVWASI_RIGHT_FD_TELL | \ - UVWASI_RIGHT_FD_WRITE | \ - UVWASI_RIGHT_FD_ADVISE | \ - UVWASI_RIGHT_FD_ALLOCATE | \ - UVWASI_RIGHT_FD_FILESTAT_GET | \ - UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \ - UVWASI_RIGHT_FD_FILESTAT_SET_TIMES |\ - UVWASI_RIGHT_POLL_FD_READWRITE) -#define UVWASI__RIGHTS_REGULAR_FILE_INHERITING 0 - -#define UVWASI__RIGHTS_DIRECTORY_BASE (UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - UVWASI_RIGHT_FD_SYNC | \ - UVWASI_RIGHT_FD_ADVISE | \ - UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \ - UVWASI_RIGHT_PATH_CREATE_FILE | \ - UVWASI_RIGHT_PATH_LINK_SOURCE | \ - UVWASI_RIGHT_PATH_LINK_TARGET | \ - UVWASI_RIGHT_PATH_OPEN | \ - UVWASI_RIGHT_FD_READDIR | \ - UVWASI_RIGHT_PATH_READLINK | \ - UVWASI_RIGHT_PATH_RENAME_SOURCE | \ - UVWASI_RIGHT_PATH_RENAME_TARGET | \ - UVWASI_RIGHT_PATH_FILESTAT_GET | \ - UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ - UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ - UVWASI_RIGHT_FD_FILESTAT_GET | \ - UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \ - UVWASI_RIGHT_PATH_SYMLINK | \ - UVWASI_RIGHT_PATH_UNLINK_FILE | \ - UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \ - UVWASI_RIGHT_POLL_FD_READWRITE) -#define UVWASI__RIGHTS_DIRECTORY_INHERITING (UVWASI__RIGHTS_DIRECTORY_BASE | \ - UVWASI__RIGHTS_REGULAR_FILE_BASE) - -#define UVWASI__RIGHTS_SOCKET_BASE (UVWASI_RIGHT_FD_READ | \ - UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - UVWASI_RIGHT_FD_WRITE | \ - UVWASI_RIGHT_FD_FILESTAT_GET | \ - UVWASI_RIGHT_POLL_FD_READWRITE | \ - UVWASI_RIGHT_SOCK_SHUTDOWN) -#define UVWASI__RIGHTS_SOCKET_INHERITING UVWASI__RIGHTS_ALL; - -#define UVWASI__RIGHTS_TTY_BASE (UVWASI_RIGHT_FD_READ | \ - UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - UVWASI_RIGHT_FD_WRITE | \ - UVWASI_RIGHT_FD_FILESTAT_GET | \ - UVWASI_RIGHT_POLL_FD_READWRITE) -#define UVWASI__RIGHTS_TTY_INHERITING 0 - -static uvwasi_errno_t uvwasi__get_type_and_rights(uv_file fd, - int flags, - uvwasi_filetype_t* type, - uvwasi_rights_t* rights_base, - uvwasi_rights_t* rights_inheriting) { - uv_fs_t req; - uvwasi_filetype_t filetype; - int read_or_write_only; - int r; - - r = uv_fs_fstat(NULL, &req, fd, NULL); - filetype = uvwasi__stat_to_filetype(&req.statbuf); - uv_fs_req_cleanup(&req); - if (r != 0) - return uvwasi__translate_uv_error(r); - - *type = filetype; - switch (filetype) { - case UVWASI_FILETYPE_REGULAR_FILE: - *rights_base = UVWASI__RIGHTS_REGULAR_FILE_BASE; - *rights_inheriting = UVWASI__RIGHTS_REGULAR_FILE_INHERITING; - break; - - case UVWASI_FILETYPE_DIRECTORY: - *rights_base = UVWASI__RIGHTS_DIRECTORY_BASE; - *rights_inheriting = UVWASI__RIGHTS_DIRECTORY_INHERITING; - break; - - /* uvwasi__stat_to_filetype() cannot differentiate socket types. It only - returns UVWASI_FILETYPE_SOCKET_STREAM. */ - case UVWASI_FILETYPE_SOCKET_STREAM: - if (uv_guess_handle(fd) == UV_UDP) - *type = UVWASI_FILETYPE_SOCKET_DGRAM; - - *rights_base = UVWASI__RIGHTS_SOCKET_BASE; - *rights_inheriting = UVWASI__RIGHTS_SOCKET_INHERITING; - break; - - case UVWASI_FILETYPE_CHARACTER_DEVICE: - if (uv_guess_handle(fd) == UV_TTY) { - *rights_base = UVWASI__RIGHTS_TTY_BASE; - *rights_inheriting = UVWASI__RIGHTS_TTY_INHERITING; - } else { - *rights_base = UVWASI__RIGHTS_CHARACTER_DEVICE_BASE; - *rights_inheriting = UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING; - } - break; - - case UVWASI_FILETYPE_BLOCK_DEVICE: - *rights_base = UVWASI__RIGHTS_BLOCK_DEVICE_BASE; - *rights_inheriting = UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING; - break; - - default: - *rights_base = 0; - *rights_inheriting = 0; - } - - if (*type == UVWASI_FILETYPE_UNKNOWN) - return UVWASI_EINVAL; - - /* Disable read/write bits depending on access mode. */ - read_or_write_only = flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR); - - if (read_or_write_only == UV_FS_O_RDONLY) - *rights_base &= ~UVWASI_RIGHT_FD_WRITE; - else if (read_or_write_only == UV_FS_O_WRONLY) - *rights_base &= ~UVWASI_RIGHT_FD_READ; - - return UVWASI_ESUCCESS; -} - - -static uvwasi_errno_t uvwasi__fd_table_insert(uvwasi_t* uvwasi, - struct uvwasi_fd_table_t* table, - uv_file fd, - const char* mapped_path, - const char* real_path, - uvwasi_filetype_t type, - uvwasi_rights_t rights_base, - uvwasi_rights_t rights_inheriting, - int preopen, - struct uvwasi_fd_wrap_t** wrap) { +uvwasi_errno_t uvwasi_fd_table_insert(uvwasi_t* uvwasi, + struct uvwasi_fd_table_t* table, + uv_file fd, + const char* mapped_path, + const char* real_path, + uvwasi_filetype_t type, + uvwasi_rights_t rights_base, + uvwasi_rights_t rights_inheriting, + int preopen, + struct uvwasi_fd_wrap_t** wrap) { struct uvwasi_fd_wrap_t* entry; struct uvwasi_fd_wrap_t** new_fds; uvwasi_errno_t err; @@ -263,11 +101,13 @@ static uvwasi_errno_t uvwasi__fd_table_insert(uvwasi_t* uvwasi, entry->rights_base = rights_base; entry->rights_inheriting = rights_inheriting; entry->preopen = preopen; - table->used++; - if (wrap != NULL) + if (wrap != NULL) { + uv_mutex_lock(&entry->mutex); *wrap = entry; + } + table->used++; err = UVWASI_ESUCCESS; exit: uv_rwlock_wrunlock(&table->rwlock); @@ -314,28 +154,30 @@ uvwasi_errno_t uvwasi_fd_table_init(uvwasi_t* uvwasi, /* Create the stdio FDs. */ for (i = 0; i < 3; ++i) { - err = uvwasi__get_type_and_rights(i, - UV_FS_O_RDWR, - &type, - &base, - &inheriting); + err = uvwasi__get_filetype_by_fd(i, &type); + if (err != UVWASI_ESUCCESS) + goto error_exit; + + err = uvwasi__get_rights(i, UV_FS_O_RDWR, type, &base, &inheriting); if (err != UVWASI_ESUCCESS) goto error_exit; - err = uvwasi__fd_table_insert(uvwasi, - table, - i, - "", - "", - type, - base, - inheriting, - 0, - &wrap); + err = uvwasi_fd_table_insert(uvwasi, + table, + i, + "", + "", + type, + base, + inheriting, + 0, + &wrap); if (err != UVWASI_ESUCCESS) goto error_exit; - if (wrap->id != i || wrap->id != (uvwasi_fd_t) wrap->fd) { + r = wrap->id != i || wrap->id != (uvwasi_fd_t) wrap->fd; + uv_mutex_unlock(&wrap->mutex); + if (r) { err = UVWASI_EBADF; goto error_exit; } @@ -386,14 +228,18 @@ uvwasi_errno_t uvwasi_fd_table_insert_preopen(uvwasi_t* uvwasi, if (table == NULL || path == NULL || real_path == NULL) return UVWASI_EINVAL; - err = uvwasi__get_type_and_rights(fd, 0, &type, &base, &inheriting); + err = uvwasi__get_filetype_by_fd(fd, &type); if (err != UVWASI_ESUCCESS) return err; if (type != UVWASI_FILETYPE_DIRECTORY) return UVWASI_ENOTDIR; - err = uvwasi__fd_table_insert(uvwasi, + err = uvwasi__get_rights(fd, 0, type, &base, &inheriting); + if (err != UVWASI_ESUCCESS) + return err; + + return uvwasi_fd_table_insert(uvwasi, table, fd, path, @@ -403,122 +249,164 @@ uvwasi_errno_t uvwasi_fd_table_insert_preopen(uvwasi_t* uvwasi, UVWASI__RIGHTS_DIRECTORY_INHERITING, 1, NULL); - if (err != UVWASI_ESUCCESS) - return err; - - return UVWASI_ESUCCESS; } -uvwasi_errno_t uvwasi_fd_table_insert_fd(uvwasi_t* uvwasi, - struct uvwasi_fd_table_t* table, - const uv_file fd, - const int flags, - const char* path, - uvwasi_rights_t rights_base, - uvwasi_rights_t rights_inheriting, - struct uvwasi_fd_wrap_t* wrap) { - struct uvwasi_fd_wrap_t* fd_wrap; - uvwasi_filetype_t type; - uvwasi_rights_t max_base; - uvwasi_rights_t max_inheriting; - uvwasi_errno_t r; +uvwasi_errno_t uvwasi_fd_table_get(struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id, + struct uvwasi_fd_wrap_t** wrap, + uvwasi_rights_t rights_base, + uvwasi_rights_t rights_inheriting) { + uvwasi_errno_t err; - if (table == NULL || path == NULL || wrap == NULL) + if (table == NULL) return UVWASI_EINVAL; - r = uvwasi__get_type_and_rights(fd, flags, &type, &max_base, &max_inheriting); - if (r != UVWASI_ESUCCESS) - return r; - - r = uvwasi__fd_table_insert(uvwasi, - table, - fd, - path, - path, - type, - rights_base & max_base, - rights_inheriting & max_inheriting, - 0, - &fd_wrap); - if (r != UVWASI_ESUCCESS) - return r; - - *wrap = *fd_wrap; - return UVWASI_ESUCCESS; + uv_rwlock_wrlock(&table->rwlock); + err = uvwasi_fd_table_get_nolock(table, + id, + wrap, + rights_base, + rights_inheriting); + uv_rwlock_wrunlock(&table->rwlock); + return err; } -uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table, - const uvwasi_fd_t id, - struct uvwasi_fd_wrap_t** wrap, - uvwasi_rights_t rights_base, - uvwasi_rights_t rights_inheriting) { +/* uvwasi_fd_table_get_nolock() retrieves a file descriptor and locks its mutex, + but does not lock the file descriptor table like uvwasi_fd_table_get() does. +*/ +uvwasi_errno_t uvwasi_fd_table_get_nolock(struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id, + struct uvwasi_fd_wrap_t** wrap, + uvwasi_rights_t rights_base, + uvwasi_rights_t rights_inheriting) { struct uvwasi_fd_wrap_t* entry; - uvwasi_errno_t err; if (table == NULL || wrap == NULL) return UVWASI_EINVAL; - uv_rwlock_rdlock((uv_rwlock_t *)&table->rwlock); - - if (id >= table->size) { - err = UVWASI_EBADF; - goto exit; - } + if (id >= table->size) + return UVWASI_EBADF; entry = table->fds[id]; - if (entry == NULL || entry->id != id) { - err = UVWASI_EBADF; - goto exit; - } + if (entry == NULL || entry->id != id) + return UVWASI_EBADF; /* Validate that the fd has the necessary rights. */ if ((~entry->rights_base & rights_base) != 0 || (~entry->rights_inheriting & rights_inheriting) != 0) { - err = UVWASI_ENOTCAPABLE; - goto exit; + return UVWASI_ENOTCAPABLE; } uv_mutex_lock(&entry->mutex); *wrap = entry; - err = UVWASI_ESUCCESS; -exit: - uv_rwlock_rdunlock((uv_rwlock_t *)&table->rwlock); - return err; + return UVWASI_ESUCCESS; } -uvwasi_errno_t uvwasi_fd_table_remove(uvwasi_t* uvwasi, - struct uvwasi_fd_table_t* table, - const uvwasi_fd_t id) { +uvwasi_errno_t uvwasi_fd_table_remove_nolock(uvwasi_t* uvwasi, + struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id) { struct uvwasi_fd_wrap_t* entry; - uvwasi_errno_t err; if (table == NULL) return UVWASI_EINVAL; + if (id >= table->size) + return UVWASI_EBADF; + + entry = table->fds[id]; + + if (entry == NULL || entry->id != id) + return UVWASI_EBADF; + + uv_mutex_destroy(&entry->mutex); + uvwasi__free(uvwasi, entry); + table->fds[id] = NULL; + table->used--; + return UVWASI_ESUCCESS; +} + + +uvwasi_errno_t uvwasi_fd_table_renumber(struct uvwasi_s* uvwasi, + struct uvwasi_fd_table_t* table, + const uvwasi_fd_t dst, + const uvwasi_fd_t src) { + struct uvwasi_fd_wrap_t* dst_entry; + struct uvwasi_fd_wrap_t* src_entry; + uv_fs_t req; + uvwasi_errno_t err; + int r; + + if (uvwasi == NULL || table == NULL) + return UVWASI_EINVAL; + + if (dst == src) + return UVWASI_ESUCCESS; + uv_rwlock_wrlock(&table->rwlock); - if (id >= table->size) { + if (dst >= table->size || src >= table->size) { err = UVWASI_EBADF; goto exit; } - entry = table->fds[id]; + dst_entry = table->fds[dst]; + src_entry = table->fds[src]; - if (entry == NULL || entry->id != id) { + if (dst_entry == NULL || dst_entry->id != dst || + src_entry == NULL || src_entry->id != src) { err = UVWASI_EBADF; goto exit; } - uv_mutex_destroy(&entry->mutex); - uvwasi__free(uvwasi, entry); - table->fds[id] = NULL; + uv_mutex_lock(&dst_entry->mutex); + uv_mutex_lock(&src_entry->mutex); + + /* Close the existing destination descriptor. */ + r = uv_fs_close(NULL, &req, dst_entry->fd, NULL); + uv_fs_req_cleanup(&req); + if (r != 0) { + uv_mutex_unlock(&src_entry->mutex); + uv_mutex_unlock(&dst_entry->mutex); + err = uvwasi__translate_uv_error(r); + goto exit; + } + + /* Move the source entry to the destination slot in the table. */ + table->fds[dst] = table->fds[src]; + table->fds[dst]->id = dst; + uv_mutex_unlock(&table->fds[dst]->mutex); + table->fds[src] = NULL; table->used--; + + /* Clean up what's left of the old destination entry. */ + uv_mutex_unlock(&dst_entry->mutex); + uv_mutex_destroy(&dst_entry->mutex); + uvwasi__free(uvwasi, dst_entry); + err = UVWASI_ESUCCESS; exit: uv_rwlock_wrunlock(&table->rwlock); return err; } + + +uvwasi_errno_t uvwasi_fd_table_lock(struct uvwasi_fd_table_t* table) { + if (table == NULL) + return UVWASI_EINVAL; + + uv_rwlock_wrlock(&table->rwlock); + return UVWASI_ESUCCESS; +} + + +uvwasi_errno_t uvwasi_fd_table_unlock(struct uvwasi_fd_table_t* table) { + if (table == NULL) + return UVWASI_EINVAL; + + uv_rwlock_wrunlock(&table->rwlock); + return UVWASI_ESUCCESS; +} diff --git a/deps/uvwasi/src/uv_mapping.c b/deps/uvwasi/src/uv_mapping.c index 846dcedbeb6b4f..297fdf5b75176f 100644 --- a/deps/uvwasi/src/uv_mapping.c +++ b/deps/uvwasi/src/uv_mapping.c @@ -241,3 +241,26 @@ void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs) { fs->st_mtim = uvwasi__timespec_to_timestamp(&stat->st_mtim); fs->st_ctim = uvwasi__timespec_to_timestamp(&stat->st_ctim); } + + +uvwasi_errno_t uvwasi__get_filetype_by_fd(uv_file fd, uvwasi_filetype_t* type) { + uv_fs_t req; + int r; + + r = uv_fs_fstat(NULL, &req, fd, NULL); + if (r != 0) { + *type = UVWASI_FILETYPE_UNKNOWN; + uv_fs_req_cleanup(&req); + return uvwasi__translate_uv_error(r); + } + + *type = uvwasi__stat_to_filetype(&req.statbuf); + uv_fs_req_cleanup(&req); + + if (*type == UVWASI_FILETYPE_SOCKET_STREAM && + uv_guess_handle(fd) == UV_UDP) { + *type = UVWASI_FILETYPE_SOCKET_DGRAM; + } + + return UVWASI_ESUCCESS; +} diff --git a/deps/uvwasi/src/uv_mapping.h b/deps/uvwasi/src/uv_mapping.h index d835ca507a4856..5a0542afb4dd8b 100644 --- a/deps/uvwasi/src/uv_mapping.h +++ b/deps/uvwasi/src/uv_mapping.h @@ -11,5 +11,6 @@ int uvwasi__translate_to_uv_signal(uvwasi_signal_t sig); uvwasi_timestamp_t uvwasi__timespec_to_timestamp(const uv_timespec_t* ts); uvwasi_filetype_t uvwasi__stat_to_filetype(const uv_stat_t* stat); void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs); +uvwasi_errno_t uvwasi__get_filetype_by_fd(uv_file fd, uvwasi_filetype_t* type); #endif /* __UVWASI_UV_MAPPING_H__ */ diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c index e5d210657ce8b1..53b7699f590e53 100644 --- a/deps/uvwasi/src/uvwasi.c +++ b/deps/uvwasi/src/uvwasi.c @@ -22,6 +22,7 @@ #include "uv_mapping.h" #include "fd_table.h" #include "clocks.h" +#include "wasi_rights.h" /* TODO(cjihrig): PATH_MAX_BYTES shouldn't be stack allocated. On Windows, paths can be 32k long, and this PATH_MAX_BYTES is an artificial limitation. */ @@ -877,18 +878,26 @@ uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd) { if (uvwasi == NULL) return UVWASI_EINVAL; - err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0); + uvwasi_fd_table_lock(&uvwasi->fds); + + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, fd, &wrap, 0, 0); if (err != UVWASI_ESUCCESS) - return err; + goto exit; r = uv_fs_close(NULL, &req, wrap->fd, NULL); uv_mutex_unlock(&wrap->mutex); uv_fs_req_cleanup(&req); - if (r != 0) - return uvwasi__translate_uv_error(r); + if (r != 0) { + err = uvwasi__translate_uv_error(r); + goto exit; + } - return uvwasi_fd_table_remove(uvwasi, &uvwasi->fds, fd); + err = uvwasi_fd_table_remove_nolock(uvwasi, &uvwasi->fds, fd); + +exit: + uvwasi_fd_table_unlock(&uvwasi->fds); + return err; } @@ -1485,41 +1494,10 @@ uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi, uvwasi_fd_t from, uvwasi_fd_t to) { - struct uvwasi_fd_wrap_t* to_wrap; - struct uvwasi_fd_wrap_t* from_wrap; - uv_fs_t req; - uvwasi_errno_t err; - int r; - if (uvwasi == NULL) return UVWASI_EINVAL; - if (from == to) - return UVWASI_ESUCCESS; - - err = uvwasi_fd_table_get(&uvwasi->fds, from, &from_wrap, 0, 0); - if (err != UVWASI_ESUCCESS) - return err; - - err = uvwasi_fd_table_get(&uvwasi->fds, to, &to_wrap, 0, 0); - if (err != UVWASI_ESUCCESS) { - uv_mutex_unlock(&from_wrap->mutex); - return err; - } - - r = uv_fs_close(NULL, &req, to_wrap->fd, NULL); - uv_fs_req_cleanup(&req); - if (r != 0) { - uv_mutex_unlock(&from_wrap->mutex); - uv_mutex_unlock(&to_wrap->mutex); - return uvwasi__translate_uv_error(r); - } - - memcpy(to_wrap, from_wrap, sizeof(*to_wrap)); - to_wrap->id = to; - uv_mutex_unlock(&from_wrap->mutex); - uv_mutex_unlock(&to_wrap->mutex); - return uvwasi_fd_table_remove(uvwasi, &uvwasi->fds, from); + return uvwasi_fd_table_renumber(uvwasi, &uvwasi->fds, to, from); } @@ -1793,37 +1771,41 @@ uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi, if (uvwasi == NULL || old_path == NULL || new_path == NULL) return UVWASI_EINVAL; - if (old_fd == new_fd) { - err = uvwasi_fd_table_get(&uvwasi->fds, - old_fd, - &old_wrap, - UVWASI_RIGHT_PATH_LINK_SOURCE | - UVWASI_RIGHT_PATH_LINK_TARGET, - 0); - if (err != UVWASI_ESUCCESS) - return err; + uvwasi_fd_table_lock(&uvwasi->fds); + if (old_fd == new_fd) { + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + old_fd, + &old_wrap, + UVWASI_RIGHT_PATH_LINK_SOURCE | + UVWASI_RIGHT_PATH_LINK_TARGET, + 0); new_wrap = old_wrap; } else { - err = uvwasi_fd_table_get(&uvwasi->fds, - old_fd, - &old_wrap, - UVWASI_RIGHT_PATH_LINK_SOURCE, - 0); - if (err != UVWASI_ESUCCESS) - return err; - - err = uvwasi_fd_table_get(&uvwasi->fds, - new_fd, - &new_wrap, - UVWASI_RIGHT_PATH_LINK_TARGET, - 0); + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + old_fd, + &old_wrap, + UVWASI_RIGHT_PATH_LINK_SOURCE, + 0); if (err != UVWASI_ESUCCESS) { - uv_mutex_unlock(&old_wrap->mutex); + uvwasi_fd_table_unlock(&uvwasi->fds); return err; } + + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + new_fd, + &new_wrap, + UVWASI_RIGHT_PATH_LINK_TARGET, + 0); + if (err != UVWASI_ESUCCESS) + uv_mutex_unlock(&old_wrap->mutex); } + uvwasi_fd_table_unlock(&uvwasi->fds); + + if (err != UVWASI_ESUCCESS) + return err; + err = uvwasi__resolve_path(uvwasi, old_wrap, old_path, @@ -1851,9 +1833,9 @@ uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi, err = UVWASI_ESUCCESS; exit: - uv_mutex_unlock(&old_wrap->mutex); + uv_mutex_unlock(&new_wrap->mutex); if (old_fd != new_fd) - uv_mutex_unlock(&new_wrap->mutex); + uv_mutex_unlock(&old_wrap->mutex); return err; } @@ -1871,8 +1853,11 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi, char resolved_path[PATH_MAX_BYTES]; uvwasi_rights_t needed_inheriting; uvwasi_rights_t needed_base; + uvwasi_rights_t max_base; + uvwasi_rights_t max_inheriting; struct uvwasi_fd_wrap_t* dirfd_wrap; - struct uvwasi_fd_wrap_t wrap; + struct uvwasi_fd_wrap_t *wrap; + uvwasi_filetype_t filetype; uvwasi_errno_t err; uv_fs_t req; int flags; @@ -1949,37 +1934,43 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi, } r = uv_fs_open(NULL, &req, resolved_path, flags, 0666, NULL); + uv_mutex_unlock(&dirfd_wrap->mutex); uv_fs_req_cleanup(&req); - if (r < 0) { - uv_mutex_unlock(&dirfd_wrap->mutex); + if (r < 0) return uvwasi__translate_uv_error(r); - } - err = uvwasi_fd_table_insert_fd(uvwasi, - &uvwasi->fds, - r, - flags, - resolved_path, - fs_rights_base, - fs_rights_inheriting, - &wrap); - if (err != UVWASI_ESUCCESS) { - uv_mutex_unlock(&dirfd_wrap->mutex); + /* Not all platforms support UV_FS_O_DIRECTORY, so get the file type and check + it here. */ + err = uvwasi__get_filetype_by_fd(r, &filetype); + if (err != UVWASI_ESUCCESS) goto close_file_and_error_exit; - } - /* Not all platforms support UV_FS_O_DIRECTORY, so enforce it here as well. */ if ((o_flags & UVWASI_O_DIRECTORY) != 0 && - wrap.type != UVWASI_FILETYPE_DIRECTORY) { - uv_mutex_unlock(&dirfd_wrap->mutex); - uvwasi_fd_table_remove(uvwasi, &uvwasi->fds, wrap.id); + filetype != UVWASI_FILETYPE_DIRECTORY) { err = UVWASI_ENOTDIR; goto close_file_and_error_exit; } - *fd = wrap.id; - uv_mutex_unlock(&dirfd_wrap->mutex); + err = uvwasi__get_rights(r, flags, filetype, &max_base, &max_inheriting); + if (err != UVWASI_ESUCCESS) + goto close_file_and_error_exit; + + err = uvwasi_fd_table_insert(uvwasi, + &uvwasi->fds, + r, + resolved_path, + resolved_path, + filetype, + fs_rights_base & max_base, + fs_rights_inheriting & max_inheriting, + 0, + &wrap); + if (err != UVWASI_ESUCCESS) + goto close_file_and_error_exit; + + *fd = wrap->id; + uv_mutex_unlock(&wrap->mutex); return UVWASI_ESUCCESS; close_file_and_error_exit: @@ -2097,36 +2088,41 @@ uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi, if (uvwasi == NULL || old_path == NULL || new_path == NULL) return UVWASI_EINVAL; + uvwasi_fd_table_lock(&uvwasi->fds); + if (old_fd == new_fd) { - err = uvwasi_fd_table_get(&uvwasi->fds, - old_fd, - &old_wrap, - UVWASI_RIGHT_PATH_RENAME_SOURCE | - UVWASI_RIGHT_PATH_RENAME_TARGET, - 0); - if (err != UVWASI_ESUCCESS) - return err; + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + old_fd, + &old_wrap, + UVWASI_RIGHT_PATH_RENAME_SOURCE | + UVWASI_RIGHT_PATH_RENAME_TARGET, + 0); new_wrap = old_wrap; } else { - err = uvwasi_fd_table_get(&uvwasi->fds, - old_fd, - &old_wrap, - UVWASI_RIGHT_PATH_RENAME_SOURCE, - 0); - if (err != UVWASI_ESUCCESS) - return err; - - err = uvwasi_fd_table_get(&uvwasi->fds, - new_fd, - &new_wrap, - UVWASI_RIGHT_PATH_RENAME_TARGET, - 0); + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + old_fd, + &old_wrap, + UVWASI_RIGHT_PATH_RENAME_SOURCE, + 0); if (err != UVWASI_ESUCCESS) { - uv_mutex_unlock(&old_wrap->mutex); + uvwasi_fd_table_unlock(&uvwasi->fds); return err; } + + err = uvwasi_fd_table_get_nolock(&uvwasi->fds, + new_fd, + &new_wrap, + UVWASI_RIGHT_PATH_RENAME_TARGET, + 0); + if (err != UVWASI_ESUCCESS) + uv_mutex_unlock(&old_wrap->mutex); } + uvwasi_fd_table_unlock(&uvwasi->fds); + + if (err != UVWASI_ESUCCESS) + return err; + err = uvwasi__resolve_path(uvwasi, old_wrap, old_path, @@ -2154,9 +2150,9 @@ uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi, err = UVWASI_ESUCCESS; exit: - uv_mutex_unlock(&old_wrap->mutex); + uv_mutex_unlock(&new_wrap->mutex); if (old_fd != new_fd) - uv_mutex_unlock(&new_wrap->mutex); + uv_mutex_unlock(&old_wrap->mutex); return err; } diff --git a/deps/uvwasi/src/wasi_rights.c b/deps/uvwasi/src/wasi_rights.c new file mode 100644 index 00000000000000..79d0338086a244 --- /dev/null +++ b/deps/uvwasi/src/wasi_rights.c @@ -0,0 +1,62 @@ +#include "uv.h" +#include "wasi_rights.h" +#include "wasi_types.h" + + +uvwasi_errno_t uvwasi__get_rights(uv_file fd, + int flags, + uvwasi_filetype_t type, + uvwasi_rights_t* rights_base, + uvwasi_rights_t* rights_inheriting) { + int read_or_write_only; + + if (type == UVWASI_FILETYPE_UNKNOWN) + return UVWASI_EINVAL; + + switch (type) { + case UVWASI_FILETYPE_REGULAR_FILE: + *rights_base = UVWASI__RIGHTS_REGULAR_FILE_BASE; + *rights_inheriting = UVWASI__RIGHTS_REGULAR_FILE_INHERITING; + break; + + case UVWASI_FILETYPE_DIRECTORY: + *rights_base = UVWASI__RIGHTS_DIRECTORY_BASE; + *rights_inheriting = UVWASI__RIGHTS_DIRECTORY_INHERITING; + break; + + case UVWASI_FILETYPE_SOCKET_STREAM: + case UVWASI_FILETYPE_SOCKET_DGRAM: + *rights_base = UVWASI__RIGHTS_SOCKET_BASE; + *rights_inheriting = UVWASI__RIGHTS_SOCKET_INHERITING; + break; + + case UVWASI_FILETYPE_CHARACTER_DEVICE: + if (uv_guess_handle(fd) == UV_TTY) { + *rights_base = UVWASI__RIGHTS_TTY_BASE; + *rights_inheriting = UVWASI__RIGHTS_TTY_INHERITING; + } else { + *rights_base = UVWASI__RIGHTS_CHARACTER_DEVICE_BASE; + *rights_inheriting = UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING; + } + break; + + case UVWASI_FILETYPE_BLOCK_DEVICE: + *rights_base = UVWASI__RIGHTS_BLOCK_DEVICE_BASE; + *rights_inheriting = UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING; + break; + + default: + *rights_base = 0; + *rights_inheriting = 0; + } + + /* Disable read/write bits depending on access mode. */ + read_or_write_only = flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR); + + if (read_or_write_only == UV_FS_O_RDONLY) + *rights_base &= ~UVWASI_RIGHT_FD_WRITE; + else if (read_or_write_only == UV_FS_O_WRONLY) + *rights_base &= ~UVWASI_RIGHT_FD_READ; + + return UVWASI_ESUCCESS; +} diff --git a/deps/uvwasi/src/wasi_rights.h b/deps/uvwasi/src/wasi_rights.h new file mode 100644 index 00000000000000..fb19bd0a00e74e --- /dev/null +++ b/deps/uvwasi/src/wasi_rights.h @@ -0,0 +1,104 @@ +#ifndef __UVWASI_WASI_RIGHTS_H__ +#define __UVWASI_WASI_RIGHTS_H__ + +#include "wasi_types.h" + +#define UVWASI__RIGHTS_ALL (UVWASI_RIGHT_FD_DATASYNC | \ + UVWASI_RIGHT_FD_READ | \ + UVWASI_RIGHT_FD_SEEK | \ + UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + UVWASI_RIGHT_FD_SYNC | \ + UVWASI_RIGHT_FD_TELL | \ + UVWASI_RIGHT_FD_WRITE | \ + UVWASI_RIGHT_FD_ADVISE | \ + UVWASI_RIGHT_FD_ALLOCATE | \ + UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \ + UVWASI_RIGHT_PATH_CREATE_FILE | \ + UVWASI_RIGHT_PATH_LINK_SOURCE | \ + UVWASI_RIGHT_PATH_LINK_TARGET | \ + UVWASI_RIGHT_PATH_OPEN | \ + UVWASI_RIGHT_FD_READDIR | \ + UVWASI_RIGHT_PATH_READLINK | \ + UVWASI_RIGHT_PATH_RENAME_SOURCE | \ + UVWASI_RIGHT_PATH_RENAME_TARGET | \ + UVWASI_RIGHT_PATH_FILESTAT_GET | \ + UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ + UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ + UVWASI_RIGHT_FD_FILESTAT_GET | \ + UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \ + UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \ + UVWASI_RIGHT_PATH_SYMLINK | \ + UVWASI_RIGHT_PATH_UNLINK_FILE | \ + UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \ + UVWASI_RIGHT_POLL_FD_READWRITE | \ + UVWASI_RIGHT_SOCK_SHUTDOWN) + +#define UVWASI__RIGHTS_BLOCK_DEVICE_BASE UVWASI__RIGHTS_ALL +#define UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING UVWASI__RIGHTS_ALL + +#define UVWASI__RIGHTS_CHARACTER_DEVICE_BASE UVWASI__RIGHTS_ALL +#define UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING UVWASI__RIGHTS_ALL + +#define UVWASI__RIGHTS_REGULAR_FILE_BASE (UVWASI_RIGHT_FD_DATASYNC | \ + UVWASI_RIGHT_FD_READ | \ + UVWASI_RIGHT_FD_SEEK | \ + UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + UVWASI_RIGHT_FD_SYNC | \ + UVWASI_RIGHT_FD_TELL | \ + UVWASI_RIGHT_FD_WRITE | \ + UVWASI_RIGHT_FD_ADVISE | \ + UVWASI_RIGHT_FD_ALLOCATE | \ + UVWASI_RIGHT_FD_FILESTAT_GET | \ + UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \ + UVWASI_RIGHT_FD_FILESTAT_SET_TIMES |\ + UVWASI_RIGHT_POLL_FD_READWRITE) +#define UVWASI__RIGHTS_REGULAR_FILE_INHERITING 0 + +#define UVWASI__RIGHTS_DIRECTORY_BASE (UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + UVWASI_RIGHT_FD_SYNC | \ + UVWASI_RIGHT_FD_ADVISE | \ + UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \ + UVWASI_RIGHT_PATH_CREATE_FILE | \ + UVWASI_RIGHT_PATH_LINK_SOURCE | \ + UVWASI_RIGHT_PATH_LINK_TARGET | \ + UVWASI_RIGHT_PATH_OPEN | \ + UVWASI_RIGHT_FD_READDIR | \ + UVWASI_RIGHT_PATH_READLINK | \ + UVWASI_RIGHT_PATH_RENAME_SOURCE | \ + UVWASI_RIGHT_PATH_RENAME_TARGET | \ + UVWASI_RIGHT_PATH_FILESTAT_GET | \ + UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ + UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ + UVWASI_RIGHT_FD_FILESTAT_GET | \ + UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \ + UVWASI_RIGHT_PATH_SYMLINK | \ + UVWASI_RIGHT_PATH_UNLINK_FILE | \ + UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \ + UVWASI_RIGHT_POLL_FD_READWRITE) +#define UVWASI__RIGHTS_DIRECTORY_INHERITING (UVWASI__RIGHTS_DIRECTORY_BASE | \ + UVWASI__RIGHTS_REGULAR_FILE_BASE) + +#define UVWASI__RIGHTS_SOCKET_BASE (UVWASI_RIGHT_FD_READ | \ + UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + UVWASI_RIGHT_FD_WRITE | \ + UVWASI_RIGHT_FD_FILESTAT_GET | \ + UVWASI_RIGHT_POLL_FD_READWRITE | \ + UVWASI_RIGHT_SOCK_SHUTDOWN) +#define UVWASI__RIGHTS_SOCKET_INHERITING UVWASI__RIGHTS_ALL; + +#define UVWASI__RIGHTS_TTY_BASE (UVWASI_RIGHT_FD_READ | \ + UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + UVWASI_RIGHT_FD_WRITE | \ + UVWASI_RIGHT_FD_FILESTAT_GET | \ + UVWASI_RIGHT_POLL_FD_READWRITE) +#define UVWASI__RIGHTS_TTY_INHERITING 0 + + +uvwasi_errno_t uvwasi__get_rights(uv_file fd, + int flags, + uvwasi_filetype_t type, + uvwasi_rights_t* rights_base, + uvwasi_rights_t* rights_inheriting); + + +#endif /* __UVWASI_WASI_RIGHTS_H__ */ diff --git a/deps/uvwasi/uvwasi.gyp b/deps/uvwasi/uvwasi.gyp index 21ac35cdfc11ad..6963cbf20a7923 100644 --- a/deps/uvwasi/uvwasi.gyp +++ b/deps/uvwasi/uvwasi.gyp @@ -13,6 +13,7 @@ 'src/fd_table.c', 'src/uv_mapping.c', 'src/uvwasi.c', + 'src/wasi_rights.c', ], 'dependencies': [ '../uv/uv.gyp:libuv', diff --git a/test/fixtures/wasi/input2.txt b/test/fixtures/wasi/input2.txt new file mode 100644 index 00000000000000..6aadea38006fb0 --- /dev/null +++ b/test/fixtures/wasi/input2.txt @@ -0,0 +1 @@ +hello from input2.txt diff --git a/test/wasi/c/freopen.c b/test/wasi/c/freopen.c new file mode 100644 index 00000000000000..0f47058da2ca95 --- /dev/null +++ b/test/wasi/c/freopen.c @@ -0,0 +1,16 @@ +#include +#include + +int main() { + FILE* file_orig = fopen("/sandbox/input.txt", "r"); + assert(file_orig != NULL); + FILE* file_new = freopen("/sandbox/input2.txt", "r", file_orig); + assert(file_new != NULL); + + int c = fgetc(file_new); + while (c != EOF) { + int wrote = fputc((char)c, stdout); + assert(wrote != EOF); + c = fgetc(file_new); + } +} diff --git a/test/wasi/test-wasi.js b/test/wasi/test-wasi.js index 9c8b2a752778f9..01d5aa8fe5cc28 100644 --- a/test/wasi/test-wasi.js +++ b/test/wasi/test-wasi.js @@ -60,6 +60,7 @@ if (process.argv[2] === 'wasi-child') { runWASI({ test: 'clock_getres' }); runWASI({ test: 'exitcode', exitCode: 120 }); runWASI({ test: 'fd_prestat_get_refresh' }); + runWASI({ test: 'freopen', stdout: `hello from input2.txt${EOL}` }); runWASI({ test: 'getentropy' }); runWASI({ test: 'getrusage' }); runWASI({ test: 'gettimeofday' }); diff --git a/test/wasi/wasm/freopen.wasm b/test/wasi/wasm/freopen.wasm new file mode 100755 index 00000000000000..fb417fbe21fa69 Binary files /dev/null and b/test/wasi/wasm/freopen.wasm differ