summaryrefslogtreecommitdiff
path: root/deps/uvwasi/src
diff options
context:
space:
mode:
authorcjihrig <cjihrig@gmail.com>2019-09-04 17:56:51 -0400
committerAnna Henningsen <anna@addaleax.net>2019-11-30 18:06:39 +0100
commit09b1228c3a2723c6ecb768b40a507688015a478f (patch)
tree88acbfc979bc6f73572c86e8ee804bf0fa4ad326 /deps/uvwasi/src
parent73c837b1ae91cb8852e75a921fa24c714471d690 (diff)
downloadandroid-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.tar.gz
android-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.tar.bz2
android-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.zip
wasi: introduce initial WASI support
Co-authored-by: Gus Caplan <me@gus.host> Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com> Co-authored-by: Jiawen Geng <technicalcute@gmail.com> Co-authored-by: Tobias Nießen <tniessen@tnie.de> Co-authored-by: Chengzhong Wu <legendecas@gmail.com> PR-URL: https://github.com/nodejs/node/pull/30258 Refs: https://github.com/nodejs/node/pull/27850 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Wyatt Preul <wpreul@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Diffstat (limited to 'deps/uvwasi/src')
-rw-r--r--deps/uvwasi/src/clocks.c194
-rw-r--r--deps/uvwasi/src/fd_table.c422
-rw-r--r--deps/uvwasi/src/uv_mapping.c243
-rw-r--r--deps/uvwasi/src/uvwasi.c1918
4 files changed, 2777 insertions, 0 deletions
diff --git a/deps/uvwasi/src/clocks.c b/deps/uvwasi/src/clocks.c
new file mode 100644
index 0000000000..e1fbc696b6
--- /dev/null
+++ b/deps/uvwasi/src/clocks.c
@@ -0,0 +1,194 @@
+#ifndef _WIN32
+# include <errno.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+# include <time.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+
+#define UVWASI__WIN_TIME_AND_RETURN(handle, time) \
+ do { \
+ FILETIME create; \
+ FILETIME exit; \
+ FILETIME system; \
+ FILETIME user; \
+ SYSTEMTIME sys_system; \
+ SYSTEMTIME sys_user; \
+ if (0 == GetProcessTimes((handle), &create, &exit, &system, &user)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ if (0 == FileTimeToSystemTime(&system, &sys_system)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ if (0 == FileTimeToSystemTime(&user, &sys_user)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ (time) = (((sys_system.wHour * 3600) + (sys_system.wMinute * 60) + \
+ sys_system.wSecond) * NANOS_PER_SEC) + \
+ (sys_system.wMilliseconds * 1000000) + \
+ (((sys_user.wHour * 3600) + (sys_user.wMinute * 60) + \
+ sys_user.wSecond) * NANOS_PER_SEC) + \
+ (sys_user.wMilliseconds * 1000000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__CLOCK_GETTIME_AND_RETURN(clk, time) \
+ do { \
+ struct timespec ts; \
+ if (0 != clock_gettime((clk), &ts)) \
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
+ (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__GETRUSAGE_AND_RETURN(who, time) \
+ do { \
+ struct rusage ru; \
+ if (0 != getrusage((who), &ru)) \
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
+ (time) = (ru.ru_utime.tv_sec * NANOS_PER_SEC) + \
+ (ru.ru_utime.tv_usec * 1000) + \
+ (ru.ru_stime.tv_sec * NANOS_PER_SEC) + \
+ (ru.ru_stime.tv_usec * 1000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__OSX_THREADTIME_AND_RETURN(time) \
+ do { \
+ mach_port_t thread; \
+ thread_basic_info_data_t info; \
+ mach_msg_type_number_t count; \
+ count = THREAD_BASIC_INFO_COUNT; \
+ thread = pthread_mach_thread_np(pthread_self()); \
+ if (KERN_SUCCESS != thread_info(thread, \
+ THREAD_BASIC_INFO, \
+ (thread_info_t) &info, \
+ &count)) { \
+ return UVWASI_ENOSYS; \
+ } \
+ (time) = (info.user_time.seconds * NANOS_PER_SEC) + \
+ (info.user_time.microseconds * 1000) + \
+ (info.system_time.seconds * NANOS_PER_SEC) + \
+ (info.system_time.microseconds * 1000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__WIN_GETRES_AND_RETURN(time) \
+ do { \
+ /* The GetProcessTimes() docs claim a resolution of 100 ns. */ \
+ (time) = 100; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__CLOCK_GETRES_AND_RETURN(clk, time) \
+ do { \
+ struct timespec ts; \
+ /* Try calling clock_getres(). If it doesn't succeed, then default to \
+ 1000000. We implement all of the clocks, and some platforms (such as \
+ SmartOS) don't support all of the clocks, even though they define \
+ the constants for them. */ \
+ if (0 != clock_getres((clk), &ts)) \
+ (time) = 1000000; \
+ else \
+ (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__SLOW_GETRES_AND_RETURN(time) \
+ do { \
+ /* Assume a "worst case" of 1000000 ns resolution. */ \
+ (time) = 1000000; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time) {
+ uv_timeval64_t tv;
+ int r;
+
+ r = uv_gettimeofday(&tv);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ *time = (tv.tv_sec * NANOS_PER_SEC) + (tv.tv_usec * 1000);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_TIME_AND_RETURN(GetCurrentProcess(), *time);
+#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
+ !defined(__APPLE__) && \
+ !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
+#else
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_SELF, *time);
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_TIME_AND_RETURN(GetCurrentThread(), *time);
+#elif defined(__APPLE__)
+ UVWASI__OSX_THREADTIME_AND_RETURN(*time);
+#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
+#else
+# if defined(RUSAGE_LWP)
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_LWP, *time);
+# elif defined(RUSAGE_THREAD)
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_THREAD, *time);
+# else
+ return UVWASI_ENOSYS;
+# endif /* RUSAGE_LWP */
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_GETRES_AND_RETURN(*time);
+#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
+ !defined(__APPLE__) && \
+ !defined(__sun)
+ UVWASI__CLOCK_GETRES_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
+#else
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_GETRES_AND_RETURN(*time);
+#elif defined(__APPLE__)
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
+#elif defined(RUSAGE_THREAD) || defined(RUSAGE_LWP)
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#else
+ return UVWASI_ENOSYS;
+#endif
+}
diff --git a/deps/uvwasi/src/fd_table.c b/deps/uvwasi/src/fd_table.c
new file mode 100644
index 0000000000..9343868074
--- /dev/null
+++ b/deps/uvwasi/src/fd_table.c
@@ -0,0 +1,422 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "fd_table.h"
+#include "wasi_types.h"
+#include "uv_mapping.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(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;
+ uint32_t new_size;
+ int index;
+ uint32_t i;
+
+ /* Check that there is room for a new item. If there isn't, grow the table. */
+ if (table->used >= table->size) {
+ new_size = table->size * 2;
+ new_fds = realloc(table->fds, new_size * sizeof(*new_fds));
+ if (new_fds == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = table->size; i < new_size; ++i)
+ new_fds[i].valid = 0;
+
+ index = table->size;
+ table->fds = new_fds;
+ table->size = new_size;
+ } else {
+ /* The table is big enough, so find an empty slot for the new data. */
+ index = -1;
+ for (i = 0; i < table->size; ++i) {
+ if (table->fds[i].valid != 1) {
+ index = i;
+ break;
+ }
+ }
+
+ /* index should never be -1. */
+ if (index == -1)
+ return UVWASI_ENOSPC;
+ }
+
+ entry = &table->fds[index];
+ entry->id = index;
+ entry->fd = fd;
+ strcpy(entry->path, mapped_path);
+ strcpy(entry->real_path, real_path);
+ entry->type = type;
+ entry->rights_base = rights_base;
+ entry->rights_inheriting = rights_inheriting;
+ entry->preopen = preopen;
+ entry->valid = 1;
+ table->used++;
+
+ if (wrap != NULL)
+ *wrap = entry;
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_fd_table_t* table,
+ uint32_t init_size) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_filetype_t type;
+ uvwasi_rights_t base;
+ uvwasi_rights_t inheriting;
+ uvwasi_errno_t err;
+ uvwasi_fd_t i;
+
+ /* Require an initial size of at least three to store the stdio FDs. */
+ if (table == NULL || init_size < 3)
+ return UVWASI_EINVAL;
+
+ table->used = 0;
+ table->size = init_size;
+ table->fds = calloc(init_size, sizeof(struct uvwasi_fd_wrap_t));
+
+ if (table->fds == NULL)
+ return UVWASI_ENOMEM;
+
+ /* Create the stdio FDs. */
+ for (i = 0; i < 3; ++i) {
+ err = uvwasi__get_type_and_rights(i,
+ UV_FS_O_RDWR,
+ &type,
+ &base,
+ &inheriting);
+ if (err != UVWASI_ESUCCESS)
+ goto error_exit;
+
+ err = uvwasi__fd_table_insert(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) {
+ err = UVWASI_EBADF;
+ goto error_exit;
+ }
+ }
+
+ return UVWASI_ESUCCESS;
+error_exit:
+ uvwasi_fd_table_free(table);
+ return err;
+}
+
+
+void uvwasi_fd_table_free(struct uvwasi_fd_table_t* table) {
+ if (table == NULL)
+ return;
+
+ free(table->fds);
+ table->fds = NULL;
+ table->size = 0;
+ table->used = 0;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_fd_table_t* table,
+ const uv_file fd,
+ const char* path,
+ const char* real_path) {
+ uvwasi_filetype_t type;
+ uvwasi_rights_t base;
+ uvwasi_rights_t inheriting;
+ uvwasi_errno_t err;
+
+ if (table == NULL || path == NULL || real_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi__get_type_and_rights(fd, 0, &type, &base, &inheriting);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ if (type != UVWASI_FILETYPE_DIRECTORY)
+ return UVWASI_ENOTDIR;
+
+ err = uvwasi__fd_table_insert(table,
+ fd,
+ path,
+ real_path,
+ UVWASI_FILETYPE_DIRECTORY,
+ UVWASI__RIGHTS_DIRECTORY_BASE,
+ UVWASI__RIGHTS_DIRECTORY_INHERITING,
+ 1,
+ NULL);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_insert_fd(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;
+
+ if (table == NULL || path == NULL || wrap == 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(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;
+}
+
+
+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) {
+ struct uvwasi_fd_wrap_t* entry;
+
+ if (table == NULL || wrap == NULL)
+ return UVWASI_EINVAL;
+ if (id >= table->size)
+ return UVWASI_EBADF;
+
+ entry = &table->fds[id];
+
+ if (entry->valid != 1 || 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)
+ return UVWASI_ENOTCAPABLE;
+
+ *wrap = entry;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id) {
+ struct uvwasi_fd_wrap_t* entry;
+
+ if (table == NULL)
+ return UVWASI_EINVAL;
+ if (id >= table->size)
+ return UVWASI_EBADF;
+
+ entry = &table->fds[id];
+
+ if (entry->valid != 1 || entry->id != id)
+ return UVWASI_EBADF;
+
+ entry->valid = 0;
+ table->used--;
+ return UVWASI_ESUCCESS;
+}
diff --git a/deps/uvwasi/src/uv_mapping.c b/deps/uvwasi/src/uv_mapping.c
new file mode 100644
index 0000000000..846dcedbeb
--- /dev/null
+++ b/deps/uvwasi/src/uv_mapping.c
@@ -0,0 +1,243 @@
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if !defined(S_ISCHR) && defined(S_IFMT) && defined(S_IFCHR)
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFMT) && defined(S_IFLNK)
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+
+uvwasi_errno_t uvwasi__translate_uv_error(int err) {
+ switch (err) {
+ case UV_E2BIG: return UVWASI_E2BIG;
+ case UV_EACCES: return UVWASI_EACCES;
+ case UV_EADDRINUSE: return UVWASI_EADDRINUSE;
+ case UV_EADDRNOTAVAIL: return UVWASI_EADDRNOTAVAIL;
+ case UV_EAFNOSUPPORT: return UVWASI_EAFNOSUPPORT;
+ case UV_EAGAIN: return UVWASI_EAGAIN;
+ case UV_EALREADY: return UVWASI_EALREADY;
+ case UV_EBADF: return UVWASI_EBADF;
+ case UV_EBUSY: return UVWASI_EBUSY;
+ case UV_ECANCELED: return UVWASI_ECANCELED;
+ case UV_ECONNABORTED: return UVWASI_ECONNABORTED;
+ case UV_ECONNREFUSED: return UVWASI_ECONNREFUSED;
+ case UV_ECONNRESET: return UVWASI_ECONNRESET;
+ case UV_EDESTADDRREQ: return UVWASI_EDESTADDRREQ;
+ case UV_EEXIST: return UVWASI_EEXIST;
+ case UV_EFAULT: return UVWASI_EFAULT;
+ case UV_EFBIG: return UVWASI_EFBIG;
+ case UV_EHOSTUNREACH: return UVWASI_EHOSTUNREACH;
+ case UV_EINTR: return UVWASI_EINTR;
+ case UV_EINVAL: return UVWASI_EINVAL;
+ case UV_EIO: return UVWASI_EIO;
+ case UV_EISCONN: return UVWASI_EISCONN;
+ case UV_EISDIR: return UVWASI_EISDIR;
+ case UV_ELOOP: return UVWASI_ELOOP;
+ case UV_EMFILE: return UVWASI_EMFILE;
+ case UV_EMLINK: return UVWASI_EMLINK;
+ case UV_EMSGSIZE: return UVWASI_EMSGSIZE;
+ case UV_ENAMETOOLONG: return UVWASI_ENAMETOOLONG;
+ case UV_ENETDOWN: return UVWASI_ENETDOWN;
+ case UV_ENETUNREACH: return UVWASI_ENETUNREACH;
+ case UV_ENFILE: return UVWASI_ENFILE;
+ case UV_ENOBUFS: return UVWASI_ENOBUFS;
+ case UV_ENODEV: return UVWASI_ENODEV;
+ case UV_ENOENT: return UVWASI_ENOENT;
+ case UV_ENOMEM: return UVWASI_ENOMEM;
+ case UV_ENOPROTOOPT: return UVWASI_ENOPROTOOPT;
+ case UV_ENOSPC: return UVWASI_ENOSPC;
+ case UV_ENOSYS: return UVWASI_ENOSYS;
+ case UV_ENOTCONN: return UVWASI_ENOTCONN;
+ case UV_ENOTDIR: return UVWASI_ENOTDIR;
+ /* On at least some AIX machines, ENOTEMPTY and EEXIST are equivalent. */
+#if ENOTEMPTY != EEXIST
+ case UV_ENOTEMPTY: return UVWASI_ENOTEMPTY;
+#endif /* ENOTEMPTY != EEXIST */
+ case UV_ENOTSOCK: return UVWASI_ENOTSOCK;
+ case UV_ENOTSUP: return UVWASI_ENOTSUP;
+ case UV_ENXIO: return UVWASI_ENXIO;
+ case UV_EPERM: return UVWASI_EPERM;
+ case UV_EPIPE: return UVWASI_EPIPE;
+ case UV_EPROTO: return UVWASI_EPROTO;
+ case UV_EPROTONOSUPPORT: return UVWASI_EPROTONOSUPPORT;
+ case UV_EPROTOTYPE: return UVWASI_EPROTOTYPE;
+ case UV_ERANGE: return UVWASI_ERANGE;
+ case UV_EROFS: return UVWASI_EROFS;
+ case UV_ESPIPE: return UVWASI_ESPIPE;
+ case UV_ESRCH: return UVWASI_ESRCH;
+ case UV_ETIMEDOUT: return UVWASI_ETIMEDOUT;
+ case UV_ETXTBSY: return UVWASI_ETXTBSY;
+ case UV_EXDEV: return UVWASI_EXDEV;
+ case 0: return UVWASI_ESUCCESS;
+ /* The following libuv error codes have no corresponding WASI error code:
+ UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS, UV_EAI_BADHINTS,
+ UV_EAI_CANCELED, UV_EAI_FAIL, UV_EAI_FAMILY, UV_EAI_MEMORY,
+ UV_EAI_NODATA, UV_EAI_NONAME, UV_EAI_OVERFLOW, UV_EAI_PROTOCOL,
+ UV_EAI_SERVICE, UV_EAI_SOCKTYPE, UV_ECHARSET, UV_ENONET, UV_EOF,
+ UV_ESHUTDOWN, UV_UNKNOWN
+ */
+ default:
+ /* libuv errors are < 0 */
+ if (err > 0)
+ return err;
+
+ return UVWASI_ENOSYS;
+ }
+}
+
+
+int uvwasi__translate_to_uv_signal(uvwasi_signal_t sig) {
+ switch (sig) {
+#ifdef SIGABRT
+ case UVWASI_SIGABRT: return SIGABRT;
+#endif
+#ifdef SIGALRM
+ case UVWASI_SIGALRM: return SIGALRM;
+#endif
+#ifdef SIGBUS
+ case UVWASI_SIGBUS: return SIGBUS;
+#endif
+#ifdef SIGCHLD
+ case UVWASI_SIGCHLD: return SIGCHLD;
+#endif
+#ifdef SIGCONT
+ case UVWASI_SIGCONT: return SIGCONT;
+#endif
+#ifdef SIGFPE
+ case UVWASI_SIGFPE: return SIGFPE;
+#endif
+#ifdef SIGHUP
+ case UVWASI_SIGHUP: return SIGHUP;
+#endif
+#ifdef SIGILL
+ case UVWASI_SIGILL: return SIGILL;
+#endif
+#ifdef SIGINT
+ case UVWASI_SIGINT: return SIGINT;
+#endif
+#ifdef SIGKILL
+ case UVWASI_SIGKILL: return SIGKILL;
+#endif
+#ifdef SIGPIPE
+ case UVWASI_SIGPIPE: return SIGPIPE;
+#endif
+#ifdef SIGQUIT
+ case UVWASI_SIGQUIT: return SIGQUIT;
+#endif
+#ifdef SIGSEGV
+ case UVWASI_SIGSEGV: return SIGSEGV;
+#endif
+#ifdef SIGSTOP
+ case UVWASI_SIGSTOP: return SIGSTOP;
+#endif
+#ifdef SIGSYS
+ case UVWASI_SIGSYS: return SIGSYS;
+#endif
+#ifdef SIGTERM
+ case UVWASI_SIGTERM: return SIGTERM;
+#endif
+#ifdef SIGTRAP
+ case UVWASI_SIGTRAP: return SIGTRAP;
+#endif
+#ifdef SIGTSTP
+ case UVWASI_SIGTSTP: return SIGTSTP;
+#endif
+#ifdef SIGTTIN
+ case UVWASI_SIGTTIN: return SIGTTIN;
+#endif
+#ifdef SIGTTOU
+ case UVWASI_SIGTTOU: return SIGTTOU;
+#endif
+#ifdef SIGURG
+ case UVWASI_SIGURG: return SIGURG;
+#endif
+#ifdef SIGUSR1
+ case UVWASI_SIGUSR1: return SIGUSR1;
+#endif
+#ifdef SIGUSR2
+ case UVWASI_SIGUSR2: return SIGUSR2;
+#endif
+#ifdef SIGVTALRM
+ case UVWASI_SIGVTALRM: return SIGVTALRM;
+#endif
+#ifdef SIGXCPU
+ case UVWASI_SIGXCPU: return SIGXCPU;
+#endif
+#ifdef SIGXFSZ
+ case UVWASI_SIGXFSZ: return SIGXFSZ;
+#endif
+ default: return -1;
+ }
+}
+
+
+uvwasi_timestamp_t uvwasi__timespec_to_timestamp(const uv_timespec_t* ts) {
+ /* TODO(cjihrig): Handle overflow. */
+ return (uvwasi_timestamp_t) ts->tv_sec * NANOS_PER_SEC + ts->tv_nsec;
+}
+
+
+uvwasi_filetype_t uvwasi__stat_to_filetype(const uv_stat_t* stat) {
+ uint64_t mode;
+
+ mode = stat->st_mode;
+
+ if (S_ISREG(mode))
+ return UVWASI_FILETYPE_REGULAR_FILE;
+
+ if (S_ISDIR(mode))
+ return UVWASI_FILETYPE_DIRECTORY;
+
+ if (S_ISCHR(mode))
+ return UVWASI_FILETYPE_CHARACTER_DEVICE;
+
+ if (S_ISLNK(mode))
+ return UVWASI_FILETYPE_SYMBOLIC_LINK;
+
+#ifdef S_ISSOCK
+ if (S_ISSOCK(mode))
+ return UVWASI_FILETYPE_SOCKET_STREAM;
+#endif /* S_ISSOCK */
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(mode))
+ return UVWASI_FILETYPE_SOCKET_STREAM;
+#endif /* S_ISFIFO */
+
+#ifdef S_ISBLK
+ if (S_ISBLK(mode))
+ return UVWASI_FILETYPE_BLOCK_DEVICE;
+#endif /* S_ISBLK */
+
+ return UVWASI_FILETYPE_UNKNOWN;
+}
+
+
+void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs) {
+ fs->st_dev = stat->st_dev;
+ fs->st_ino = stat->st_ino;
+ fs->st_nlink = stat->st_nlink;
+ fs->st_size = stat->st_size;
+ fs->st_filetype = uvwasi__stat_to_filetype(stat);
+ fs->st_atim = uvwasi__timespec_to_timestamp(&stat->st_atim);
+ fs->st_mtim = uvwasi__timespec_to_timestamp(&stat->st_mtim);
+ fs->st_ctim = uvwasi__timespec_to_timestamp(&stat->st_ctim);
+}
diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c
new file mode 100644
index 0000000000..39a94b6d21
--- /dev/null
+++ b/deps/uvwasi/src/uvwasi.c
@@ -0,0 +1,1918 @@
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <sched.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <dirent.h>
+# include <time.h>
+# define SLASH '/'
+# define SLASH_STR "/"
+# define IS_SLASH(c) ((c) == '/')
+#else
+# define SLASH '\\'
+# define SLASH_STR "\\"
+# define IS_SLASH(c) ((c) == '/' || (c) == '\\')
+#endif /* _WIN32 */
+
+#define UVWASI__READDIR_NUM_ENTRIES 1
+
+#include "uvwasi.h"
+#include "uv.h"
+#include "uv_mapping.h"
+#include "fd_table.h"
+#include "clocks.h"
+
+
+static int uvwasi__is_absolute_path(const char* path, size_t path_len) {
+ /* TODO(cjihrig): Add a Windows implementation. */
+ return path != NULL && path_len > 0 && path[0] == SLASH;
+}
+
+
+static uvwasi_errno_t uvwasi__resolve_path(const struct uvwasi_fd_wrap_t* fd,
+ const char* path,
+ size_t path_len,
+ char* resolved_path,
+ uvwasi_lookupflags_t flags) {
+ /* TODO(cjihrig): path_len is treated as a size. Need to verify if path_len is
+ really a string length or a size. Also need to verify if it is null
+ terminated. */
+ uv_fs_t realpath_req;
+ uvwasi_errno_t err;
+ char* abs_path;
+ char* tok;
+ char* ptr;
+ int realpath_size;
+ int abs_size;
+ int input_is_absolute;
+ int r;
+#ifdef _WIN32
+ int i;
+#endif /* _WIN32 */
+
+ err = UVWASI_ESUCCESS;
+ input_is_absolute = uvwasi__is_absolute_path(path, path_len);
+
+ if (1 == input_is_absolute) {
+ /* TODO(cjihrig): Revisit this. Copying is probably not necessary here. */
+ abs_size = path_len;
+ abs_path = malloc(abs_size);
+ if (abs_path == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ memcpy(abs_path, path, abs_size);
+ } else {
+ /* Resolve the relative path to fd's real path. */
+ abs_size = path_len + strlen(fd->real_path) + 2;
+ abs_path = malloc(abs_size);
+ if (abs_path == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ r = snprintf(abs_path, abs_size, "%s/%s", fd->real_path, path);
+ if (r <= 0) {
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ goto exit;
+ }
+ }
+
+#ifdef _WIN32
+ /* On Windows, convert slashes to backslashes. */
+ for (i = 0; i < abs_size; ++i) {
+ if (abs_path[i] == '/')
+ abs_path[i] = SLASH;
+ }
+#endif /* _WIN32 */
+
+ ptr = resolved_path;
+ tok = strtok(abs_path, SLASH_STR);
+ for (; tok != NULL; tok = strtok(NULL, SLASH_STR)) {
+ if (0 == strcmp(tok, "."))
+ continue;
+
+ if (0 == strcmp(tok, "..")) {
+ while (*ptr != SLASH && ptr != resolved_path)
+ ptr--;
+ *ptr = '\0';
+ continue;
+ }
+
+#ifdef _WIN32
+ /* On Windows, prevent a leading slash in the path. */
+ if (ptr == resolved_path)
+ r = sprintf(ptr, "%s", tok);
+ else
+#endif /* _WIN32 */
+ r = sprintf(ptr, "%c%s", SLASH, tok);
+
+ if (r < 1) { /* At least one character should have been written. */
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ goto exit;
+ }
+
+ ptr += r;
+ }
+
+ if ((flags & UVWASI_LOOKUP_SYMLINK_FOLLOW) == UVWASI_LOOKUP_SYMLINK_FOLLOW) {
+ r = uv_fs_realpath(NULL, &realpath_req, resolved_path, NULL);
+ if (r == 0) {
+ realpath_size = strlen(realpath_req.ptr) + 1;
+ if (realpath_size > PATH_MAX_BYTES) {
+ err = UVWASI_ENOBUFS;
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ memcpy(resolved_path, realpath_req.ptr, realpath_size);
+ } else if (r != UV_ENOENT) {
+ /* Report errors except ENOENT. */
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ uv_fs_req_cleanup(&realpath_req);
+ }
+
+ /* Verify that the resolved path is still in the sandbox. */
+ if (resolved_path != strstr(resolved_path, fd->real_path)) {
+ err = UVWASI_ENOTCAPABLE;
+ goto exit;
+ }
+
+exit:
+ free(abs_path);
+ return err;
+}
+
+
+static uvwasi_errno_t uvwasi__lseek(uv_file fd,
+ uvwasi_filedelta_t offset,
+ uvwasi_whence_t whence,
+ uvwasi_filesize_t* newoffset) {
+ int real_whence;
+
+ if (whence == UVWASI_WHENCE_CUR)
+ real_whence = SEEK_CUR;
+ else if (whence == UVWASI_WHENCE_END)
+ real_whence = SEEK_END;
+ else if (whence == UVWASI_WHENCE_SET)
+ real_whence = SEEK_SET;
+ else
+ return UVWASI_EINVAL;
+
+#ifdef _WIN32
+ int64_t r;
+
+ r = _lseeki64(fd, offset, real_whence);
+ if (-1L == r)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#else
+ off_t r;
+
+ r = lseek(fd, offset, real_whence);
+ if ((off_t) -1 == r)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#endif /* _WIN32 */
+
+ *newoffset = r;
+ return UVWASI_ESUCCESS;
+}
+
+
+static uvwasi_errno_t uvwasi__setup_iovs(uv_buf_t** buffers,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len) {
+ uv_buf_t* bufs;
+ size_t i;
+
+ bufs = malloc(iovs_len * sizeof(*bufs));
+ if (bufs == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = 0; i < iovs_len; ++i)
+ bufs[i] = uv_buf_init(iovs[i].buf, iovs[i].buf_len);
+
+ *buffers = bufs;
+ return UVWASI_ESUCCESS;
+}
+
+
+static uvwasi_errno_t uvwasi__setup_ciovs(uv_buf_t** buffers,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len) {
+ uv_buf_t* bufs;
+ size_t i;
+
+ bufs = malloc(iovs_len * sizeof(*bufs));
+ if (bufs == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = 0; i < iovs_len; ++i)
+ bufs[i] = uv_buf_init((char*)iovs[i].buf, iovs[i].buf_len);
+
+ *buffers = bufs;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, uvwasi_options_t* options) {
+ uv_fs_t realpath_req;
+ uv_fs_t open_req;
+ uvwasi_errno_t err;
+ size_t args_size;
+ size_t size;
+ size_t offset;
+ size_t env_count;
+ size_t env_buf_size;
+ size_t i;
+ int r;
+
+ if (uvwasi == NULL || options == NULL || options->fd_table_size == 0)
+ return UVWASI_EINVAL;
+
+ uvwasi->argv_buf = NULL;
+ uvwasi->argv = NULL;
+ uvwasi->env_buf = NULL;
+ uvwasi->env = NULL;
+ uvwasi->fds.fds = NULL;
+
+ args_size = 0;
+ for (i = 0; i < options->argc; ++i)
+ args_size += strlen(options->argv[i]) + 1;
+
+ uvwasi->argc = options->argc;
+ uvwasi->argv_buf_size = args_size;
+
+ if (args_size > 0) {
+ uvwasi->argv_buf = malloc(args_size);
+ if (uvwasi->argv_buf == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ uvwasi->argv = calloc(options->argc, sizeof(char*));
+ if (uvwasi->argv == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ offset = 0;
+ for (i = 0; i < options->argc; ++i) {
+ size = strlen(options->argv[i]) + 1;
+ memcpy(uvwasi->argv_buf + offset, options->argv[i], size);
+ uvwasi->argv[i] = uvwasi->argv_buf + offset;
+ offset += size;
+ }
+ }
+
+ env_count = 0;
+ env_buf_size = 0;
+ if (options->envp != NULL) {
+ while (options->envp[env_count] != NULL) {
+ env_buf_size += strlen(options->envp[env_count]) + 1;
+ env_count++;
+ }
+ }
+
+ uvwasi->envc = env_count;
+ uvwasi->env_buf_size = env_buf_size;
+
+ if (env_buf_size > 0) {
+ uvwasi->env_buf = malloc(env_buf_size);
+ if (uvwasi->env_buf == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ uvwasi->env = calloc(env_count, sizeof(char*));
+ if (uvwasi->env == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ offset = 0;
+ for (i = 0; i < env_count; ++i) {
+ size = strlen(options->envp[i]) + 1;
+ memcpy(uvwasi->env_buf + offset, options->envp[i], size);
+ uvwasi->env[i] = uvwasi->env_buf + offset;
+ offset += size;
+ }
+ }
+
+ for (i = 0; i < options->preopenc; ++i) {
+ if (options->preopens[i].real_path == NULL ||
+ options->preopens[i].mapped_path == NULL) {
+ err = UVWASI_EINVAL;
+ goto exit;
+ }
+ }
+
+ err = uvwasi_fd_table_init(&uvwasi->fds, options->fd_table_size);
+ if (err != UVWASI_ESUCCESS)
+ goto exit;
+
+ for (i = 0; i < options->preopenc; ++i) {
+ r = uv_fs_realpath(NULL,
+ &realpath_req,
+ options->preopens[i].real_path,
+ NULL);
+ if (r != 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ r = uv_fs_open(NULL, &open_req, realpath_req.ptr, 0, 0666, NULL);
+ if (r < 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ uv_fs_req_cleanup(&open_req);
+ goto exit;
+ }
+
+ err = uvwasi_fd_table_insert_preopen(&uvwasi->fds,
+ open_req.result,
+ options->preopens[i].mapped_path,
+ realpath_req.ptr);
+ uv_fs_req_cleanup(&realpath_req);
+ uv_fs_req_cleanup(&open_req);
+
+ if (err != UVWASI_ESUCCESS)
+ goto exit;
+ }
+
+ return UVWASI_ESUCCESS;
+
+exit:
+ uvwasi_destroy(uvwasi);
+ return err;
+}
+
+
+void uvwasi_destroy(uvwasi_t* uvwasi) {
+ if (uvwasi == NULL)
+ return;
+
+ uvwasi_fd_table_free(&uvwasi->fds);
+ free(uvwasi->argv_buf);
+ free(uvwasi->argv);
+ free(uvwasi->env_buf);
+ free(uvwasi->env);
+ uvwasi->argv_buf = NULL;
+ uvwasi->argv = NULL;
+ uvwasi->env_buf = NULL;
+ uvwasi->env = NULL;
+}
+
+
+uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi,
+ const uvwasi_fd_t fd,
+ uv_file new_host_fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ wrap->fd = new_host_fd;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf) {
+ size_t i;
+
+ if (uvwasi == NULL || argv == NULL || argv_buf == NULL)
+ return UVWASI_EINVAL;
+
+ for (i = 0; i < uvwasi->argc; ++i) {
+ argv[i] = argv_buf + (uvwasi->argv[i] - uvwasi->argv_buf);
+ }
+
+ memcpy(argv_buf, uvwasi->argv_buf, uvwasi->argv_buf_size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi,
+ size_t* argc,
+ size_t* argv_buf_size) {
+ if (uvwasi == NULL || argc == NULL || argv_buf_size == NULL)
+ return UVWASI_EINVAL;
+
+ *argc = uvwasi->argc;
+ *argv_buf_size = uvwasi->argv_buf_size;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t* resolution) {
+ if (uvwasi == NULL || resolution == NULL)
+ return UVWASI_EINVAL;
+
+ switch (clock_id) {
+ case UVWASI_CLOCK_MONOTONIC:
+ case UVWASI_CLOCK_REALTIME:
+ *resolution = 1; /* Nanosecond precision. */
+ return UVWASI_ESUCCESS;
+ case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
+ return uvwasi__clock_getres_process_cputime(resolution);
+ case UVWASI_CLOCK_THREAD_CPUTIME_ID:
+ return uvwasi__clock_getres_thread_cputime(resolution);
+ default:
+ return UVWASI_EINVAL;
+ }
+}
+
+
+uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t precision,
+ uvwasi_timestamp_t* time) {
+ if (uvwasi == NULL || time == NULL)
+ return UVWASI_EINVAL;
+
+ switch (clock_id) {
+ case UVWASI_CLOCK_MONOTONIC:
+ *time = uv_hrtime();
+ return UVWASI_ESUCCESS;
+ case UVWASI_CLOCK_REALTIME:
+ return uvwasi__clock_gettime_realtime(time);
+ case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
+ return uvwasi__clock_gettime_process_cputime(time);
+ case UVWASI_CLOCK_THREAD_CPUTIME_ID:
+ return uvwasi__clock_gettime_thread_cputime(time);
+ default:
+ return UVWASI_EINVAL;
+ }
+}
+
+
+uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi,
+ char** environment,
+ char* environ_buf) {
+ size_t i;
+
+ if (uvwasi == NULL || environment == NULL || environ_buf == NULL)
+ return UVWASI_EINVAL;
+
+ for (i = 0; i < uvwasi->envc; ++i) {
+ environment[i] = environ_buf + (uvwasi->env[i] - uvwasi->env_buf);
+ }
+
+ memcpy(environ_buf, uvwasi->env_buf, uvwasi->env_buf_size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi,
+ size_t* environ_count,
+ size_t* environ_buf_size) {
+ if (uvwasi == NULL || environ_count == NULL || environ_buf_size == NULL)
+ return UVWASI_EINVAL;
+
+ *environ_count = uvwasi->envc;
+ *environ_buf_size = uvwasi->env_buf_size;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len,
+ uvwasi_advice_t advice) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+#ifdef POSIX_FADV_NORMAL
+ int mapped_advice;
+ int r;
+#endif /* POSIX_FADV_NORMAL */
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ switch (advice) {
+ case UVWASI_ADVICE_DONTNEED:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_DONTNEED;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_NOREUSE:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_NOREUSE;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_NORMAL:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_NORMAL;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_RANDOM:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_RANDOM;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_SEQUENTIAL:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_SEQUENTIAL;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_WILLNEED:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_WILLNEED;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ default:
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_ADVISE, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+#ifdef POSIX_FADV_NORMAL
+ r = posix_fadvise(wrap->fd, offset, len, mapped_advice);
+ if (r != 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(r));
+#endif /* POSIX_FADV_NORMAL */
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len) {
+#if !defined(__POSIX__)
+ uv_fs_t req;
+ uint64_t st_size;
+#endif /* !__POSIX__ */
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_ALLOCATE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Try to use posix_fallocate(). If that's not an option, fall back to the
+ race condition prone combination of fstat() + ftruncate(). */
+#if defined(__POSIX__)
+ r = posix_fallocate(wrap->fd, offset, len);
+ if (r != 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(r));
+#else
+ r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
+ st_size = req.statbuf.st_size;
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ if (st_size < offset + len) {
+ r = uv_fs_ftruncate(NULL, &req, wrap->fd, offset + len, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+ }
+#endif /* __POSIX__ */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_close(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return uvwasi_fd_table_remove(&uvwasi->fds, fd);
+}
+
+
+uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_DATASYNC,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fdatasync(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdstat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+#ifndef _WIN32
+ int r;
+#endif
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ buf->fs_filetype = wrap->type;
+ buf->fs_rights_base = wrap->rights_base;
+ buf->fs_rights_inheriting = wrap->rights_inheriting;
+#ifdef _WIN32
+ buf->fs_flags = 0; /* TODO(cjihrig): Missing Windows support. */
+#else
+ r = fcntl(wrap->fd, F_GETFL);
+ if (r < 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ buf->fs_flags = r;
+#endif /* _WIN32 */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdflags_t flags) {
+#ifdef _WIN32
+ /* TODO(cjihrig): Missing Windows support. */
+ return UVWASI_ENOSYS;
+#else
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ int mapped_flags;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ mapped_flags = 0;
+
+ if ((flags & UVWASI_FDFLAG_APPEND) == UVWASI_FDFLAG_APPEND)
+ mapped_flags |= O_APPEND;
+
+ if ((flags & UVWASI_FDFLAG_DSYNC) == UVWASI_FDFLAG_DSYNC)
+#ifdef O_DSYNC
+ mapped_flags |= O_DSYNC;
+#else
+ mapped_flags |= O_SYNC;
+#endif /* O_DSYNC */
+
+ if ((flags & UVWASI_FDFLAG_NONBLOCK) == UVWASI_FDFLAG_NONBLOCK)
+ mapped_flags |= O_NONBLOCK;
+
+ if ((flags & UVWASI_FDFLAG_RSYNC) == UVWASI_FDFLAG_RSYNC)
+#ifdef O_RSYNC
+ mapped_flags |= O_RSYNC;
+#else
+ mapped_flags |= O_SYNC;
+#endif /* O_RSYNC */
+
+ if ((flags & UVWASI_FDFLAG_SYNC) == UVWASI_FDFLAG_SYNC)
+ mapped_flags |= O_SYNC;
+
+ r = fcntl(wrap->fd, F_SETFL, mapped_flags);
+ if (r < 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+
+ return UVWASI_ESUCCESS;
+#endif /* _WIN32 */
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_set_rights(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting
+ ) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Check for attempts to add new permissions. */
+ if ((fs_rights_base | wrap->rights_base) > wrap->rights_base)
+ return UVWASI_ENOTCAPABLE;
+ if ((fs_rights_inheriting | wrap->rights_inheriting) >
+ wrap->rights_inheriting) {
+ return UVWASI_ENOTCAPABLE;
+ }
+
+ wrap->rights_base = fs_rights_base;
+ wrap->rights_inheriting = fs_rights_inheriting;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filestat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_GET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ uvwasi__stat_to_filestat(&req.statbuf, buf);
+ uv_fs_req_cleanup(&req);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t st_size) {
+ /* TODO(cjihrig): uv_fs_ftruncate() takes an int64_t. st_size is uint64_t. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_ftruncate(NULL, &req, wrap->fd, st_size, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags) {
+ /* TODO(cjihrig): libuv does not currently support nanosecond precision. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ if (fst_flags & ~(UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW |
+ UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) {
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_SET_TIMES,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* TODO(cjihrig): st_atim and st_mtim should not be unconditionally passed. */
+ r = uv_fs_futime(NULL, &req, wrap->fd, st_atim, st_mtim, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nread) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvread;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nread == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_READ | UVWASI_RIGHT_FD_SEEK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_iovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
+ uvread = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nread = uvread;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_prestat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+ if (wrap->preopen != 1)
+ return UVWASI_EINVAL;
+
+ buf->pr_type = UVWASI_PREOPENTYPE_DIR;
+ buf->u.dir.pr_name_len = strlen(wrap->path) + 1;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ char* path,
+ size_t path_len) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ size_t size;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+ if (wrap->preopen != 1)
+ return UVWASI_EBADF;
+
+ size = strlen(wrap->path) + 1;
+ if (size > path_len)
+ return UVWASI_ENOBUFS;
+
+ memcpy(path, wrap->path, size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_pwrite(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nwritten) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvwritten;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_WRITE | UVWASI_RIGHT_FD_SEEK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_ciovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
+ uvwritten = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nwritten = uvwritten;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_read(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ size_t* nread) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvread;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nread == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_READ, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_iovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
+ uvread = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nread = uvread;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ void* buf,
+ size_t buf_len,
+ uvwasi_dircookie_t cookie,
+ size_t* bufused) {
+ /* TODO(cjihrig): Support Windows where seekdir() and telldir() are used. */
+ /* TODO(cjihrig): Avoid opening and closing the directory on each call. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_dirent_t dirent;
+ uv_dirent_t dirents[UVWASI__READDIR_NUM_ENTRIES];
+ uv_dir_t* dir;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t name_len;
+ size_t available;
+ size_t size_to_cp;
+ long tell;
+ int i;
+ int r;
+
+ if (uvwasi == NULL || buf == NULL || bufused == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_READDIR,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Open the directory. */
+ r = uv_fs_opendir(NULL, &req, wrap->real_path, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ /* Setup for reading the directory. */
+ dir = req.ptr;
+ dir->dirents = dirents;
+ dir->nentries = UVWASI__READDIR_NUM_ENTRIES;
+ uv_fs_req_cleanup(&req);
+
+#ifndef _WIN32
+ /* TODO(cjihrig): Need a Windows equivalent of this logic. */
+ /* Seek to the proper location in the directory. */
+ if (cookie != UVWASI_DIRCOOKIE_START)
+ seekdir(dir->dir, cookie);
+#endif
+
+ /* Read the directory entries into the provided buffer. */
+ err = UVWASI_ESUCCESS;
+ *bufused = 0;
+ while (0 != (r = uv_fs_readdir(NULL, &req, dir, NULL))) {
+ if (r < 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&req);
+ goto exit;
+ }
+
+ for (i = 0; i < r; i++) {
+ /* TODO(cjihrig): This should probably be serialized to the buffer
+ consistently across platforms. In other words, d_next should always
+ be 8 bytes, d_ino should always be 8 bytes, d_namlen should always be
+ 4 bytes, and d_type should always be 1 byte. */
+#ifndef _WIN32
+ tell = telldir(dir->dir);
+ if (tell < 0) {
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ uv_fs_req_cleanup(&req);
+ goto exit;
+ }
+#else
+ tell = 0; /* TODO(cjihrig): Need to support Windows. */
+#endif /* _WIN32 */
+
+ name_len = strlen(dirents[i].name);
+ dirent.d_next = (uvwasi_dircookie_t) tell;
+ /* TODO(cjihrig): Missing ino libuv (and Windows) support. fstat()? */
+ dirent.d_ino = 0;
+ dirent.d_namlen = name_len;
+
+ switch (dirents[i].type) {
+ case UV_DIRENT_FILE:
+ dirent.d_type = UVWASI_FILETYPE_REGULAR_FILE;
+ break;
+ case UV_DIRENT_DIR:
+ dirent.d_type = UVWASI_FILETYPE_DIRECTORY;
+ break;
+ case UV_DIRENT_SOCKET:
+ dirent.d_type = UVWASI_FILETYPE_SOCKET_STREAM;
+ break;
+ case UV_DIRENT_LINK:
+ dirent.d_type = UVWASI_FILETYPE_SYMBOLIC_LINK;
+ break;
+ case UV_DIRENT_CHAR:
+ dirent.d_type = UVWASI_FILETYPE_CHARACTER_DEVICE;
+ break;
+ case UV_DIRENT_BLOCK:
+ dirent.d_type = UVWASI_FILETYPE_BLOCK_DEVICE;
+ break;
+ case UV_DIRENT_FIFO:
+ case UV_DIRENT_UNKNOWN:
+ default:
+ dirent.d_type = UVWASI_FILETYPE_UNKNOWN;
+ break;
+ }
+
+ /* Write dirent to the buffer. */
+ available = buf_len - *bufused;
+ size_to_cp = sizeof(dirent) > available ? available : sizeof(dirent);
+ memcpy((char*)buf + *bufused, &dirent, size_to_cp);
+ *bufused += size_to_cp;
+ /* Write the entry name to the buffer. */
+ available = buf_len - *bufused;
+ size_to_cp = name_len > available ? available : name_len;
+ memcpy((char*)buf + *bufused, &dirents[i].name, size_to_cp);
+ *bufused += size_to_cp;
+ }
+
+ uv_fs_req_cleanup(&req);
+
+ if (*bufused >= buf_len)
+ break;
+ }
+
+exit:
+ /* Close the directory. */
+ r = uv_fs_closedir(NULL, &req, dir, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return err;
+}
+
+
+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;
+
+ 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)
+ return err;
+
+ r = uv_fs_close(NULL, &req, to_wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ memcpy(to_wrap, from_wrap, sizeof(*to_wrap));
+ to_wrap->id = to;
+
+ return uvwasi_fd_table_remove(&uvwasi->fds, from);
+}
+
+
+uvwasi_errno_t uvwasi_fd_seek(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filedelta_t offset,
+ uvwasi_whence_t whence,
+ uvwasi_filesize_t* newoffset) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || newoffset == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_SEEK, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return uvwasi__lseek(wrap->fd, offset, whence, newoffset);
+}
+
+
+uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_SYNC,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fsync(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t* offset) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || offset == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_TELL, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return uvwasi__lseek(wrap->fd, 0, UVWASI_WHENCE_CUR, offset);
+}
+
+
+uvwasi_errno_t uvwasi_fd_write(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ size_t* nwritten) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvwritten;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_WRITE, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_ciovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
+ uvwritten = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nwritten = uvwritten;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_CREATE_DIRECTORY,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_mkdir(NULL, &req, resolved_path, 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_filestat_t* buf) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_FILESTAT_GET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_stat(NULL, &req, resolved_path, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ uvwasi__stat_to_filestat(&req.statbuf, buf);
+ uv_fs_req_cleanup(&req);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags) {
+ /* TODO(cjihrig): libuv does not currently support nanosecond precision. */
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ if (fst_flags & ~(UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW |
+ UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) {
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* TODO(cjihrig): st_atim and st_mtim should not be unconditionally passed. */
+ r = uv_fs_utime(NULL, &req, resolved_path, st_atim, st_mtim, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ uvwasi_lookupflags_t old_flags,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_old_path[PATH_MAX_BYTES];
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* old_wrap;
+ struct uvwasi_fd_wrap_t* new_wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ 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);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(old_wrap,
+ old_path,
+ old_path_len,
+ resolved_old_path,
+ old_flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(new_wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_link(NULL, &req, resolved_old_path, resolved_new_path, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
+ uvwasi_fd_t dirfd,
+ uvwasi_lookupflags_t dirflags,
+ const char* path,
+ size_t path_len,
+ uvwasi_oflags_t o_flags,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting,
+ uvwasi_fdflags_t fs_flags,
+ uvwasi_fd_t* fd) {
+ char resolved_path[PATH_MAX_BYTES];
+ uvwasi_rights_t needed_inheriting;
+ uvwasi_rights_t needed_base;
+ struct uvwasi_fd_wrap_t* dirfd_wrap;
+ struct uvwasi_fd_wrap_t wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int flags;
+ int read;
+ int write;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || fd == NULL)
+ return UVWASI_EINVAL;
+
+ read = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_READ |
+ UVWASI_RIGHT_FD_READDIR));
+ write = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_DATASYNC |
+ UVWASI_RIGHT_FD_WRITE |
+ UVWASI_RIGHT_FD_ALLOCATE |
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE));
+ flags = write ? read ? UV_FS_O_RDWR : UV_FS_O_WRONLY : UV_FS_O_RDONLY;
+ needed_base = UVWASI_RIGHT_PATH_OPEN;
+ needed_inheriting = fs_rights_base | fs_rights_inheriting;
+
+ if ((o_flags & UVWASI_O_CREAT) != 0) {
+ flags |= UV_FS_O_CREAT;
+ needed_base |= UVWASI_RIGHT_PATH_CREATE_FILE;
+ }
+ if ((o_flags & UVWASI_O_DIRECTORY) != 0)
+ flags |= UV_FS_O_DIRECTORY;
+ if ((o_flags & UVWASI_O_EXCL) != 0)
+ flags |= UV_FS_O_EXCL;
+ if ((o_flags & UVWASI_O_TRUNC) != 0) {
+ flags |= UV_FS_O_TRUNC;
+ needed_base |= UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE;
+ }
+
+ if ((fs_flags & UVWASI_FDFLAG_APPEND) != 0)
+ flags |= UV_FS_O_APPEND;
+ if ((fs_flags & UVWASI_FDFLAG_DSYNC) != 0) {
+ flags |= UV_FS_O_DSYNC;
+ needed_inheriting |= UVWASI_RIGHT_FD_DATASYNC;
+ }
+ if ((fs_flags & UVWASI_FDFLAG_NONBLOCK) != 0)
+ flags |= UV_FS_O_NONBLOCK;
+ if ((fs_flags & UVWASI_FDFLAG_RSYNC) != 0) {
+#ifdef O_RSYNC
+ flags |= O_RSYNC; /* libuv has no UV_FS_O_RSYNC. */
+#else
+ flags |= UV_FS_O_SYNC;
+#endif
+ needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
+ }
+ if ((fs_flags & UVWASI_FDFLAG_SYNC) != 0) {
+ flags |= UV_FS_O_SYNC;
+ needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
+ }
+ if (write && (flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC)) == 0)
+ needed_inheriting |= UVWASI_RIGHT_FD_SEEK;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ dirfd,
+ &dirfd_wrap,
+ needed_base,
+ needed_inheriting);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(dirfd_wrap,
+ path,
+ path_len,
+ resolved_path,
+ dirflags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_open(NULL, &req, resolved_path, flags, 0666, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ err = uvwasi_fd_table_insert_fd(&uvwasi->fds,
+ r,
+ flags,
+ resolved_path,
+ fs_rights_base,
+ fs_rights_inheriting,
+ &wrap);
+ 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) {
+ uvwasi_fd_table_remove(&uvwasi->fds, wrap.id);
+ err = UVWASI_ENOTDIR;
+ goto close_file_and_error_exit;
+ }
+
+ *fd = wrap.id;
+ return UVWASI_ESUCCESS;
+
+close_file_and_error_exit:
+ uv_fs_close(NULL, &req, r, NULL);
+ uv_fs_req_cleanup(&req);
+ return err;
+}
+
+
+uvwasi_errno_t uvwasi_path_readlink(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len,
+ char* buf,
+ size_t buf_len,
+ size_t* bufused) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ size_t len;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || buf == NULL || bufused == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_READLINK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_readlink(NULL, &req, resolved_path, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ len = strnlen(req.ptr, buf_len);
+ if (len >= buf_len) {
+ uv_fs_req_cleanup(&req);
+ return UVWASI_ENOBUFS;
+ }
+
+ memcpy(buf, req.ptr, len);
+ buf[len] = '\0';
+ *bufused = len + 1;
+ uv_fs_req_cleanup(&req);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_REMOVE_DIRECTORY,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_rmdir(NULL, &req, resolved_path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_old_path[PATH_MAX_BYTES];
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* old_wrap;
+ struct uvwasi_fd_wrap_t* new_wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ 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);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(old_wrap,
+ old_path,
+ old_path_len,
+ resolved_old_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(new_wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_rename(NULL, &req, resolved_old_path, resolved_new_path, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_SYMLINK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Windows support may require setting the flags option. */
+ r = uv_fs_symlink(NULL, &req, old_path, resolved_new_path, 0, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_UNLINK_FILE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_unlink(NULL, &req, resolved_path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi,
+ const uvwasi_subscription_t* in,
+ uvwasi_event_t* out,
+ size_t nsubscriptions,
+ size_t* nevents) {
+ /* TODO(cjihrig): Implement this. */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval) {
+ exit(rval);
+ return UVWASI_ESUCCESS; /* This doesn't happen. */
+}
+
+
+uvwasi_errno_t uvwasi_proc_raise(uvwasi_t* uvwasi, uvwasi_signal_t sig) {
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ r = uvwasi__translate_to_uv_signal(sig);
+ if (r == -1)
+ return UVWASI_ENOSYS;
+
+ r = uv_kill(uv_os_getpid(), r);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, void* buf, size_t buf_len) {
+ int r;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ r = uv_random(NULL, NULL, buf, buf_len, 0, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi) {
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+#ifndef _WIN32
+ if (0 != sched_yield())
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#else
+ SwitchToThread();
+#endif /* _WIN32 */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_sock_recv(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_iovec_t* ri_data,
+ size_t ri_data_len,
+ uvwasi_riflags_t ri_flags,
+ size_t* ro_datalen,
+ uvwasi_roflags_t* ro_flags) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_sock_send(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_ciovec_t* si_data,
+ size_t si_data_len,
+ uvwasi_siflags_t si_flags,
+ size_t* so_datalen) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ uvwasi_sdflags_t how) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}