From 9ec53cf5c157931f8bdf31a0af7be13023f093d3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 4 Sep 2019 17:56:51 -0400 Subject: [PATCH] wasi: introduce initial WASI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gus Caplan Co-authored-by: Daniel Bevenius Co-authored-by: Jiawen Geng Co-authored-by: Tobias Nießen Co-authored-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/30258 Refs: https://github.com/nodejs/node/pull/27850 Reviewed-By: Anna Henningsen Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Guy Bedford Reviewed-By: Richard Lau Reviewed-By: Wyatt Preul Reviewed-By: Matteo Collina Reviewed-By: Tobias Nießen Reviewed-By: Jiawen Geng Reviewed-By: Chengzhong Wu Reviewed-By: Daniel Bevenius --- LICENSE | 25 + deps/uvwasi/LICENSE | 21 + deps/uvwasi/include/clocks.h | 13 + deps/uvwasi/include/fd_table.h | 60 + deps/uvwasi/include/uv_mapping.h | 15 + deps/uvwasi/include/uvwasi.h | 252 + deps/uvwasi/include/wasi_types.h | 323 + deps/uvwasi/src/clocks.c | 194 + deps/uvwasi/src/fd_table.c | 422 ++ deps/uvwasi/src/uv_mapping.c | 243 + deps/uvwasi/src/uvwasi.c | 1918 ++++++ deps/uvwasi/uvwasi.gyp | 25 + doc/api/cli.md | 8 + doc/api/errors.md | 5 + doc/api/index.md | 1 + doc/api/wasi.md | 90 + doc/node.1 | 3 + lib/internal/bootstrap/loaders.js | 3 + lib/internal/errors.js | 1 + lib/internal/modules/cjs/helpers.js | 5 + lib/wasi.js | 105 + node.gyp | 19 +- src/env-inl.h | 15 + src/env.h | 8 +- src/node_binding.cc | 1 + src/node_config.cc | 3 + src/node_options.cc | 4 + src/node_options.h | 1 + src/node_wasi.cc | 1802 ++++++ src/node_wasi.h | 103 + test/fixtures/outside.txt | 2 + test/fixtures/wasi/input.txt | 1 + test/fixtures/wasi/notadir | 0 test/fixtures/wasi/simple-wasi.wasm | Bin 0 -> 15873 bytes test/fixtures/wasi/simple-wasi.wat | 6533 ++++++++++++++++++++ test/fixtures/wasi/subdir/input_link.txt | 1 + test/fixtures/wasi/subdir/loop1 | 1 + test/fixtures/wasi/subdir/loop2 | 1 + test/fixtures/wasi/subdir/outside.txt | 1 + test/wasi/Makefile | 12 + test/wasi/README.md | 8 + test/wasi/c/cant_dotdot.c | 11 + test/wasi/c/clock_getres.c | 17 + test/wasi/c/exitcode.c | 3 + test/wasi/c/fd_prestat_get_refresh.c | 8 + test/wasi/c/follow_symlink.c | 14 + test/wasi/c/getentropy.c | 18 + test/wasi/c/getrusage.c | 34 + test/wasi/c/gettimeofday.c | 35 + test/wasi/c/notdir.c | 11 + test/wasi/c/poll.c | 31 + test/wasi/c/preopen_populates.c | 3 + test/wasi/c/read_file.c | 14 + test/wasi/c/read_file_twice.c | 16 + test/wasi/c/stat.c | 53 + test/wasi/c/stdin.c | 13 + test/wasi/c/symlink_escape.c | 9 + test/wasi/c/symlink_loop.c | 9 + test/wasi/c/write_file.c | 15 + test/wasi/test-wasi-binding.js | 19 + test/wasi/test-wasi-symlinks.js | 78 + test/wasi/test-wasi.js | 81 + test/wasi/testcfg.py | 6 + test/wasi/wasi.status | 7 + test/wasi/wasm/cant_dotdot.wasm | Bin 0 -> 33007 bytes test/wasi/wasm/clock_getres.wasm | Bin 0 -> 30146 bytes test/wasi/wasm/exitcode.wasm | Bin 0 -> 12694 bytes test/wasi/wasm/fd_prestat_get_refresh.wasm | Bin 0 -> 12855 bytes test/wasi/wasm/follow_symlink.wasm | Bin 0 -> 34948 bytes test/wasi/wasm/getentropy.wasm | Bin 0 -> 29943 bytes test/wasi/wasm/getrusage.wasm | Bin 0 -> 30602 bytes test/wasi/wasm/gettimeofday.wasm | Bin 0 -> 30428 bytes test/wasi/wasm/notdir.wasm | Bin 0 -> 31267 bytes test/wasi/wasm/poll.wasm | Bin 0 -> 34096 bytes test/wasi/wasm/preopen_populates.wasm | Bin 0 -> 12689 bytes test/wasi/wasm/read_file.wasm | Bin 0 -> 34932 bytes test/wasi/wasm/read_file_twice.wasm | Bin 0 -> 35018 bytes test/wasi/wasm/stat.wasm | Bin 0 -> 34507 bytes test/wasi/wasm/stdin.wasm | Bin 0 -> 18390 bytes test/wasi/wasm/symlink_escape.wasm | Bin 0 -> 33026 bytes test/wasi/wasm/symlink_loop.wasm | Bin 0 -> 33009 bytes test/wasi/wasm/write_file.wasm | Bin 0 -> 33357 bytes tools/doc/type-parser.js | 2 +- tools/license-builder.sh | 2 + 84 files changed, 12753 insertions(+), 4 deletions(-) create mode 100644 deps/uvwasi/LICENSE create mode 100644 deps/uvwasi/include/clocks.h create mode 100644 deps/uvwasi/include/fd_table.h create mode 100644 deps/uvwasi/include/uv_mapping.h create mode 100644 deps/uvwasi/include/uvwasi.h create mode 100644 deps/uvwasi/include/wasi_types.h create mode 100644 deps/uvwasi/src/clocks.c create mode 100644 deps/uvwasi/src/fd_table.c create mode 100644 deps/uvwasi/src/uv_mapping.c create mode 100644 deps/uvwasi/src/uvwasi.c create mode 100644 deps/uvwasi/uvwasi.gyp create mode 100644 doc/api/wasi.md create mode 100644 lib/wasi.js create mode 100644 src/node_wasi.cc create mode 100644 src/node_wasi.h create mode 100644 test/fixtures/outside.txt create mode 100644 test/fixtures/wasi/input.txt create mode 100644 test/fixtures/wasi/notadir create mode 100755 test/fixtures/wasi/simple-wasi.wasm create mode 100644 test/fixtures/wasi/simple-wasi.wat create mode 120000 test/fixtures/wasi/subdir/input_link.txt create mode 120000 test/fixtures/wasi/subdir/loop1 create mode 120000 test/fixtures/wasi/subdir/loop2 create mode 120000 test/fixtures/wasi/subdir/outside.txt create mode 100644 test/wasi/Makefile create mode 100644 test/wasi/README.md create mode 100644 test/wasi/c/cant_dotdot.c create mode 100644 test/wasi/c/clock_getres.c create mode 100644 test/wasi/c/exitcode.c create mode 100644 test/wasi/c/fd_prestat_get_refresh.c create mode 100644 test/wasi/c/follow_symlink.c create mode 100644 test/wasi/c/getentropy.c create mode 100644 test/wasi/c/getrusage.c create mode 100644 test/wasi/c/gettimeofday.c create mode 100644 test/wasi/c/notdir.c create mode 100644 test/wasi/c/poll.c create mode 100644 test/wasi/c/preopen_populates.c create mode 100644 test/wasi/c/read_file.c create mode 100644 test/wasi/c/read_file_twice.c create mode 100644 test/wasi/c/stat.c create mode 100644 test/wasi/c/stdin.c create mode 100644 test/wasi/c/symlink_escape.c create mode 100644 test/wasi/c/symlink_loop.c create mode 100644 test/wasi/c/write_file.c create mode 100644 test/wasi/test-wasi-binding.js create mode 100644 test/wasi/test-wasi-symlinks.js create mode 100644 test/wasi/test-wasi.js create mode 100644 test/wasi/testcfg.py create mode 100644 test/wasi/wasi.status create mode 100755 test/wasi/wasm/cant_dotdot.wasm create mode 100755 test/wasi/wasm/clock_getres.wasm create mode 100755 test/wasi/wasm/exitcode.wasm create mode 100755 test/wasi/wasm/fd_prestat_get_refresh.wasm create mode 100755 test/wasi/wasm/follow_symlink.wasm create mode 100755 test/wasi/wasm/getentropy.wasm create mode 100755 test/wasi/wasm/getrusage.wasm create mode 100755 test/wasi/wasm/gettimeofday.wasm create mode 100755 test/wasi/wasm/notdir.wasm create mode 100755 test/wasi/wasm/poll.wasm create mode 100755 test/wasi/wasm/preopen_populates.wasm create mode 100755 test/wasi/wasm/read_file.wasm create mode 100755 test/wasi/wasm/read_file_twice.wasm create mode 100755 test/wasi/wasm/stat.wasm create mode 100755 test/wasi/wasm/stdin.wasm create mode 100755 test/wasi/wasm/symlink_escape.wasm create mode 100755 test/wasi/wasm/symlink_loop.wasm create mode 100755 test/wasi/wasm/write_file.wasm diff --git a/LICENSE b/LICENSE index d09611738be467..9d65fc76cb949e 100644 --- a/LICENSE +++ b/LICENSE @@ -1503,3 +1503,28 @@ The externally maintained libraries used by Node.js are: ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ + +- uvwasi, located at deps/uvwasi, is licensed as follows: + """ + MIT License + + Copyright (c) 2019 Colin Ihrig and Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ diff --git a/deps/uvwasi/LICENSE b/deps/uvwasi/LICENSE new file mode 100644 index 00000000000000..dfb8546af52b03 --- /dev/null +++ b/deps/uvwasi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Colin Ihrig and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/deps/uvwasi/include/clocks.h b/deps/uvwasi/include/clocks.h new file mode 100644 index 00000000000000..7437d03df6bfa7 --- /dev/null +++ b/deps/uvwasi/include/clocks.h @@ -0,0 +1,13 @@ +#ifndef __UVWASI_CLOCKS_H__ +#define __UVWASI_CLOCKS_H__ + +#include "wasi_types.h" + +uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time); +uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time); +uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time); + +uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time); +uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time); + +#endif /* __UVWASI_CLOCKS_H__ */ diff --git a/deps/uvwasi/include/fd_table.h b/deps/uvwasi/include/fd_table.h new file mode 100644 index 00000000000000..ef87a3ff8f93c5 --- /dev/null +++ b/deps/uvwasi/include/fd_table.h @@ -0,0 +1,60 @@ +#ifndef __UVWASI_FD_TABLE_H__ +#define __UVWASI_FD_TABLE_H__ + +#include +#include "uv.h" +#include "wasi_types.h" +#include "uv_mapping.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. */ +#ifdef _WIN32 +/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */ +# define PATH_MAX_BYTES (MAX_PATH * 4) +#else +# include +# define PATH_MAX_BYTES (PATH_MAX) +#endif + + +struct uvwasi_fd_wrap_t { + uvwasi_fd_t id; + uv_file fd; + char path[PATH_MAX_BYTES]; + char real_path[PATH_MAX_BYTES]; + uvwasi_filetype_t type; + uvwasi_rights_t rights_base; + uvwasi_rights_t rights_inheriting; + int preopen; + int valid; +}; + +struct uvwasi_fd_table_t { + struct uvwasi_fd_wrap_t* fds; + uint32_t size; + uint32_t used; +}; + +uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_fd_table_t* table, + uint32_t init_size); +void uvwasi_fd_table_free(struct uvwasi_fd_table_t* table); +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_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); +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_errno_t uvwasi_fd_table_remove(struct uvwasi_fd_table_t* table, + const uvwasi_fd_t id); + +#endif /* __UVWASI_FD_TABLE_H__ */ diff --git a/deps/uvwasi/include/uv_mapping.h b/deps/uvwasi/include/uv_mapping.h new file mode 100644 index 00000000000000..d835ca507a4856 --- /dev/null +++ b/deps/uvwasi/include/uv_mapping.h @@ -0,0 +1,15 @@ +#ifndef __UVWASI_UV_MAPPING_H__ +#define __UVWASI_UV_MAPPING_H__ + +#include "uv.h" +#include "wasi_types.h" + +#define NANOS_PER_SEC 1000000000 + +uvwasi_errno_t uvwasi__translate_uv_error(int err); +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); + +#endif /* __UVWASI_UV_MAPPING_H__ */ diff --git a/deps/uvwasi/include/uvwasi.h b/deps/uvwasi/include/uvwasi.h new file mode 100644 index 00000000000000..a7695734ac2ac6 --- /dev/null +++ b/deps/uvwasi/include/uvwasi.h @@ -0,0 +1,252 @@ +#ifndef __UVWASI_H__ +#define __UVWASI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wasi_types.h" +#include "uv_mapping.h" +#include "fd_table.h" + +#define UVWASI_VERSION_MAJOR 0 +#define UVWASI_VERSION_MINOR 0 +#define UVWASI_VERSION_PATCH 1 +#define UVWASI_VERSION_HEX ((UVWASI_VERSION_MAJOR << 16) | \ + (UVWASI_VERSION_MINOR << 8) | \ + (UVWASI_VERSION_PATCH)) +#define UVWASI_STRINGIFY(v) UVWASI_STRINGIFY_HELPER(v) +#define UVWASI_STRINGIFY_HELPER(v) #v +#define UVWASI_VERSION_STRING UVWASI_STRINGIFY(UVWASI_VERSION_MAJOR) "." \ + UVWASI_STRINGIFY(UVWASI_VERSION_MINOR) "." \ + UVWASI_STRINGIFY(UVWASI_VERSION_PATCH) + + +typedef struct uvwasi_s { + struct uvwasi_fd_table_t fds; + size_t argc; + char** argv; + char* argv_buf; + size_t argv_buf_size; + size_t envc; + char** env; + char* env_buf; + size_t env_buf_size; +} uvwasi_t; + +typedef struct uvwasi_preopen_s { + char* mapped_path; + char* real_path; +} uvwasi_preopen_t; + +typedef struct uvwasi_options_s { + size_t fd_table_size; + size_t preopenc; + uvwasi_preopen_t* preopens; + size_t argc; + char** argv; + char** envp; +} uvwasi_options_t; + + +// Embedder API. +uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, uvwasi_options_t* options); +void uvwasi_destroy(uvwasi_t* uvwasi); +uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi, + const uvwasi_fd_t fd, + uv_file new_host_fd); + + +// WASI system call API. +uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf); +uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi, + size_t* argc, + size_t* argv_buf_size); +uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi, + uvwasi_clockid_t clock_id, + uvwasi_timestamp_t* resolution); +uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi, + uvwasi_clockid_t clock_id, + uvwasi_timestamp_t precision, + uvwasi_timestamp_t* time); +uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi, + char** environment, + char* environ_buf); +uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi, + size_t* environ_count, + size_t* environ_buf_size); +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); +uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_filesize_t offset, + uvwasi_filesize_t len); +uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd); +uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd); +uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_fdstat_t* buf); +uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_fdflags_t flags); +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 + ); +uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_filestat_t* buf); +uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_filesize_t st_size); +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); +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); +uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_prestat_t* buf); +uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + char* path, + size_t path_len); +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); +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); +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); +uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi, + uvwasi_fd_t from, + uvwasi_fd_t to); +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); +uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd); +uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + uvwasi_filesize_t* 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); +uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + const char* path, + size_t path_len); +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); +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); +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); +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); +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); +uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + const char* path, + size_t path_len); +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); +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); +uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi, + uvwasi_fd_t fd, + const char* path, + size_t path_len); +uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi, + const uvwasi_subscription_t* in, + uvwasi_event_t* out, + size_t nsubscriptions, + size_t* nevents); +uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval); +uvwasi_errno_t uvwasi_proc_raise(uvwasi_t* uvwasi, uvwasi_signal_t sig); +uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, void* buf, size_t buf_len); +uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi); +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); +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); +uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi, + uvwasi_fd_t sock, + uvwasi_sdflags_t how); + +#ifdef __cplusplus +} +#endif + +#endif /* __UVWASI_H__ */ diff --git a/deps/uvwasi/include/wasi_types.h b/deps/uvwasi/include/wasi_types.h new file mode 100644 index 00000000000000..34b5291c577627 --- /dev/null +++ b/deps/uvwasi/include/wasi_types.h @@ -0,0 +1,323 @@ +#ifndef __UVWASI_WASI_TYPES_H__ +#define __UVWASI_WASI_TYPES_H__ + +#include +#include + +/* API: https://github.com/WebAssembly/WASI/blob/master/phases/unstable/docs/wasi_unstable_preview0.md */ + +typedef uint8_t uvwasi_advice_t; +#define UVWASI_ADVICE_NORMAL 0 +#define UVWASI_ADVICE_SEQUENTIAL 1 +#define UVWASI_ADVICE_RANDOM 2 +#define UVWASI_ADVICE_WILLNEED 3 +#define UVWASI_ADVICE_DONTNEED 4 +#define UVWASI_ADVICE_NOREUSE 5 + +typedef struct uvwasi_ciovec_s { + const void* buf; + size_t buf_len; +} uvwasi_ciovec_t; + +typedef uint32_t uvwasi_clockid_t; +#define UVWASI_CLOCK_REALTIME 0 +#define UVWASI_CLOCK_MONOTONIC 1 +#define UVWASI_CLOCK_PROCESS_CPUTIME_ID 2 +#define UVWASI_CLOCK_THREAD_CPUTIME_ID 3 + +typedef uint64_t uvwasi_device_t; + +typedef uint64_t uvwasi_dircookie_t; +#define UVWASI_DIRCOOKIE_START 0 + +typedef uint16_t uvwasi_errno_t; +#define UVWASI_ESUCCESS 0 +#define UVWASI_E2BIG 1 +#define UVWASI_EACCES 2 +#define UVWASI_EADDRINUSE 3 +#define UVWASI_EADDRNOTAVAIL 4 +#define UVWASI_EAFNOSUPPORT 5 +#define UVWASI_EAGAIN 6 +#define UVWASI_EALREADY 7 +#define UVWASI_EBADF 8 +#define UVWASI_EBADMSG 9 +#define UVWASI_EBUSY 10 +#define UVWASI_ECANCELED 11 +#define UVWASI_ECHILD 12 +#define UVWASI_ECONNABORTED 13 +#define UVWASI_ECONNREFUSED 14 +#define UVWASI_ECONNRESET 15 +#define UVWASI_EDEADLK 16 +#define UVWASI_EDESTADDRREQ 17 +#define UVWASI_EDOM 18 +#define UVWASI_EDQUOT 19 +#define UVWASI_EEXIST 20 +#define UVWASI_EFAULT 21 +#define UVWASI_EFBIG 22 +#define UVWASI_EHOSTUNREACH 23 +#define UVWASI_EIDRM 24 +#define UVWASI_EILSEQ 25 +#define UVWASI_EINPROGRESS 26 +#define UVWASI_EINTR 27 +#define UVWASI_EINVAL 28 +#define UVWASI_EIO 29 +#define UVWASI_EISCONN 30 +#define UVWASI_EISDIR 31 +#define UVWASI_ELOOP 32 +#define UVWASI_EMFILE 33 +#define UVWASI_EMLINK 34 +#define UVWASI_EMSGSIZE 35 +#define UVWASI_EMULTIHOP 36 +#define UVWASI_ENAMETOOLONG 37 +#define UVWASI_ENETDOWN 38 +#define UVWASI_ENETRESET 39 +#define UVWASI_ENETUNREACH 40 +#define UVWASI_ENFILE 41 +#define UVWASI_ENOBUFS 42 +#define UVWASI_ENODEV 43 +#define UVWASI_ENOENT 44 +#define UVWASI_ENOEXEC 45 +#define UVWASI_ENOLCK 46 +#define UVWASI_ENOLINK 47 +#define UVWASI_ENOMEM 48 +#define UVWASI_ENOMSG 49 +#define UVWASI_ENOPROTOOPT 50 +#define UVWASI_ENOSPC 51 +#define UVWASI_ENOSYS 52 +#define UVWASI_ENOTCONN 53 +#define UVWASI_ENOTDIR 54 +#define UVWASI_ENOTEMPTY 55 +#define UVWASI_ENOTRECOVERABLE 56 +#define UVWASI_ENOTSOCK 57 +#define UVWASI_ENOTSUP 58 +#define UVWASI_ENOTTY 59 +#define UVWASI_ENXIO 60 +#define UVWASI_EOVERFLOW 61 +#define UVWASI_EOWNERDEAD 62 +#define UVWASI_EPERM 63 +#define UVWASI_EPIPE 64 +#define UVWASI_EPROTO 65 +#define UVWASI_EPROTONOSUPPORT 66 +#define UVWASI_EPROTOTYPE 67 +#define UVWASI_ERANGE 68 +#define UVWASI_EROFS 69 +#define UVWASI_ESPIPE 70 +#define UVWASI_ESRCH 71 +#define UVWASI_ESTALE 72 +#define UVWASI_ETIMEDOUT 73 +#define UVWASI_ETXTBSY 74 +#define UVWASI_EXDEV 75 +#define UVWASI_ENOTCAPABLE 76 + +typedef uint16_t uvwasi_eventrwflags_t; /* Bitfield */ +#define UVWASI_EVENT_FD_READWRITE_HANGUP (1 << 0) + +typedef uint8_t uvwasi_eventtype_t; +#define UVWASI_EVENTTYPE_CLOCK 0 +#define UVWASI_EVENTTYPE_FD_READ 1 +#define UVWASI_EVENTTYPE_FD_WRITE 2 + +typedef uint32_t uvwasi_exitcode_t; + +typedef uint32_t uvwasi_fd_t; + +typedef uint16_t uvwasi_fdflags_t; /* Bitfield */ +#define UVWASI_FDFLAG_APPEND (1 << 0) +#define UVWASI_FDFLAG_DSYNC (1 << 1) +#define UVWASI_FDFLAG_NONBLOCK (1 << 2) +#define UVWASI_FDFLAG_RSYNC (1 << 3) +#define UVWASI_FDFLAG_SYNC (1 << 4) + +typedef int64_t uvwasi_filedelta_t; + +typedef uint64_t uvwasi_filesize_t; + +typedef uint8_t uvwasi_filetype_t; +#define UVWASI_FILETYPE_UNKNOWN 0 +#define UVWASI_FILETYPE_BLOCK_DEVICE 1 +#define UVWASI_FILETYPE_CHARACTER_DEVICE 2 +#define UVWASI_FILETYPE_DIRECTORY 3 +#define UVWASI_FILETYPE_REGULAR_FILE 4 +#define UVWASI_FILETYPE_SOCKET_DGRAM 5 +#define UVWASI_FILETYPE_SOCKET_STREAM 6 +#define UVWASI_FILETYPE_SYMBOLIC_LINK 7 + +typedef uint16_t uvwasi_fstflags_t; /* Bitfield */ +#define UVWASI_FILESTAT_SET_ATIM (1 << 0) +#define UVWASI_FILESTAT_SET_ATIM_NOW (1 << 1) +#define UVWASI_FILESTAT_SET_MTIM (1 << 2) +#define UVWASI_FILESTAT_SET_MTIM_NOW (1 << 3) + +typedef uint64_t uvwasi_inode_t; + +typedef struct uvwasi_iovec_s { + void* buf; + size_t buf_len; +} uvwasi_iovec_t; + +typedef uint32_t uvwasi_linkcount_t; + +typedef uint32_t uvwasi_lookupflags_t; /* Bitfield */ +#define UVWASI_LOOKUP_SYMLINK_FOLLOW (1 << 0) + +typedef uint16_t uvwasi_oflags_t; /* Bitfield */ +#define UVWASI_O_CREAT (1 << 0) +#define UVWASI_O_DIRECTORY (1 << 1) +#define UVWASI_O_EXCL (1 << 2) +#define UVWASI_O_TRUNC (1 << 3) + +typedef uint8_t uvwasi_preopentype_t; +#define UVWASI_PREOPENTYPE_DIR 0 + +typedef struct uvwasi_prestat_s { + uvwasi_preopentype_t pr_type; + union uvwasi_prestat_u { + struct uvwasi_prestat_dir_t { + size_t pr_name_len; + } dir; + } u; +} uvwasi_prestat_t; + +typedef uint16_t uvwasi_riflags_t; /* Bitfield */ +#define UVWASI_SOCK_RECV_PEEK (1 << 0) +#define UVWASI_SOCK_RECV_WAITALL (1 << 1) + +typedef uint64_t uvwasi_rights_t; /* Bitfield */ +#define UVWASI_RIGHT_FD_DATASYNC (1 << 0) +#define UVWASI_RIGHT_FD_READ (1 << 1) +#define UVWASI_RIGHT_FD_SEEK (1 << 2) +#define UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS (1 << 3) +#define UVWASI_RIGHT_FD_SYNC (1 << 4) +#define UVWASI_RIGHT_FD_TELL (1 << 5) +#define UVWASI_RIGHT_FD_WRITE (1 << 6) +#define UVWASI_RIGHT_FD_ADVISE (1 << 7) +#define UVWASI_RIGHT_FD_ALLOCATE (1 << 8) +#define UVWASI_RIGHT_PATH_CREATE_DIRECTORY (1 << 9) +#define UVWASI_RIGHT_PATH_CREATE_FILE (1 << 10) +#define UVWASI_RIGHT_PATH_LINK_SOURCE (1 << 11) +#define UVWASI_RIGHT_PATH_LINK_TARGET (1 << 12) +#define UVWASI_RIGHT_PATH_OPEN (1 << 13) +#define UVWASI_RIGHT_FD_READDIR (1 << 14) +#define UVWASI_RIGHT_PATH_READLINK (1 << 15) +#define UVWASI_RIGHT_PATH_RENAME_SOURCE (1 << 16) +#define UVWASI_RIGHT_PATH_RENAME_TARGET (1 << 17) +#define UVWASI_RIGHT_PATH_FILESTAT_GET (1 << 18) +#define UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE (1 << 19) +#define UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES (1 << 20) +#define UVWASI_RIGHT_FD_FILESTAT_GET (1 << 21) +#define UVWASI_RIGHT_FD_FILESTAT_SET_SIZE (1 << 22) +#define UVWASI_RIGHT_FD_FILESTAT_SET_TIMES (1 << 23) +#define UVWASI_RIGHT_PATH_SYMLINK (1 << 24) +#define UVWASI_RIGHT_PATH_REMOVE_DIRECTORY (1 << 25) +#define UVWASI_RIGHT_PATH_UNLINK_FILE (1 << 26) +#define UVWASI_RIGHT_POLL_FD_READWRITE (1 << 27) +#define UVWASI_RIGHT_SOCK_SHUTDOWN (1 << 28) + +typedef uint16_t uvwasi_roflags_t; /* Bitfield */ +#define UVWASI_SOCK_RECV_DATA_TRUNCATED (1 << 0) + +typedef uint8_t uvwasi_sdflags_t; /* Bitfield */ +#define UVWASI_SHUT_RD (1 << 0) +#define UVWASI_SHUT_WR (1 << 1) + +typedef uint16_t uvwasi_siflags_t; /* Bitfield */ + +typedef uint8_t uvwasi_signal_t; +#define UVWASI_SIGHUP 1 +#define UVWASI_SIGINT 2 +#define UVWASI_SIGQUIT 3 +#define UVWASI_SIGILL 4 +#define UVWASI_SIGTRAP 5 +#define UVWASI_SIGABRT 6 +#define UVWASI_SIGBUS 7 +#define UVWASI_SIGFPE 8 +#define UVWASI_SIGKILL 9 +#define UVWASI_SIGUSR1 10 +#define UVWASI_SIGSEGV 11 +#define UVWASI_SIGUSR2 12 +#define UVWASI_SIGPIPE 13 +#define UVWASI_SIGALRM 14 +#define UVWASI_SIGTERM 15 +#define UVWASI_SIGCHLD 16 +#define UVWASI_SIGCONT 17 +#define UVWASI_SIGSTOP 18 +#define UVWASI_SIGTSTP 19 +#define UVWASI_SIGTTIN 20 +#define UVWASI_SIGTTOU 21 +#define UVWASI_SIGURG 22 +#define UVWASI_SIGXCPU 23 +#define UVWASI_SIGXFSZ 24 +#define UVWASI_SIGVTALRM 25 +#define UVWASI_SIGPROF 26 +#define UVWASI_SIGWINCH 27 +#define UVWASI_SIGPOLL 28 +#define UVWASI_SIGPWR 29 +#define UVWASI_SIGSYS 30 + +typedef uint16_t uvwasi_subclockflags_t; /* Bitfield */ +#define UVWASI_SUBSCRIPTION_CLOCK_ABSTIME (1 << 0) + +typedef uint64_t uvwasi_timestamp_t; + +typedef uint64_t uvwasi_userdata_t; + +typedef struct uvwasi_subscription_s { + uvwasi_userdata_t userdata; + uvwasi_eventtype_t type; + union { + struct { + uvwasi_userdata_t identifier; + uvwasi_clockid_t clock_id; + uvwasi_timestamp_t timeout; + uvwasi_timestamp_t precision; + uvwasi_subclockflags_t flags; + } clock; + struct { + uvwasi_fd_t fd; + } fd_readwrite; + } u; +} uvwasi_subscription_t; + +typedef struct uvwasi_dirent_s { + uvwasi_dircookie_t d_next; + uvwasi_inode_t d_ino; + uint32_t d_namlen; + uvwasi_filetype_t d_type; +} uvwasi_dirent_t; + +typedef struct uvwasi_fdstat_s { + uvwasi_filetype_t fs_filetype; + uvwasi_fdflags_t fs_flags; + uvwasi_rights_t fs_rights_base; + uvwasi_rights_t fs_rights_inheriting; +} uvwasi_fdstat_t; + +typedef struct uvwasi_filestat_s { + uvwasi_device_t st_dev; + uvwasi_inode_t st_ino; + uvwasi_filetype_t st_filetype; + uvwasi_linkcount_t st_nlink; + uvwasi_filesize_t st_size; + uvwasi_timestamp_t st_atim; + uvwasi_timestamp_t st_mtim; + uvwasi_timestamp_t st_ctim; +} uvwasi_filestat_t; + +typedef struct uvwasi_event_s { + uvwasi_userdata_t userdata; + uvwasi_errno_t error; + uvwasi_eventtype_t type; + union { + struct { + uvwasi_filesize_t nbytes; + uvwasi_eventrwflags_t flags; + } fd_readwrite; + } u; +} uvwasi_event_t; + +typedef uint8_t uvwasi_whence_t; +#define UVWASI_WHENCE_CUR 0 +#define UVWASI_WHENCE_END 1 +#define UVWASI_WHENCE_SET 2 + +#endif /* __UVWASI_WASI_TYPES_H__ */ diff --git a/deps/uvwasi/src/clocks.c b/deps/uvwasi/src/clocks.c new file mode 100644 index 00000000000000..e1fbc696b62f05 --- /dev/null +++ b/deps/uvwasi/src/clocks.c @@ -0,0 +1,194 @@ +#ifndef _WIN32 +# include +# include +# include +# include +#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 00000000000000..9343868074d10c --- /dev/null +++ b/deps/uvwasi/src/fd_table.c @@ -0,0 +1,422 @@ +#include +#include +#include + +#ifndef _WIN32 +# include +#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 00000000000000..846dcedbeb6b4f --- /dev/null +++ b/deps/uvwasi/src/uv_mapping.c @@ -0,0 +1,243 @@ +#include + +#ifndef _WIN32 +# include +#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 00000000000000..39a94b6d217c52 --- /dev/null +++ b/deps/uvwasi/src/uvwasi.c @@ -0,0 +1,1918 @@ +#include +#include + +#ifndef _WIN32 +# include +# include +# include +# include +# include +# 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; +} diff --git a/deps/uvwasi/uvwasi.gyp b/deps/uvwasi/uvwasi.gyp new file mode 100644 index 00000000000000..c07b07b608b724 --- /dev/null +++ b/deps/uvwasi/uvwasi.gyp @@ -0,0 +1,25 @@ +{ + 'targets': [ + { + 'target_name': 'uvwasi', + 'type': 'static_library', + 'cflags': ['-fvisibility=hidden'], + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + }, + 'include_dirs': ['include'], + 'sources': [ + 'src/clocks.c', + 'src/fd_table.c', + 'src/uv_mapping.c', + 'src/uvwasi.c', + ], + 'dependencies': [ + '../uv/uv.gyp:libuv', + ], + 'direct_dependent_settings': { + 'include_dirs': ['include'] + }, + } + ] +} diff --git a/doc/api/cli.md b/doc/api/cli.md index 333ecd4e09ecb7..fa600336b704f7 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -230,6 +230,13 @@ added: v9.6.0 Enable experimental ES Module support in the `vm` module. +### `--experimental-wasi-unstable-preview0` + + +Enable experimental WebAssembly System Interface (WASI) support. + ### `--experimental-wasm-modules` + +> Stability: 1 - Experimental + +The WASI API provides an implementation of the [WebAssembly System Interface][] +specification. WASI gives sandboxed WebAssembly applications access to the +underlying operating system via a collection of POSIX-like functions. + +```js +'use strict'; +const fs = require('fs'); +const { WASI } = require('wasi'); +const wasi = new WASI({ + args: process.argv, + env: process.env, + preopens: { + '/sandbox': '/some/real/path/that/wasm/can/access' + } +}); +const importObject = { wasi_unstable: wasi.wasiImport }; + +(async () => { + const wasm = await WebAssembly.compile(fs.readFileSync('./binary.wasm')); + const instance = await WebAssembly.instantiate(wasm, importObject); + + wasi.start(instance); +})(); +``` + +The `--experimental-wasi-unstable-preview0` and `--experimental-wasm-bigint` +CLI arguments are needed for the previous example to run. + +## Class: WASI + + +The `WASI` class provides the WASI system call API and additional convenience +methods for working with WASI-based applications. Each `WASI` instance +represents a distinct sandbox environment. For security purposes, each `WASI` +instance must have its command line arguments, environment variables, and +sandbox directory structure configured explicitly. + +### new WASI(\[options\]) + + +* `options` {Object} + * `args` {Array} An array of strings that the WebAssembly application will + see as command line arguments. The first argument is the virtual path to the + WASI command itself. **Default:** `[]`. + * `env` {Object} An object similar to `process.env` that the WebAssembly + application will see as its environment. **Default:** `{}`. + * `preopens` {Object} This object represents the WebAssembly application's + sandbox directory structure. The string keys of `preopens` are treated as + directories within the sandbox. The corresponding values in `preopens` are + the real paths to those directories on the host machine. + +### wasi.start(instance) + + +* `instance` {WebAssembly.Instance} + +Attempt to begin execution of `instance` by invoking its `_start()` export. +If `instance` does not contain a `_start()` export, then `start()` attempts to +invoke the `__wasi_unstable_reactor_start()` export. If neither of those exports +is present on `instance`, then `start()` does nothing. + +`start()` requires that `instance` exports a [`WebAssembly.Memory`][] named +`memory`. If `instance` does not have a `memory` export an exception is thrown. + +### wasi.wasiImport + + +* {Object} + +`wasiImport` is an object that implements the WASI system call API. This object +should be passed as the `wasi_unstable` import during the instantiation of a +[`WebAssembly.Instance`][]. + +[`WebAssembly.Instance`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance +[`WebAssembly.Memory`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory +[WebAssembly System Interface]: https://wasi.dev/ diff --git a/doc/node.1 b/doc/node.1 index e3628034e832e5..714772336e07c1 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -141,6 +141,9 @@ Enable experimental support for a package to load itself. .It Fl -experimental-vm-modules Enable experimental ES module support in VM module. . +.It Fl -experimental-wasi-unstable-preview0 +Enable experimental WebAssembly System Interface support. +. .It Fl -experimental-wasm-modules Enable experimental WebAssembly module support. . diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index cfefc56bd81bc8..044bea3114b840 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -157,6 +157,9 @@ function NativeModule(id) { this.loaded = false; this.loading = false; this.canBeRequiredByUsers = !id.startsWith('internal/'); + + if (id === 'wasi') + this.canBeRequiredByUsers = !!internalBinding('config').experimentalWasi; } // To be called during pre-execution when --expose-internals is on. diff --git a/lib/internal/errors.js b/lib/internal/errors.js index ee467f31f3e1f3..88a38f5e1de62d 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1229,6 +1229,7 @@ E('ERR_VM_MODULE_LINKING_ERRORED', E('ERR_VM_MODULE_NOT_MODULE', 'Provided module is not an instance of Module', Error); E('ERR_VM_MODULE_STATUS', 'Module status %s', Error); +E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error); E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) => `Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`, Error); diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index f7155c4aa1803f..2d73219a77772c 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -117,6 +117,11 @@ const builtinLibs = [ 'v8', 'vm', 'worker_threads', 'zlib' ]; +if (internalBinding('config').experimentalWasi) { + builtinLibs.push('wasi'); + builtinLibs.sort(); +} + if (typeof internalBinding('inspector').open === 'function') { builtinLibs.push('inspector'); builtinLibs.sort(); diff --git a/lib/wasi.js b/lib/wasi.js new file mode 100644 index 00000000000000..65b8473624198c --- /dev/null +++ b/lib/wasi.js @@ -0,0 +1,105 @@ +'use strict'; +/* global WebAssembly */ +const { + ArrayIsArray, + ArrayPrototypeForEach, + ArrayPrototypeMap, + FunctionPrototypeBind, + ObjectKeys +} = primordials; +const { + ERR_INVALID_ARG_TYPE, + ERR_WASI_ALREADY_STARTED +} = require('internal/errors').codes; +const { emitExperimentalWarning } = require('internal/util'); +const { WASI: _WASI } = internalBinding('wasi'); +const kSetMemory = Symbol('setMemory'); +const kStarted = Symbol('started'); + +emitExperimentalWarning('WASI'); + + +class WASI { + constructor(options = {}) { + if (options === null || typeof options !== 'object') + throw new ERR_INVALID_ARG_TYPE('options', 'object', options); + + // eslint-disable-next-line prefer-const + let { args, env, preopens } = options; + + if (ArrayIsArray(args)) + args = ArrayPrototypeMap(args, (arg) => { return String(arg); }); + else if (args === undefined) + args = []; + else + throw new ERR_INVALID_ARG_TYPE('options.args', 'Array', args); + + const envPairs = []; + + if (env !== null && typeof env === 'object') { + for (const key in env) { + const value = env[key]; + if (value !== undefined) + envPairs.push(`${key}=${value}`); + } + } else if (env !== undefined) { + throw new ERR_INVALID_ARG_TYPE('options.env', 'Object', env); + } + + const preopenArray = []; + + if (typeof preopens === 'object' && preopens !== null) { + ArrayPrototypeForEach(ObjectKeys(preopens), (key) => { + preopenArray.push(String(key)); + preopenArray.push(String(preopens[key])); + }); + } else if (preopens !== undefined) { + throw new ERR_INVALID_ARG_TYPE('options.preopens', 'Object', preopens); + } + + const wrap = new _WASI(args, envPairs, preopenArray); + + for (const prop in wrap) { + wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap); + } + + this[kSetMemory] = wrap._setMemory; + delete wrap._setMemory; + this.wasiImport = wrap; + this[kStarted] = false; + } + + start(instance) { + if (!(instance instanceof WebAssembly.Instance)) { + throw new ERR_INVALID_ARG_TYPE( + 'instance', 'WebAssembly.Instance', instance); + } + + const exports = instance.exports; + + if (exports === null || typeof exports !== 'object') + throw new ERR_INVALID_ARG_TYPE('instance.exports', 'Object', exports); + + const { memory } = exports; + + if (!(memory instanceof WebAssembly.Memory)) { + throw new ERR_INVALID_ARG_TYPE( + 'instance.exports.memory', 'WebAssembly.Memory', memory); + } + + if (this[kStarted]) { + throw new ERR_WASI_ALREADY_STARTED(); + } + + this[kStarted] = true; + this[kSetMemory](memory); + + if (exports._start) + exports._start(); + else if (exports.__wasi_unstable_reactor_start) + exports.__wasi_unstable_reactor_start(); + } +} + + +module.exports = { WASI }; diff --git a/node.gyp b/node.gyp index d8b55960833194..cffd150845e51a 100644 --- a/node.gyp +++ b/node.gyp @@ -82,6 +82,7 @@ 'lib/util.js', 'lib/v8.js', 'lib/vm.js', + 'lib/wasi.js', 'lib/worker_threads.js', 'lib/zlib.js', 'lib/internal/assert.js', @@ -321,7 +322,10 @@ 'src/node_main.cc' ], - 'dependencies': [ 'deps/histogram/histogram.gyp:histogram' ], + 'dependencies': [ + 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', + ], 'msvs_settings': { 'VCLinkerTool': { @@ -495,7 +499,10 @@ 'src', '<(SHARED_INTERMEDIATE_DIR)' # for node_natives.h ], - 'dependencies': [ 'deps/histogram/histogram.gyp:histogram' ], + 'dependencies': [ + 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', + ], 'sources': [ 'src/api/async_resource.cc', @@ -560,6 +567,7 @@ 'src/node_url.cc', 'src/node_util.cc', 'src/node_v8.cc', + 'src/node_wasi.cc', 'src/node_watchdog.cc', 'src/node_worker.cc', 'src/node_zlib.cc', @@ -638,6 +646,7 @@ 'src/node_url.h', 'src/node_version.h', 'src/node_v8_platform-inl.h', + 'src/node_wasi.h', 'src/node_watchdog.h', 'src/node_worker.h', 'src/pipe_wrap.h', @@ -1072,6 +1081,7 @@ 'dependencies': [ '<(node_lib_target_name)', 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', 'node_dtrace_header', 'node_dtrace_ustack', 'node_dtrace_provider', @@ -1087,6 +1097,7 @@ 'deps/v8/include', 'deps/cares/include', 'deps/uv/include', + 'deps/uvwasi/include', 'test/cctest', ], @@ -1181,6 +1192,7 @@ 'dependencies': [ '<(node_lib_target_name)', 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', ], 'includes': [ @@ -1193,6 +1205,7 @@ 'deps/v8/include', 'deps/cares/include', 'deps/uv/include', + 'deps/uvwasi/include', ], 'defines': [ @@ -1224,6 +1237,7 @@ 'dependencies': [ '<(node_lib_target_name)', 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', ], 'includes': [ @@ -1236,6 +1250,7 @@ 'deps/v8/include', 'deps/cares/include', 'deps/uv/include', + 'deps/uvwasi/include', ], 'defines': [ 'NODE_WANT_INTERNALS=1' ], diff --git a/src/env-inl.h b/src/env-inl.h index d34bd03c7c6896..d75b4ea743c4f4 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -1102,6 +1102,21 @@ inline void Environment::SetProtoMethodNoSideEffect( t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility. } +inline void Environment::SetInstanceMethod(v8::Local that, + const char* name, + v8::FunctionCallback callback) { + v8::Local signature = v8::Signature::New(isolate(), that); + v8::Local t = + NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow, + v8::SideEffectType::kHasSideEffect); + // kInternalized strings are created in the old space. + const v8::NewStringType type = v8::NewStringType::kInternalized; + v8::Local name_string = + v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); + that->InstanceTemplate()->Set(name_string, t); + t->SetClassName(name_string); +} + void Environment::AddCleanupHook(void (*fn)(void*), void* arg) { auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback { fn, arg, cleanup_hook_counter_++ diff --git a/src/env.h b/src/env.h index c0c8ac0db4882d..c25a03ea1e520a 100644 --- a/src/env.h +++ b/src/env.h @@ -541,7 +541,8 @@ struct ContextInfo { #define DEBUG_CATEGORY_NAMES(V) \ NODE_ASYNC_PROVIDER_TYPES(V) \ V(INSPECTOR_SERVER) \ - V(INSPECTOR_PROFILER) + V(INSPECTOR_PROFILER) \ + V(WASI) enum class DebugCategory { #define V(name) name, @@ -1114,6 +1115,11 @@ class Environment : public MemoryRetainer { const char* name, v8::FunctionCallback callback); + inline void SetInstanceMethod(v8::Local that, + const char* name, + v8::FunctionCallback callback); + + // Safe variants denote the function has no side effects. inline void SetMethodNoSideEffect(v8::Local that, const char* name, diff --git a/src/node_binding.cc b/src/node_binding.cc index f57ddb54b629ca..82836585c589a5 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -85,6 +85,7 @@ V(util) \ V(uv) \ V(v8) \ + V(wasi) \ V(worker) \ V(zlib) diff --git a/src/node_config.cc b/src/node_config.cc index 92985dff2f8b0c..16050bdd5b967d 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -84,6 +84,9 @@ static void Initialize(Local target, READONLY_PROPERTY(target, "hasCachedBuiltins", v8::Boolean::New(isolate, native_module::has_code_cache)); + + if (env->options()->experimental_wasi) + READONLY_TRUE_PROPERTY(target, "experimentalWasi"); } // InitConfig } // namespace node diff --git a/src/node_options.cc b/src/node_options.cc index 505441d0620b29..498bedd1e5e892 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -347,6 +347,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { &EnvironmentOptions::experimental_report, kAllowedInEnvironment); #endif // NODE_REPORT + AddOption("--experimental-wasi-unstable-preview0", + "experimental WASI support", + &EnvironmentOptions::experimental_wasi, + kAllowedInEnvironment); AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals); AddOption("--frozen-intrinsics", "experimental frozen intrinsics support", diff --git a/src/node_options.h b/src/node_options.h index 763e6ab9c87b57..fea912da446568 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -152,6 +152,7 @@ class EnvironmentOptions : public Options { #ifdef NODE_REPORT bool experimental_report = false; #endif // NODE_REPORT + bool experimental_wasi = false; std::string eval_string; bool print_eval = false; bool force_repl = false; diff --git a/src/node_wasi.cc b/src/node_wasi.cc new file mode 100644 index 00000000000000..8de7f1fc1cae68 --- /dev/null +++ b/src/node_wasi.cc @@ -0,0 +1,1802 @@ +#include "env-inl.h" +#include "base_object-inl.h" +#include "debug_utils.h" +#include "util-inl.h" +#include "node.h" +#include "uv.h" +#include "uvwasi.h" +#include "node_wasi.h" + +namespace node { +namespace wasi { + +static inline bool is_access_oob(size_t mem_size, + uint32_t offset, + uint32_t buf_size) { + return offset + buf_size > mem_size; +} + +template +inline void Debug(WASI* wasi, Args&&... args) { + Debug(wasi->env(), DebugCategory::WASI, std::forward(args)...); +} + +#define RETURN_IF_BAD_ARG_COUNT(args, expected) \ + do { \ + if ((args).Length() != (expected)) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + } while (0) + +#define CHECK_TO_TYPE_OR_RETURN(args, input, type, result) \ + do { \ + if (!(input)->Is##type()) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + (result) = (input).As()->Value(); \ + } while (0) + +#define UNWRAP_BIGINT_OR_RETURN(args, input, type, result) \ + do { \ + if (!(input)->IsBigInt()) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + Local js_value = (input).As(); \ + bool lossless; \ + (result) = js_value->type ## Value(&lossless); \ + } while (0) + +#define GET_BACKING_STORE_OR_RETURN(wasi, args, mem_ptr, mem_size) \ + do { \ + uvwasi_errno_t err = (wasi)->backingStore((mem_ptr), (mem_size)); \ + if (err != UVWASI_ESUCCESS) { \ + (args).GetReturnValue().Set(err); \ + return; \ + } \ + } while (0) + +#define CHECK_BOUNDS_OR_RETURN(args, mem_size, offset, buf_size) \ + do { \ + if (is_access_oob((mem_size), (offset), (buf_size))) { \ + (args).GetReturnValue().Set(UVWASI_EOVERFLOW); \ + return; \ + } \ + } while (0) + + +using v8::Array; +using v8::ArrayBuffer; +using v8::BackingStore; +using v8::BigInt; +using v8::Context; +using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Uint32; +using v8::Value; + + +WASI::WASI(Environment* env, + Local object, + uvwasi_options_t* options) : BaseObject(env, object) { + MakeWeak(); + CHECK_EQ(uvwasi_init(&uvw_, options), UVWASI_ESUCCESS); +} + + +WASI::~WASI() { + uvwasi_destroy(&uvw_); +} + + +void WASI::New(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + CHECK_EQ(args.Length(), 3); + CHECK(args[0]->IsArray()); + CHECK(args[1]->IsArray()); + CHECK(args[2]->IsArray()); + + Environment* env = Environment::GetCurrent(args); + Local context = env->context(); + Local argv = args[0].As(); + const uint32_t argc = argv->Length(); + uvwasi_options_t options; + + options.fd_table_size = 3; + options.argc = argc; + options.argv = argc == 0 ? nullptr : new char*[argc]; + + for (uint32_t i = 0; i < argc; i++) { + auto arg = argv->Get(context, i).ToLocalChecked(); + CHECK(arg->IsString()); + node::Utf8Value str(env->isolate(), arg); + options.argv[i] = strdup(*str); + CHECK_NOT_NULL(options.argv[i]); + } + + Local env_pairs = args[1].As(); + const uint32_t envc = env_pairs->Length(); + options.envp = new char*[envc + 1]; + for (uint32_t i = 0; i < envc; i++) { + auto pair = env_pairs->Get(context, i).ToLocalChecked(); + CHECK(pair->IsString()); + node::Utf8Value str(env->isolate(), pair); + options.envp[i] = strdup(*str); + CHECK_NOT_NULL(options.envp[i]); + } + options.envp[envc] = nullptr; + + Local preopens = args[2].As(); + CHECK_EQ(preopens->Length() % 2, 0); + options.preopenc = preopens->Length() / 2; + options.preopens = UncheckedCalloc(options.preopenc); + int index = 0; + for (uint32_t i = 0; i < preopens->Length(); i += 2) { + auto mapped = preopens->Get(context, i).ToLocalChecked(); + auto real = preopens->Get(context, i + 1).ToLocalChecked(); + CHECK(mapped->IsString()); + CHECK(real->IsString()); + node::Utf8Value mapped_path(env->isolate(), mapped); + node::Utf8Value real_path(env->isolate(), real); + options.preopens[index].mapped_path = strdup(*mapped_path); + options.preopens[index].real_path = strdup(*real_path); + index++; + } + + new WASI(env, args.This(), &options); + + if (options.argv != nullptr) { + for (uint32_t i = 0; i < argc; i++) + free(options.argv[i]); + delete[] options.argv; + } + + if (options.envp != nullptr) { + for (uint32_t i = 0; options.envp[i]; i++) + free(options.envp[i]); + delete[] options.envp; + } +} + + +void WASI::ArgsGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t argv_offset; + uint32_t argv_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, argv_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, argv_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "args_get(%d, %d)\n", argv_offset, argv_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, + mem_size, + argv_buf_offset, + wasi->uvw_.argv_buf_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argv_offset, wasi->uvw_.argc * 4); + std::vector argv(wasi->uvw_.argc); + char* argv_buf = &memory[argv_buf_offset]; + uvwasi_errno_t err = uvwasi_args_get(&wasi->uvw_, argv.data(), argv_buf); + + if (err == UVWASI_ESUCCESS) { + for (size_t i = 0; i < wasi->uvw_.argc; i++) { + uint32_t offset = argv_buf_offset + (argv[i] - argv[0]); + wasi->writeUInt32(memory, offset, argv_offset + (i * 4)); + } + } + + args.GetReturnValue().Set(err); +} + + +void WASI::ArgsSizesGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t argc_offset; + uint32_t argv_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, argc_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, argv_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "args_sizes_get(%d, %d)\n", argc_offset, argv_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argc_offset, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argv_buf_offset, 4); + size_t argc; + size_t argv_buf_size; + uvwasi_errno_t err = uvwasi_args_sizes_get(&wasi->uvw_, + &argc, + &argv_buf_size); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, argc, argc_offset); + wasi->writeUInt32(memory, argv_buf_size, argv_buf_offset); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::ClockResGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t clock_id; + uint32_t resolution_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, clock_id); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, resolution_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "clock_res_get(%d, %d)\n", clock_id, resolution_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, resolution_ptr, 8); + uvwasi_timestamp_t resolution; + uvwasi_errno_t err = uvwasi_clock_res_get(&wasi->uvw_, + clock_id, + &resolution); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, resolution, resolution_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::ClockTimeGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t clock_id; + uint64_t precision; + uint32_t time_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, clock_id); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, precision); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, time_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "clock_time_get(%d, %d, %d)\n", clock_id, precision, time_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, time_ptr, 8); + uvwasi_timestamp_t time; + uvwasi_errno_t err = uvwasi_clock_time_get(&wasi->uvw_, + clock_id, + precision, + &time); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, time, time_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::EnvironGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t environ_offset; + uint32_t environ_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, environ_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, environ_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "environ_get(%d, %d)\n", environ_offset, environ_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, + mem_size, + environ_buf_offset, + wasi->uvw_.env_buf_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, environ_offset, wasi->uvw_.envc * 4); + std::vector environment(wasi->uvw_.envc); + char* environ_buf = &memory[environ_buf_offset]; + uvwasi_errno_t err = uvwasi_environ_get(&wasi->uvw_, + environment.data(), + environ_buf); + + if (err == UVWASI_ESUCCESS) { + for (size_t i = 0; i < wasi->uvw_.envc; i++) { + uint32_t offset = environ_buf_offset + (environment[i] - environment[0]); + wasi->writeUInt32(memory, offset, environ_offset + (i * 4)); + } + } + + args.GetReturnValue().Set(err); +} + + +void WASI::EnvironSizesGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t envc_offset; + uint32_t env_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, envc_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, env_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "environ_sizes_get(%d, %d)\n", envc_offset, env_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, envc_offset, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, env_buf_offset, 4); + size_t envc; + size_t env_buf_size; + uvwasi_errno_t err = uvwasi_environ_sizes_get(&wasi->uvw_, + &envc, + &env_buf_size); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, envc, envc_offset); + wasi->writeUInt32(memory, env_buf_size, env_buf_offset); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdAdvise(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t offset; + uint64_t len; + uint8_t advice; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, offset); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, advice); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_advise(%d, %d, %d, %d)\n", fd, offset, len, advice); + uvwasi_errno_t err = uvwasi_fd_advise(&wasi->uvw_, fd, offset, len, advice); + args.GetReturnValue().Set(err); +} + + +void WASI::FdAllocate(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t offset; + uint64_t len; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, offset); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_allocate(%d, %d, %d)\n", fd, offset, len); + uvwasi_errno_t err = uvwasi_fd_allocate(&wasi->uvw_, fd, offset, len); + args.GetReturnValue().Set(err); +} + + +void WASI::FdClose(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_close(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_close(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdDatasync(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_datasync(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_datasync(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_fdstat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 24); + uvwasi_fdstat_t stats; + uvwasi_errno_t err = uvwasi_fd_fdstat_get(&wasi->uvw_, fd, &stats); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt8(memory, stats.fs_filetype, buf); + wasi->writeUInt16(memory, stats.fs_flags, buf + 2); + wasi->writeUInt64(memory, stats.fs_rights_base, buf + 8); + wasi->writeUInt64(memory, stats.fs_rights_inheriting, buf + 16); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatSetFlags(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint16_t flags; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_fdstat_set_flags(%d, %d)\n", fd, flags); + uvwasi_errno_t err = uvwasi_fd_fdstat_set_flags(&wasi->uvw_, fd, flags); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatSetRights(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t fs_rights_base; + uint64_t fs_rights_inheriting; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, fs_rights_base); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, fs_rights_inheriting); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_fdstat_set_rights(%d, %d, %d)\n", + fd, + fs_rights_base, + fs_rights_inheriting); + uvwasi_errno_t err = uvwasi_fd_fdstat_set_rights(&wasi->uvw_, + fd, + fs_rights_base, + fs_rights_inheriting); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_filestat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 56); + uvwasi_filestat_t stats; + uvwasi_errno_t err = uvwasi_fd_filestat_get(&wasi->uvw_, fd, &stats); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt64(memory, stats.st_dev, buf); + wasi->writeUInt64(memory, stats.st_ino, buf + 8); + wasi->writeUInt8(memory, stats.st_filetype, buf + 16); + wasi->writeUInt32(memory, stats.st_nlink, buf + 20); + wasi->writeUInt64(memory, stats.st_size, buf + 24); + wasi->writeUInt64(memory, stats.st_atim, buf + 32); + wasi->writeUInt64(memory, stats.st_mtim, buf + 40); + wasi->writeUInt64(memory, stats.st_ctim, buf + 48); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatSetSize(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t st_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, st_size); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_filestat_set_size(%d, %d)\n", fd, st_size); + uvwasi_errno_t err = uvwasi_fd_filestat_set_size(&wasi->uvw_, fd, st_size); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatSetTimes(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t st_atim; + uint64_t st_mtim; + uint16_t fst_flags; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, st_atim); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, st_mtim); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, fst_flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_filestat_set_times(%d, %d, %d, %d)\n", + fd, + st_atim, + st_mtim, + fst_flags); + uvwasi_errno_t err = uvwasi_fd_filestat_set_times(&wasi->uvw_, + fd, + st_atim, + st_mtim, + fst_flags); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPread(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint64_t offset; + uint32_t nread_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, nread_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_pread(%d, %d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + offset, + nread_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nread_ptr, 4); + uvwasi_iovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nread; + uvwasi_errno_t err = uvwasi_fd_pread(&wasi->uvw_, + fd, + iovs, + iovs_len, + offset, + &nread); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nread, nread_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPrestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_prestat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 8); + uvwasi_prestat_t prestat; + uvwasi_errno_t err = uvwasi_fd_prestat_get(&wasi->uvw_, fd, &prestat); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, prestat.pr_type, buf); + wasi->writeUInt32(memory, prestat.u.dir.pr_name_len, buf + 4); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdPrestatDirName(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_prestat_dir_name(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_fd_prestat_dir_name(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPwrite(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint64_t offset; + uint32_t nwritten_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, nwritten_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_pwrite(%d, %d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + offset, + nwritten_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nwritten_ptr, 4); + uvwasi_ciovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nwritten; + uvwasi_errno_t err = uvwasi_fd_pwrite(&wasi->uvw_, + fd, + iovs, + iovs_len, + offset, + &nwritten); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nwritten, nwritten_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdRead(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint32_t nread_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nread_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_read(%d, %d, %d, %d)\n", fd, iovs_ptr, iovs_len, nread_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nread_ptr, 4); + uvwasi_iovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nread; + uvwasi_errno_t err = uvwasi_fd_read(&wasi->uvw_, + fd, + iovs, + iovs_len, + &nread); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nread, nread_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdReaddir(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf_ptr; + uint32_t buf_len; + uint64_t cookie; + uint32_t bufused_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, buf_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, cookie); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, bufused_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_readdir(%d, %d, %d, %d, %d)\n", + fd, + buf_ptr, + buf_len, + cookie, + bufused_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, bufused_ptr, 4); + size_t bufused; + uvwasi_errno_t err = uvwasi_fd_readdir(&wasi->uvw_, + fd, + &memory[buf_ptr], + buf_len, + cookie, + &bufused); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, bufused, bufused_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdRenumber(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t from; + uint32_t to; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, from); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, to); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_renumber(%d, %d)\n", from, to); + uvwasi_errno_t err = uvwasi_fd_renumber(&wasi->uvw_, from, to); + args.GetReturnValue().Set(err); +} + + +void WASI::FdSeek(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + int64_t offset; + uint8_t whence; + uint32_t newoffset_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Int64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, whence); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, newoffset_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_seek(%d, %d, %d, %d)\n", fd, offset, whence, newoffset_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, newoffset_ptr, 8); + uvwasi_filesize_t newoffset; + uvwasi_errno_t err = uvwasi_fd_seek(&wasi->uvw_, + fd, + offset, + whence, + &newoffset); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, newoffset, newoffset_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdSync(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_sync(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_sync(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdTell(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t offset_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, offset_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_tell(%d, %d)\n", fd, offset_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, offset_ptr, 8); + uvwasi_filesize_t offset; + uvwasi_errno_t err = uvwasi_fd_tell(&wasi->uvw_, fd, &offset); + + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, offset, offset_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdWrite(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint32_t nwritten_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nwritten_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_write(%d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + nwritten_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nwritten_ptr, 4); + uvwasi_ciovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nwritten; + uvwasi_errno_t err = uvwasi_fd_write(&wasi->uvw_, + fd, + iovs, + iovs_len, + &nwritten); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nwritten, nwritten_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::PathCreateDirectory(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_create_directory(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_create_directory(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathFilestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t flags; + uint32_t path_ptr; + uint32_t path_len; + uint32_t buf_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, buf_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_filestat_get(%d, %d, %d, %d, %d)\n", + fd, + path_ptr, + path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, 56); + uvwasi_filestat_t stats; + uvwasi_errno_t err = uvwasi_path_filestat_get(&wasi->uvw_, + fd, + flags, + &memory[path_ptr], + path_len, + &stats); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt64(memory, stats.st_dev, buf_ptr); + wasi->writeUInt64(memory, stats.st_ino, buf_ptr + 8); + wasi->writeUInt8(memory, stats.st_filetype, buf_ptr + 16); + wasi->writeUInt32(memory, stats.st_nlink, buf_ptr + 20); + wasi->writeUInt64(memory, stats.st_size, buf_ptr + 24); + wasi->writeUInt64(memory, stats.st_atim, buf_ptr + 32); + wasi->writeUInt64(memory, stats.st_mtim, buf_ptr + 40); + wasi->writeUInt64(memory, stats.st_ctim, buf_ptr + 48); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::PathFilestatSetTimes(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t flags; + uint32_t path_ptr; + uint32_t path_len; + uint64_t st_atim; + uint64_t st_mtim; + uint16_t fst_flags; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 7); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + UNWRAP_BIGINT_OR_RETURN(args, args[4], Uint64, st_atim); + UNWRAP_BIGINT_OR_RETURN(args, args[5], Uint64, st_mtim); + CHECK_TO_TYPE_OR_RETURN(args, args[6], Uint32, fst_flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_filestat_set_times(%d, %d, %d, %d, %d, %d, %d)\n", + fd, + flags, + path_ptr, + path_len, + st_atim, + st_mtim, + fst_flags); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_filestat_set_times(&wasi->uvw_, + fd, + flags, + &memory[path_ptr], + path_len, + st_atim, + st_mtim, + fst_flags); + args.GetReturnValue().Set(err); +} + + +void WASI::PathLink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_fd; + uint32_t old_flags; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t new_fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 7); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[6], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_link(%d, %d, %d, %d, %d, %d, %d)\n", + old_fd, + old_flags, + old_path_ptr, + old_path_len, + new_fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_link(&wasi->uvw_, + old_fd, + old_flags, + &memory[old_path_ptr], + old_path_len, + new_fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathOpen(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t dirfd; + uint32_t dirflags; + uint32_t path_ptr; + uint32_t path_len; + uint32_t o_flags; + uint64_t fs_rights_base; + uint64_t fs_rights_inheriting; + uint32_t fs_flags; + uint32_t fd_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 9); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, dirfd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, dirflags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, o_flags); + UNWRAP_BIGINT_OR_RETURN(args, args[5], Uint64, fs_rights_base); + UNWRAP_BIGINT_OR_RETURN(args, args[6], Uint64, fs_rights_inheriting); + CHECK_TO_TYPE_OR_RETURN(args, args[7], Uint32, fs_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[8], Uint32, fd_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_open(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", + dirfd, + dirflags, + path_ptr, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, fd_ptr, 4); + uvwasi_fd_t fd; + uvwasi_errno_t err = uvwasi_path_open(&wasi->uvw_, + dirfd, + dirflags, + &memory[path_ptr], + path_len, + static_cast(o_flags), + fs_rights_base, + fs_rights_inheriting, + static_cast(fs_flags), + &fd); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, fd, fd_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::PathReadlink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + uint32_t buf_ptr; + uint32_t buf_len; + uint32_t bufused_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, buf_len); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, bufused_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_readlink(%d, %d, %d, %d, %d, %d)\n", + fd, + path_ptr, + path_len, + buf_ptr, + buf_len, + bufused_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, bufused_ptr, 4); + size_t bufused; + uvwasi_errno_t err = uvwasi_path_readlink(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len, + &memory[buf_ptr], + buf_len, + &bufused); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, bufused, bufused_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::PathRemoveDirectory(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_remove_directory(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_remove_directory(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathRename(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_fd; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t new_fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, new_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_rename(%d, %d, %d, %d, %d, %d)\n", + old_fd, + old_path_ptr, + old_path_len, + new_fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_rename(&wasi->uvw_, + old_fd, + &memory[old_path_ptr], + old_path_len, + new_fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathSymlink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_symlink(%d, %d, %d, %d, %d)\n", + old_path_ptr, + old_path_len, + fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_symlink(&wasi->uvw_, + &memory[old_path_ptr], + old_path_len, + fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathUnlinkFile(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_unlink_file(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_unlink_file(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PollOneoff(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t in_ptr; + uint32_t out_ptr; + uint32_t nsubscriptions; + uint32_t nevents_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, in_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, out_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, nsubscriptions); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nevents_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "poll_oneoff(%d, %d, %d, %d)\n", + in_ptr, + out_ptr, + nsubscriptions, + nevents_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, in_ptr, nsubscriptions * 56); + CHECK_BOUNDS_OR_RETURN(args, mem_size, out_ptr, nsubscriptions * 32); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nevents_ptr, 4); + uvwasi_subscription_t* in = + UncheckedCalloc(nsubscriptions); + + if (in == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + uvwasi_event_t* out = UncheckedCalloc(nsubscriptions); + + if (out == nullptr) { + free(in); + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < nsubscriptions; ++i) { + uvwasi_subscription_t sub = in[i]; + wasi->readUInt64(memory, &sub.userdata, in_ptr); + wasi->readUInt8(memory, &sub.type, in_ptr + 8); + + if (sub.type == UVWASI_EVENTTYPE_CLOCK) { + wasi->readUInt64(memory, &sub.u.clock.identifier, in_ptr + 16); + wasi->readUInt32(memory, &sub.u.clock.clock_id, in_ptr + 24); + wasi->readUInt64(memory, &sub.u.clock.timeout, in_ptr + 32); + wasi->readUInt64(memory, &sub.u.clock.precision, in_ptr + 40); + wasi->readUInt16(memory, &sub.u.clock.flags, in_ptr + 48); + } else if (sub.type == UVWASI_EVENTTYPE_FD_READ || + sub.type == UVWASI_EVENTTYPE_FD_WRITE) { + wasi->readUInt32(memory, &sub.u.fd_readwrite.fd, in_ptr + 16); + } + + in_ptr += 56; + } + + size_t nevents; + uvwasi_errno_t err = uvwasi_poll_oneoff(&wasi->uvw_, + in, + out, + nsubscriptions, + &nevents); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, nevents, nevents_ptr); + + for (uint32_t i = 0; i < nsubscriptions; ++i) { + uvwasi_event_t event = out[i]; + + wasi->writeUInt64(memory, event.userdata, out_ptr); + wasi->writeUInt16(memory, event.error, out_ptr + 8); + wasi->writeUInt8(memory, event.type, out_ptr + 10); + + if (event.type == UVWASI_EVENTTYPE_FD_READ || + event.type == UVWASI_EVENTTYPE_FD_WRITE) { + wasi->writeUInt64(memory, event.u.fd_readwrite.nbytes, out_ptr + 16); + wasi->writeUInt16(memory, event.u.fd_readwrite.flags, out_ptr + 24); + } + + out_ptr += 32; + } + } + + free(in); + free(out); + args.GetReturnValue().Set(err); +} + + +void WASI::ProcExit(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t code; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, code); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "proc_exit(%d)\n", code); + args.GetReturnValue().Set(uvwasi_proc_exit(&wasi->uvw_, code)); +} + + +void WASI::ProcRaise(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sig; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sig); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "proc_raise(%d)\n", sig); + uvwasi_errno_t err = uvwasi_proc_raise(&wasi->uvw_, sig); + args.GetReturnValue().Set(err); +} + + +void WASI::RandomGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t buf_ptr; + uint32_t buf_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "random_get(%d, %d)\n", buf_ptr, buf_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + uvwasi_errno_t err = uvwasi_random_get(&wasi->uvw_, + &memory[buf_ptr], + buf_len); + args.GetReturnValue().Set(err); +} + + +void WASI::SchedYield(const FunctionCallbackInfo& args) { + WASI* wasi; + RETURN_IF_BAD_ARG_COUNT(args, 0); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "sched_yield()\n"); + uvwasi_errno_t err = uvwasi_sched_yield(&wasi->uvw_); + args.GetReturnValue().Set(err); +} + + +void WASI::SockRecv(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint32_t ri_data_ptr; + uint32_t ri_data_len; + uint16_t ri_flags; + uint32_t ro_datalen_ptr; + uint16_t ro_flags_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, ri_data_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, ri_data_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, ri_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, ro_datalen_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, ro_flags_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "sock_recv(%d, %d, %d, %d, %d, %d)\n", + sock, + ri_data_ptr, + ri_data_len, + ri_flags, + ro_datalen_ptr, + ro_flags_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ri_data_ptr, ri_data_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ro_datalen_ptr, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ro_flags_ptr, 4); + uvwasi_iovec_t* ri_data = UncheckedCalloc(ri_data_len); + + if (ri_data == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < ri_data_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, ri_data_ptr); + wasi->readUInt32(memory, &buf_len, ri_data_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(ri_data); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + ri_data_ptr += 8; + ri_data[i].buf = static_cast(&memory[buf_ptr]); + ri_data[i].buf_len = buf_len; + } + + size_t ro_datalen; + uvwasi_roflags_t ro_flags; + uvwasi_errno_t err = uvwasi_sock_recv(&wasi->uvw_, + sock, + ri_data, + ri_data_len, + ri_flags, + &ro_datalen, + &ro_flags); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, ro_datalen, ro_datalen_ptr); + wasi->writeUInt32(memory, ro_flags, ro_flags_ptr); + } + + free(ri_data); + args.GetReturnValue().Set(err); +} + + +void WASI::SockSend(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint32_t si_data_ptr; + uint32_t si_data_len; + uint16_t si_flags; + uint32_t so_datalen_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, si_data_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, si_data_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, si_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, so_datalen_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "sock_send(%d, %d, %d, %d, %d)\n", + sock, + si_data_ptr, + si_data_len, + si_flags, + so_datalen_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, si_data_ptr, si_data_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, so_datalen_ptr, 4); + uvwasi_ciovec_t* si_data = UncheckedCalloc(si_data_len); + + if (si_data == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < si_data_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, si_data_ptr); + wasi->readUInt32(memory, &buf_len, si_data_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(si_data); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + si_data_ptr += 8; + si_data[i].buf = static_cast(&memory[buf_ptr]); + si_data[i].buf_len = buf_len; + } + + size_t so_datalen; + uvwasi_errno_t err = uvwasi_sock_send(&wasi->uvw_, + sock, + si_data, + si_data_len, + si_flags, + &so_datalen); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, so_datalen, so_datalen_ptr); + + free(si_data); + args.GetReturnValue().Set(err); +} + + +void WASI::SockShutdown(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint8_t how; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, how); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "sock_shutdown(%d, %d)\n", sock, how); + uvwasi_errno_t err = uvwasi_sock_shutdown(&wasi->uvw_, sock, how); + args.GetReturnValue().Set(err); +} + + +void WASI::_SetMemory(const FunctionCallbackInfo& args) { + WASI* wasi; + CHECK_EQ(args.Length(), 1); + CHECK(args[0]->IsObject()); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + wasi->memory_.Reset(wasi->env()->isolate(), args[0].As()); +} + + +void WASI::readUInt8(char* memory, uint8_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = memory[offset] & 0xFF; +} + + +void WASI::readUInt16(char* memory, uint16_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8); +} + + +void WASI::readUInt32(char* memory, uint32_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8) | + ((memory[offset + 2] & 0xFF) << 16) | + ((memory[offset + 3] & 0xFF) << 24); +} + + +void WASI::readUInt64(char* memory, uint64_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + uint64_t low = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8) | + ((memory[offset + 2] & 0xFF) << 16) | + ((memory[offset + 3] & 0xFF) << 24); + uint64_t high = (memory[offset + 4] & 0xFF) | + ((memory[offset + 5] & 0xFF) << 8) | + ((memory[offset + 6] & 0xFF) << 16) | + ((memory[offset + 7] & 0xFF) << 24); + *value = (high << 32) + low; +} + + +void WASI::writeUInt8(char* memory, uint8_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset] = value & 0xFF; +} + + +void WASI::writeUInt16(char* memory, uint16_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset] = (value >> 8) & 0xFF; +} + + +void WASI::writeUInt32(char* memory, uint32_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset++] = (value >> 8) & 0xFF; + memory[offset++] = (value >> 16) & 0xFF; + memory[offset] = (value >> 24) & 0xFF; +} + + +void WASI::writeUInt64(char* memory, uint64_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset++] = (value >> 8) & 0xFF; + memory[offset++] = (value >> 16) & 0xFF; + memory[offset++] = (value >> 24) & 0xFF; + memory[offset++] = (value >> 32) & 0xFF; + memory[offset++] = (value >> 40) & 0xFF; + memory[offset++] = (value >> 48) & 0xFF; + memory[offset] = (value >> 56) & 0xFF; +} + + +uvwasi_errno_t WASI::backingStore(char** store, size_t* byte_length) { + Environment* env = this->env(); + Local memory = PersistentToLocal::Strong(this->memory_); + Local prop; + + if (!memory->Get(env->context(), env->buffer_string()).ToLocal(&prop)) + return UVWASI_EINVAL; + + if (!prop->IsArrayBuffer()) + return UVWASI_EINVAL; + + Local ab = prop.As(); + std::shared_ptr backing_store = ab->GetBackingStore(); + *byte_length = backing_store->ByteLength(); + *store = static_cast(backing_store->Data()); + return UVWASI_ESUCCESS; +} + + +static void Initialize(Local target, + Local unused, + Local context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + + Local tmpl = env->NewFunctionTemplate(WASI::New); + auto wasi_wrap_string = FIXED_ONE_BYTE_STRING(env->isolate(), "WASI"); + tmpl->InstanceTemplate()->SetInternalFieldCount(1); + tmpl->SetClassName(wasi_wrap_string); + + env->SetProtoMethod(tmpl, "args_get", WASI::ArgsGet); + env->SetProtoMethod(tmpl, "args_sizes_get", WASI::ArgsSizesGet); + env->SetProtoMethod(tmpl, "clock_res_get", WASI::ClockResGet); + env->SetProtoMethod(tmpl, "clock_time_get", WASI::ClockTimeGet); + env->SetProtoMethod(tmpl, "environ_get", WASI::EnvironGet); + env->SetProtoMethod(tmpl, "environ_sizes_get", WASI::EnvironSizesGet); + env->SetProtoMethod(tmpl, "fd_advise", WASI::FdAdvise); + env->SetProtoMethod(tmpl, "fd_allocate", WASI::FdAllocate); + env->SetProtoMethod(tmpl, "fd_close", WASI::FdClose); + env->SetProtoMethod(tmpl, "fd_datasync", WASI::FdDatasync); + env->SetProtoMethod(tmpl, "fd_fdstat_get", WASI::FdFdstatGet); + env->SetProtoMethod(tmpl, "fd_fdstat_set_flags", WASI::FdFdstatSetFlags); + env->SetProtoMethod(tmpl, "fd_fdstat_set_rights", WASI::FdFdstatSetRights); + env->SetProtoMethod(tmpl, "fd_filestat_get", WASI::FdFilestatGet); + env->SetProtoMethod(tmpl, "fd_filestat_set_size", WASI::FdFilestatSetSize); + env->SetProtoMethod(tmpl, "fd_filestat_set_times", WASI::FdFilestatSetTimes); + env->SetProtoMethod(tmpl, "fd_pread", WASI::FdPread); + env->SetProtoMethod(tmpl, "fd_prestat_get", WASI::FdPrestatGet); + env->SetProtoMethod(tmpl, "fd_prestat_dir_name", WASI::FdPrestatDirName); + env->SetProtoMethod(tmpl, "fd_pwrite", WASI::FdPwrite); + env->SetProtoMethod(tmpl, "fd_read", WASI::FdRead); + env->SetProtoMethod(tmpl, "fd_readdir", WASI::FdReaddir); + env->SetProtoMethod(tmpl, "fd_renumber", WASI::FdRenumber); + env->SetProtoMethod(tmpl, "fd_seek", WASI::FdSeek); + env->SetProtoMethod(tmpl, "fd_sync", WASI::FdSync); + env->SetProtoMethod(tmpl, "fd_tell", WASI::FdTell); + env->SetProtoMethod(tmpl, "fd_write", WASI::FdWrite); + env->SetProtoMethod(tmpl, "path_create_directory", WASI::PathCreateDirectory); + env->SetProtoMethod(tmpl, "path_filestat_get", WASI::PathFilestatGet); + env->SetProtoMethod(tmpl, + "path_filestat_set_times", + WASI::PathFilestatSetTimes); + env->SetProtoMethod(tmpl, "path_link", WASI::PathLink); + env->SetProtoMethod(tmpl, "path_open", WASI::PathOpen); + env->SetProtoMethod(tmpl, "path_readlink", WASI::PathReadlink); + env->SetProtoMethod(tmpl, "path_remove_directory", WASI::PathRemoveDirectory); + env->SetProtoMethod(tmpl, "path_rename", WASI::PathRename); + env->SetProtoMethod(tmpl, "path_symlink", WASI::PathSymlink); + env->SetProtoMethod(tmpl, "path_unlink_file", WASI::PathUnlinkFile); + env->SetProtoMethod(tmpl, "poll_oneoff", WASI::PollOneoff); + env->SetProtoMethod(tmpl, "proc_exit", WASI::ProcExit); + env->SetProtoMethod(tmpl, "proc_raise", WASI::ProcRaise); + env->SetProtoMethod(tmpl, "random_get", WASI::RandomGet); + env->SetProtoMethod(tmpl, "sched_yield", WASI::SchedYield); + env->SetProtoMethod(tmpl, "sock_recv", WASI::SockRecv); + env->SetProtoMethod(tmpl, "sock_send", WASI::SockSend); + env->SetProtoMethod(tmpl, "sock_shutdown", WASI::SockShutdown); + + env->SetInstanceMethod(tmpl, "_setMemory", WASI::_SetMemory); + + target->Set(env->context(), + wasi_wrap_string, + tmpl->GetFunction(context).ToLocalChecked()).ToChecked(); +} + + +} // namespace wasi +} // namespace node + +NODE_MODULE_CONTEXT_AWARE_INTERNAL(wasi, node::wasi::Initialize) diff --git a/src/node_wasi.h b/src/node_wasi.h new file mode 100644 index 00000000000000..ca726e48a42a47 --- /dev/null +++ b/src/node_wasi.h @@ -0,0 +1,103 @@ +#ifndef SRC_NODE_WASI_H_ +#define SRC_NODE_WASI_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "base_object.h" +#include "memory_tracker-inl.h" +#include "uvwasi.h" + +namespace node { +namespace wasi { + + +class WASI : public BaseObject { + public: + WASI(Environment* env, + v8::Local object, + uvwasi_options_t* options); + static void New(const v8::FunctionCallbackInfo& args); + void MemoryInfo(MemoryTracker* tracker) const override { + /* TODO(cjihrig): Get memory consumption from uvwasi. */ + tracker->TrackField("memory", memory_); + } + + SET_MEMORY_INFO_NAME(WASI) + SET_SELF_SIZE(WASI) + + static void ArgsGet(const v8::FunctionCallbackInfo& args); + static void ArgsSizesGet(const v8::FunctionCallbackInfo& args); + static void ClockResGet(const v8::FunctionCallbackInfo& args); + static void ClockTimeGet(const v8::FunctionCallbackInfo& args); + static void EnvironGet(const v8::FunctionCallbackInfo& args); + static void EnvironSizesGet(const v8::FunctionCallbackInfo& args); + static void FdAdvise(const v8::FunctionCallbackInfo& args); + static void FdAllocate(const v8::FunctionCallbackInfo& args); + static void FdClose(const v8::FunctionCallbackInfo& args); + static void FdDatasync(const v8::FunctionCallbackInfo& args); + static void FdFdstatGet(const v8::FunctionCallbackInfo& args); + static void FdFdstatSetFlags(const v8::FunctionCallbackInfo& args); + static void FdFdstatSetRights( + const v8::FunctionCallbackInfo& args); + static void FdFilestatGet(const v8::FunctionCallbackInfo& args); + static void FdFilestatSetSize( + const v8::FunctionCallbackInfo& args); + static void FdFilestatSetTimes( + const v8::FunctionCallbackInfo& args); + static void FdPread(const v8::FunctionCallbackInfo& args); + static void FdPrestatGet(const v8::FunctionCallbackInfo& args); + static void FdPrestatDirName(const v8::FunctionCallbackInfo& args); + static void FdPwrite(const v8::FunctionCallbackInfo& args); + static void FdRead(const v8::FunctionCallbackInfo& args); + static void FdReaddir(const v8::FunctionCallbackInfo& args); + static void FdRenumber(const v8::FunctionCallbackInfo& args); + static void FdSeek(const v8::FunctionCallbackInfo& args); + static void FdSync(const v8::FunctionCallbackInfo& args); + static void FdTell(const v8::FunctionCallbackInfo& args); + static void FdWrite(const v8::FunctionCallbackInfo& args); + static void PathCreateDirectory( + const v8::FunctionCallbackInfo& args); + static void PathFilestatGet(const v8::FunctionCallbackInfo& args); + static void PathFilestatSetTimes( + const v8::FunctionCallbackInfo& args); + static void PathLink(const v8::FunctionCallbackInfo& args); + static void PathOpen(const v8::FunctionCallbackInfo& args); + static void PathReadlink(const v8::FunctionCallbackInfo& args); + static void PathRemoveDirectory( + const v8::FunctionCallbackInfo& args); + static void PathRename(const v8::FunctionCallbackInfo& args); + static void PathSymlink(const v8::FunctionCallbackInfo& args); + static void PathUnlinkFile(const v8::FunctionCallbackInfo& args); + static void PollOneoff(const v8::FunctionCallbackInfo& args); + static void ProcExit(const v8::FunctionCallbackInfo& args); + static void ProcRaise(const v8::FunctionCallbackInfo& args); + static void RandomGet(const v8::FunctionCallbackInfo& args); + static void SchedYield(const v8::FunctionCallbackInfo& args); + static void SockRecv(const v8::FunctionCallbackInfo& args); + static void SockSend(const v8::FunctionCallbackInfo& args); + static void SockShutdown(const v8::FunctionCallbackInfo& args); + + static void _SetMemory(const v8::FunctionCallbackInfo& args); + + private: + ~WASI() override; + inline void readUInt8(char* memory, uint8_t* value, uint32_t offset); + inline void readUInt16(char* memory, uint16_t* value, uint32_t offset); + inline void readUInt32(char* memory, uint32_t* value, uint32_t offset); + inline void readUInt64(char* memory, uint64_t* value, uint32_t offset); + inline void writeUInt8(char* memory, uint8_t value, uint32_t offset); + inline void writeUInt16(char* memory, uint16_t value, uint32_t offset); + inline void writeUInt32(char* memory, uint32_t value, uint32_t offset); + inline void writeUInt64(char* memory, uint64_t value, uint32_t offset); + uvwasi_errno_t backingStore(char** store, size_t* byte_length); + uvwasi_t uvw_; + v8::Global memory_; +}; + + +} // namespace wasi +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_NODE_WASI_H_ diff --git a/test/fixtures/outside.txt b/test/fixtures/outside.txt new file mode 100644 index 00000000000000..044c4b9614586d --- /dev/null +++ b/test/fixtures/outside.txt @@ -0,0 +1,2 @@ +this file is part of the WASI tests. it exists outside of the sandbox, and +should be inaccessible from the WASI tests. diff --git a/test/fixtures/wasi/input.txt b/test/fixtures/wasi/input.txt new file mode 100644 index 00000000000000..4c380537647f19 --- /dev/null +++ b/test/fixtures/wasi/input.txt @@ -0,0 +1 @@ +hello from input.txt diff --git a/test/fixtures/wasi/notadir b/test/fixtures/wasi/notadir new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/test/fixtures/wasi/simple-wasi.wasm b/test/fixtures/wasi/simple-wasi.wasm new file mode 100755 index 0000000000000000000000000000000000000000..334d3a3dcac6c09aade3babbc7a6f9a8a3ab6f16 GIT binary patch literal 15873 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 +#include +#include + +int main() { + FILE* file = fopen("/sandbox/../outside.txt", "r"); + assert(file == NULL); + assert(errno == ENOTCAPABLE); + + return 0; +} diff --git a/test/wasi/c/clock_getres.c b/test/wasi/c/clock_getres.c new file mode 100644 index 00000000000000..eaac02c665b9f2 --- /dev/null +++ b/test/wasi/c/clock_getres.c @@ -0,0 +1,17 @@ +#include +#include + +int main() { + struct timespec ts; + int r; + + // supported clocks + r = clock_getres(CLOCK_REALTIME, &ts); + assert(r == 0); + r = clock_getres(CLOCK_MONOTONIC, &ts); + assert(r == 0); + r = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts); + assert(r == 0); + r = clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts); + assert(r == 0); +} diff --git a/test/wasi/c/exitcode.c b/test/wasi/c/exitcode.c new file mode 100644 index 00000000000000..9c44b0de741a69 --- /dev/null +++ b/test/wasi/c/exitcode.c @@ -0,0 +1,3 @@ +int main() { + return 120; +} diff --git a/test/wasi/c/fd_prestat_get_refresh.c b/test/wasi/c/fd_prestat_get_refresh.c new file mode 100644 index 00000000000000..fb644ab49b208a --- /dev/null +++ b/test/wasi/c/fd_prestat_get_refresh.c @@ -0,0 +1,8 @@ +#include + +int main(void) { + isatty(1); + __builtin_wasm_memory_grow(0, 1); + isatty(1); + return 0; +} diff --git a/test/wasi/c/follow_symlink.c b/test/wasi/c/follow_symlink.c new file mode 100644 index 00000000000000..badb0ee2676bbe --- /dev/null +++ b/test/wasi/c/follow_symlink.c @@ -0,0 +1,14 @@ +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/input_link.txt", "r"); + assert(file != NULL); + + char c = fgetc(file); + while (c != EOF) { + int wrote = fputc(c, stdout); + assert(wrote != EOF); + c = fgetc(file); + } +} diff --git a/test/wasi/c/getentropy.c b/test/wasi/c/getentropy.c new file mode 100644 index 00000000000000..75547e1c474bba --- /dev/null +++ b/test/wasi/c/getentropy.c @@ -0,0 +1,18 @@ +#include +#include + +int main() { + char buf[256] = {0}; + int r = getentropy(buf, 256); + assert(r == 0); + + for (int i = 0; i < 256; i++) { + if (buf[i] != 0) { + return 0; + } + } + + // if this ever is reached, we either have a bug or should buy a lottery + // ticket + return 1; +} diff --git a/test/wasi/c/getrusage.c b/test/wasi/c/getrusage.c new file mode 100644 index 00000000000000..ad1e430b853395 --- /dev/null +++ b/test/wasi/c/getrusage.c @@ -0,0 +1,34 @@ +#include +#include + +int main() { + struct rusage ru1; + struct rusage ru2; + long long s1; + long long us1; + long long s2; + long long us2; + int r; + int success = 0; + + r = getrusage(RUSAGE_SELF, &ru1); + assert(r == 0); + s1 = ru1.ru_utime.tv_sec; + us1 = ru1.ru_utime.tv_usec; + + for (int i = 0; i < 10000; i++) { + r = getrusage(RUSAGE_SELF, &ru2); + assert(r == 0); + s2 = ru2.ru_utime.tv_sec; + us2 = ru2.ru_utime.tv_usec; + assert(s1 <= s2); + + // Verify that some time has passed. + if (s2 > s1 || (s2 == s1 && us2 > us1)) { + success = 1; + break; + } + } + + assert(success == 1); +} diff --git a/test/wasi/c/gettimeofday.c b/test/wasi/c/gettimeofday.c new file mode 100644 index 00000000000000..209a54e4983bfa --- /dev/null +++ b/test/wasi/c/gettimeofday.c @@ -0,0 +1,35 @@ +#include +#include +#include + +int main() { + struct timeval tv1; + struct timeval tv2; + long long s1; + long long us1; + long long s2; + long long us2; + int r; + int success = 0; + + r = gettimeofday(&tv1, NULL); + assert(r == 0); + s1 = tv1.tv_sec; + us1 = tv1.tv_usec; + + for (int i = 0; i < 10000; i++) { + r = gettimeofday(&tv2, NULL); + assert(r == 0); + s2 = tv2.tv_sec; + us2 = tv2.tv_usec; + assert(s1 <= s2); + + // Verify that some time has passed. + if (s2 > s1 || (s2 == s1 && us2 > us1)) { + success = 1; + break; + } + } + + assert(success == 1); +} diff --git a/test/wasi/c/notdir.c b/test/wasi/c/notdir.c new file mode 100644 index 00000000000000..03f369ffd3a862 --- /dev/null +++ b/test/wasi/c/notdir.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main() { + DIR* dir = opendir("/sandbox/notadir"); + assert(dir == NULL); + assert(errno == ENOTDIR); + + return 0; +} diff --git a/test/wasi/c/poll.c b/test/wasi/c/poll.c new file mode 100644 index 00000000000000..6b6ef71fd68c3b --- /dev/null +++ b/test/wasi/c/poll.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +int main(void) { + struct pollfd fds[2]; + time_t before, now; + int ret; + + fds[0] = (struct pollfd){.fd = 1, .events = POLLOUT, .revents = 0}; + fds[1] = (struct pollfd){.fd = 2, .events = POLLOUT, .revents = 0}; + + ret = poll(fds, 2, -1); + assert(ret == 2); + assert(fds[0].revents == POLLOUT); + assert(fds[1].revents == POLLOUT); + + fds[0] = (struct pollfd){.fd = 0, .events = POLLIN, .revents = 0}; + time(&before); + ret = poll(fds, 1, 2000); + time(&now); + assert(ret == 0); + assert(now - before >= 2); + + sleep(1); + time(&now); + assert(now - before >= 3); + + return 0; +} diff --git a/test/wasi/c/preopen_populates.c b/test/wasi/c/preopen_populates.c new file mode 100644 index 00000000000000..03b2213bb9a36c --- /dev/null +++ b/test/wasi/c/preopen_populates.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/test/wasi/c/read_file.c b/test/wasi/c/read_file.c new file mode 100644 index 00000000000000..40023e29e2727f --- /dev/null +++ b/test/wasi/c/read_file.c @@ -0,0 +1,14 @@ +#include +#include + +int main() { + FILE* file = fopen("/sandbox/input.txt", "r"); + assert(file != NULL); + + char c = fgetc(file); + while (c != EOF) { + int wrote = fputc(c, stdout); + assert(wrote != EOF); + c = fgetc(file); + } +} diff --git a/test/wasi/c/read_file_twice.c b/test/wasi/c/read_file_twice.c new file mode 100644 index 00000000000000..e295e38a3b3e13 --- /dev/null +++ b/test/wasi/c/read_file_twice.c @@ -0,0 +1,16 @@ +#include +#include + +int main() { + for (int i = 0; i < 2; i++) { + FILE* file = fopen("/sandbox/input.txt", "r"); + assert(file != NULL); + + char c = fgetc(file); + while (c != EOF) { + int wrote = fputc(c, stdout); + assert(wrote != EOF); + c = fgetc(file); + } + } +} diff --git a/test/wasi/c/stat.c b/test/wasi/c/stat.c new file mode 100644 index 00000000000000..fd3854937b9e6e --- /dev/null +++ b/test/wasi/c/stat.c @@ -0,0 +1,53 @@ +#include + +#include +#include +#include +#include + +#define BASE_DIR "/tmp" +#define OUTPUT_DIR BASE_DIR "/testdir" +#define PATH OUTPUT_DIR "/output.txt" +#define SIZE 500 + +int main(void) { + struct stat st; + int fd; + int ret; + off_t pos; + + (void)st; + ret = mkdir(OUTPUT_DIR, 0755); + assert(ret == 0); + + fd = open(PATH, O_CREAT | O_WRONLY, 0666); + assert(fd != -1); + + pos = lseek(fd, SIZE - 1, SEEK_SET); + assert(pos == SIZE - 1); + + ret = (int)write(fd, "", 1); + assert(ret == 1); + + ret = fstat(fd, &st); + assert(ret == 0); + assert(st.st_size == SIZE); + + ret = close(fd); + assert(ret == 0); + + ret = access(PATH, R_OK); + assert(ret == 0); + + ret = stat(PATH, &st); + assert(ret == 0); + assert(st.st_size == SIZE); + + ret = unlink(PATH); + assert(ret == 0); + + ret = stat(PATH, &st); + assert(ret == -1); + + return 0; +} diff --git a/test/wasi/c/stdin.c b/test/wasi/c/stdin.c new file mode 100644 index 00000000000000..5a81ea1265fb11 --- /dev/null +++ b/test/wasi/c/stdin.c @@ -0,0 +1,13 @@ +#include + +int main(void) { + char x[32]; + + if (fgets(x, sizeof x, stdin) == NULL) { + return ferror(stdin); + } + if (fputs(x, stdout) == EOF) { + return ferror(stdout); + } + return 0; +} diff --git a/test/wasi/c/symlink_escape.c b/test/wasi/c/symlink_escape.c new file mode 100644 index 00000000000000..32dcc64eebdc2b --- /dev/null +++ b/test/wasi/c/symlink_escape.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/outside.txt", "r"); + assert(file == NULL); + assert(errno == ENOTCAPABLE); +} diff --git a/test/wasi/c/symlink_loop.c b/test/wasi/c/symlink_loop.c new file mode 100644 index 00000000000000..23bd70ba601176 --- /dev/null +++ b/test/wasi/c/symlink_loop.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/loop1", "r"); + assert(file == NULL); + assert(errno == ELOOP); +} diff --git a/test/wasi/c/write_file.c b/test/wasi/c/write_file.c new file mode 100644 index 00000000000000..c4cf30cf2954cb --- /dev/null +++ b/test/wasi/c/write_file.c @@ -0,0 +1,15 @@ +#include +#include +#include + +static char* message = "hello, file!"; + +int main() { + FILE* file = fopen("/tmp/output.txt", "w"); + assert(file != NULL); + + int nwritten = fprintf(file, "%s", message); + assert(nwritten == strlen(message)); + int r = fclose(file); + assert(r == 0); +} diff --git a/test/wasi/test-wasi-binding.js b/test/wasi/test-wasi-binding.js new file mode 100644 index 00000000000000..876c8a15a72c13 --- /dev/null +++ b/test/wasi/test-wasi-binding.js @@ -0,0 +1,19 @@ +// Flags: --experimental-wasi-unstable-preview0 +'use strict'; + +const common = require('../common'); + +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const buffer = fixtures.readSync(['wasi', 'simple-wasi.wasm']); +const { WASI } = require('wasi'); +const wasi = new WASI({ args: [], env: process.env }); +const importObject = { + wasi_unstable: wasi.wasiImport +}; + +WebAssembly.instantiate(buffer, importObject) +.then(common.mustCall((results) => { + assert(results.instance.exports._start); + wasi.start(results.instance); +})); diff --git a/test/wasi/test-wasi-symlinks.js b/test/wasi/test-wasi-symlinks.js new file mode 100644 index 00000000000000..3829464198273b --- /dev/null +++ b/test/wasi/test-wasi-symlinks.js @@ -0,0 +1,78 @@ +'use strict'; +const common = require('../common'); +const fs = require('fs'); +const path = require('path'); + +if (process.argv[2] === 'wasi-child') { + common.expectWarning('ExperimentalWarning', + 'WASI is an experimental feature. This feature could ' + + 'change at any time'); + + const { WASI } = require('wasi'); + const wasmDir = path.join(__dirname, 'wasm'); + const wasi = new WASI({ + args: [], + env: process.env, + preopens: { + '/sandbox': process.argv[4] + } + }); + const importObject = { wasi_unstable: wasi.wasiImport }; + const modulePath = path.join(wasmDir, `${process.argv[3]}.wasm`); + const buffer = fs.readFileSync(modulePath); + + (async () => { + const { instance } = await WebAssembly.instantiate(buffer, importObject); + + wasi.start(instance); + })(); +} else { + if (!common.canCreateSymLink()) { + common.skip('insufficient privileges'); + } + + const assert = require('assert'); + const cp = require('child_process'); + const tmpdir = require('../../test/common/tmpdir'); + + // Setup the sandbox environment. + tmpdir.refresh(); + const sandbox = path.join(tmpdir.path, 'sandbox'); + const sandboxedFile = path.join(sandbox, 'input.txt'); + const externalFile = path.join(tmpdir.path, 'outside.txt'); + const sandboxedDir = path.join(sandbox, 'subdir'); + const sandboxedSymlink = path.join(sandboxedDir, 'input_link.txt'); + const escapingSymlink = path.join(sandboxedDir, 'outside.txt'); + const loopSymlink1 = path.join(sandboxedDir, 'loop1'); + const loopSymlink2 = path.join(sandboxedDir, 'loop2'); + + fs.mkdirSync(sandbox); + fs.mkdirSync(sandboxedDir); + fs.writeFileSync(sandboxedFile, 'hello from input.txt', 'utf8'); + fs.writeFileSync(externalFile, 'this should be inaccessible', 'utf8'); + fs.symlinkSync(sandboxedFile, sandboxedSymlink, 'file'); + fs.symlinkSync(externalFile, escapingSymlink, 'file'); + fs.symlinkSync(loopSymlink2, loopSymlink1, 'file'); + fs.symlinkSync(loopSymlink1, loopSymlink2, 'file'); + + function runWASI(options) { + console.log('executing', options.test); + const opts = { env: { ...process.env, NODE_DEBUG_NATIVE: 'wasi' } }; + const child = cp.spawnSync(process.execPath, [ + '--experimental-wasi-unstable-preview0', + '--experimental-wasm-bigint', + __filename, + 'wasi-child', + options.test, + sandbox + ], opts); + console.log(child.stderr.toString()); + assert.strictEqual(child.status, 0); + assert.strictEqual(child.signal, null); + assert.strictEqual(child.stdout.toString(), options.stdout || ''); + } + + runWASI({ test: 'follow_symlink', stdout: 'hello from input.txt' }); + runWASI({ test: 'symlink_escape' }); + runWASI({ test: 'symlink_loop' }); +} diff --git a/test/wasi/test-wasi.js b/test/wasi/test-wasi.js new file mode 100644 index 00000000000000..fa2e0894c906ce --- /dev/null +++ b/test/wasi/test-wasi.js @@ -0,0 +1,81 @@ +'use strict'; +const common = require('../common'); + +if (process.argv[2] === 'wasi-child') { + const fixtures = require('../common/fixtures'); + const tmpdir = require('../../test/common/tmpdir'); + const fs = require('fs'); + const path = require('path'); + + common.expectWarning('ExperimentalWarning', + 'WASI is an experimental feature. This feature could ' + + 'change at any time'); + + const { WASI } = require('wasi'); + tmpdir.refresh(); + const wasmDir = path.join(__dirname, 'wasm'); + const wasi = new WASI({ + args: [], + env: process.env, + preopens: { + '/sandbox': fixtures.path('wasi'), + '/tmp': tmpdir.path + } + }); + const importObject = { wasi_unstable: wasi.wasiImport }; + const modulePath = path.join(wasmDir, `${process.argv[3]}.wasm`); + const buffer = fs.readFileSync(modulePath); + + (async () => { + const { instance } = await WebAssembly.instantiate(buffer, importObject); + + wasi.start(instance); + })(); +} else { + const assert = require('assert'); + const cp = require('child_process'); + const { EOL } = require('os'); + + function runWASI(options) { + console.log('executing', options.test); + const opts = { env: { ...process.env, NODE_DEBUG_NATIVE: 'wasi' } }; + + if (options.stdin !== undefined) + opts.input = options.stdin; + + const child = cp.spawnSync(process.execPath, [ + '--experimental-wasi-unstable-preview0', + '--experimental-wasm-bigint', + __filename, + 'wasi-child', + options.test + ], opts); + console.log(child.stderr.toString()); + assert.strictEqual(child.status, options.exitCode || 0); + assert.strictEqual(child.signal, null); + assert.strictEqual(child.stdout.toString(), options.stdout || ''); + } + + runWASI({ test: 'cant_dotdot' }); + runWASI({ test: 'clock_getres' }); + runWASI({ test: 'exitcode', exitCode: 120 }); + runWASI({ test: 'fd_prestat_get_refresh' }); + runWASI({ test: 'getentropy' }); + runWASI({ test: 'getrusage' }); + runWASI({ test: 'gettimeofday' }); + runWASI({ test: 'notdir' }); + // runWASI({ test: 'poll' }); + runWASI({ test: 'preopen_populates' }); + runWASI({ test: 'read_file', stdout: `hello from input.txt${EOL}` }); + runWASI({ + test: 'read_file_twice', + stdout: `hello from input.txt${EOL}hello from input.txt${EOL}` + }); + runWASI({ test: 'stat' }); + runWASI({ test: 'write_file' }); + + // Tests that are currently unsupported on Windows. + if (!common.isWindows) { + runWASI({ test: 'stdin', stdin: 'hello world', stdout: 'hello world' }); + } +} diff --git a/test/wasi/testcfg.py b/test/wasi/testcfg.py new file mode 100644 index 00000000000000..ec6cbc5fe3dc3a --- /dev/null +++ b/test/wasi/testcfg.py @@ -0,0 +1,6 @@ +import sys, os +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +import testpy + +def GetConfiguration(context, root): + return testpy.ParallelTestConfiguration(context, root, 'wasi') diff --git a/test/wasi/wasi.status b/test/wasi/wasi.status new file mode 100644 index 00000000000000..12212e8f72822b --- /dev/null +++ b/test/wasi/wasi.status @@ -0,0 +1,7 @@ +prefix wasi + +# To mark a test as flaky, list the test name in the appropriate section +# below, without ".js", followed by ": PASS,FLAKY". Example: +# sample-test : PASS,FLAKY + +[true] # This section applies to all platforms diff --git a/test/wasi/wasm/cant_dotdot.wasm b/test/wasi/wasm/cant_dotdot.wasm new file mode 100755 index 0000000000000000000000000000000000000000..61e202d6913a3e000ecbd8978ce183df41f8e64f GIT binary patch literal 33007 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 J->)&w{{wP$&w>B| literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/clock_getres.wasm b/test/wasi/wasm/clock_getres.wasm new file mode 100755 index 0000000000000000000000000000000000000000..fac14edb04d794431f1b5a605af66af8c95c2949 GIT binary patch literal 30146 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 ogiscTh+}Z+;a$u? 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 GCGcOAZ1mFr literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/follow_symlink.wasm b/test/wasi/wasm/follow_symlink.wasm new file mode 100755 index 0000000000000000000000000000000000000000..48cf8da1eb28605e93a9611e394a0632b899c4ef GIT binary patch literal 34948 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 RdanPp$LdSB_W3Es`G5ZeZDRlc literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/getrusage.wasm b/test/wasi/wasm/getrusage.wasm new file mode 100755 index 0000000000000000000000000000000000000000..524e809175b5aafe5f8124ecf0d181eae03c8d99 GIT binary patch literal 30602 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 F{{sOI-^l;~ literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/gettimeofday.wasm b/test/wasi/wasm/gettimeofday.wasm new file mode 100755 index 0000000000000000000000000000000000000000..94627f00866903691760e8cfb59830d432c1978f GIT binary patch literal 30428 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 literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/read_file_twice.wasm b/test/wasi/wasm/read_file_twice.wasm new file mode 100755 index 0000000000000000000000000000000000000000..cd075a4de75a51b6921a665137bb4c04a1ec3a7b GIT binary patch literal 35018 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 literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/stat.wasm b/test/wasi/wasm/stat.wasm new file mode 100755 index 0000000000000000000000000000000000000000..9007334d37d1a166a9399975059aaf324bad1021 GIT binary patch literal 34507 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 literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/stdin.wasm b/test/wasi/wasm/stdin.wasm new file mode 100755 index 0000000000000000000000000000000000000000..7264608753229f610a0327453e49d0b0beb01ac3 GIT binary patch literal 18390 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 A_W%F@ literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/symlink_escape.wasm b/test/wasi/wasm/symlink_escape.wasm new file mode 100755 index 0000000000000000000000000000000000000000..0cdb8327a1a23b88c42ae305be21ba6832cc3c4f GIT binary patch literal 33026 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 OZ|(1H?f2`9^Zx)Dvf2ay literal 0 HcmV?d00001 diff --git a/test/wasi/wasm/symlink_loop.wasm b/test/wasi/wasm/symlink_loop.wasm new file mode 100755 index 0000000000000000000000000000000000000000..3883d5278c7008ad7053529111570c9ff7c8574e GIT binary patch literal 33009 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

4-Br(tI&644Analx#Se>nxXTWo6F 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 literal 0 HcmV?d00001 diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js index 0b9458351e6618..ef4499e50ff35a 100644 --- a/tools/doc/type-parser.js +++ b/tools/doc/type-parser.js @@ -18,7 +18,7 @@ const jsGlobalTypes = [ 'Array', 'ArrayBuffer', 'ArrayBufferView', 'DataView', 'Date', 'Error', 'EvalError', 'Function', 'Map', 'Object', 'Promise', 'RangeError', 'ReferenceError', 'RegExp', 'Set', 'SharedArrayBuffer', 'SyntaxError', - 'TypeError', 'TypedArray', 'URIError', 'Uint8Array', + 'TypeError', 'TypedArray', 'URIError', 'Uint8Array', 'WebAssembly.Instance', ]; const customTypesMap = { diff --git a/tools/license-builder.sh b/tools/license-builder.sh index 60f38e5cebf694..51c5b4d0c6a66d 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -108,4 +108,6 @@ addlicense "node-heapdump" "src/heap_utils.cc" \ addlicense "rimraf" "lib/internal/fs/rimraf.js" \ "$(curl -sL https://raw.githubusercontent.com/isaacs/rimraf/0e365ac4e4d64a25aa2a3cc026348f13410210e1/LICENSE)" +addlicense "uvwasi" "deps/uvwasi" "$(cat ${rootdir}/deps/uvwasi/LICENSE)" + mv $tmplicense $licensefile