wasi: introduce initial WASI support

Co-authored-by: Gus Caplan <me@gus.host>
Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
Co-authored-by: Jiawen Geng <technicalcute@gmail.com>
Co-authored-by: Tobias Nießen <tniessen@tnie.de>
Co-authored-by: Chengzhong Wu <legendecas@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/30258
Refs: https://github.com/nodejs/node/pull/27850
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Wyatt Preul <wpreul@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
cjihrig 2019-09-04 17:56:51 -04:00 committed by Anna Henningsen
parent 73c837b1ae
commit 09b1228c3a
No known key found for this signature in database
GPG key ID: 9C63F3A6CD2AD8F9
84 changed files with 12753 additions and 4 deletions

25
LICENSE
View file

@ -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.
"""

21
deps/uvwasi/LICENSE vendored Normal file
View file

@ -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.

13
deps/uvwasi/include/clocks.h vendored Normal file
View file

@ -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__ */

60
deps/uvwasi/include/fd_table.h vendored Normal file
View file

@ -0,0 +1,60 @@
#ifndef __UVWASI_FD_TABLE_H__
#define __UVWASI_FD_TABLE_H__
#include <stdint.h>
#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 <limits.h>
# 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__ */

15
deps/uvwasi/include/uv_mapping.h vendored Normal file
View file

@ -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__ */

252
deps/uvwasi/include/uvwasi.h vendored Normal file
View file

@ -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__ */

323
deps/uvwasi/include/wasi_types.h vendored Normal file
View file

@ -0,0 +1,323 @@
#ifndef __UVWASI_WASI_TYPES_H__
#define __UVWASI_WASI_TYPES_H__
#include <stddef.h>
#include <stdint.h>
/* 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__ */

194
deps/uvwasi/src/clocks.c vendored Normal file
View file

@ -0,0 +1,194 @@
#ifndef _WIN32
# include <errno.h>
# include <sys/time.h>
# include <sys/resource.h>
# include <time.h>
#endif /* _WIN32 */
#include "uv.h"
#include "wasi_types.h"
#include "uv_mapping.h"
#define UVWASI__WIN_TIME_AND_RETURN(handle, time) \
do { \
FILETIME create; \
FILETIME exit; \
FILETIME system; \
FILETIME user; \
SYSTEMTIME sys_system; \
SYSTEMTIME sys_user; \
if (0 == GetProcessTimes((handle), &create, &exit, &system, &user)) { \
return uvwasi__translate_uv_error( \
uv_translate_sys_error(GetLastError()) \
); \
} \
\
if (0 == FileTimeToSystemTime(&system, &sys_system)) { \
return uvwasi__translate_uv_error( \
uv_translate_sys_error(GetLastError()) \
); \
} \
\
if (0 == FileTimeToSystemTime(&user, &sys_user)) { \
return uvwasi__translate_uv_error( \
uv_translate_sys_error(GetLastError()) \
); \
} \
\
(time) = (((sys_system.wHour * 3600) + (sys_system.wMinute * 60) + \
sys_system.wSecond) * NANOS_PER_SEC) + \
(sys_system.wMilliseconds * 1000000) + \
(((sys_user.wHour * 3600) + (sys_user.wMinute * 60) + \
sys_user.wSecond) * NANOS_PER_SEC) + \
(sys_user.wMilliseconds * 1000000); \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__CLOCK_GETTIME_AND_RETURN(clk, time) \
do { \
struct timespec ts; \
if (0 != clock_gettime((clk), &ts)) \
return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
(time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__GETRUSAGE_AND_RETURN(who, time) \
do { \
struct rusage ru; \
if (0 != getrusage((who), &ru)) \
return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
(time) = (ru.ru_utime.tv_sec * NANOS_PER_SEC) + \
(ru.ru_utime.tv_usec * 1000) + \
(ru.ru_stime.tv_sec * NANOS_PER_SEC) + \
(ru.ru_stime.tv_usec * 1000); \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__OSX_THREADTIME_AND_RETURN(time) \
do { \
mach_port_t thread; \
thread_basic_info_data_t info; \
mach_msg_type_number_t count; \
count = THREAD_BASIC_INFO_COUNT; \
thread = pthread_mach_thread_np(pthread_self()); \
if (KERN_SUCCESS != thread_info(thread, \
THREAD_BASIC_INFO, \
(thread_info_t) &info, \
&count)) { \
return UVWASI_ENOSYS; \
} \
(time) = (info.user_time.seconds * NANOS_PER_SEC) + \
(info.user_time.microseconds * 1000) + \
(info.system_time.seconds * NANOS_PER_SEC) + \
(info.system_time.microseconds * 1000); \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__WIN_GETRES_AND_RETURN(time) \
do { \
/* The GetProcessTimes() docs claim a resolution of 100 ns. */ \
(time) = 100; \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__CLOCK_GETRES_AND_RETURN(clk, time) \
do { \
struct timespec ts; \
/* Try calling clock_getres(). If it doesn't succeed, then default to \
1000000. We implement all of the clocks, and some platforms (such as \
SmartOS) don't support all of the clocks, even though they define \
the constants for them. */ \
if (0 != clock_getres((clk), &ts)) \
(time) = 1000000; \
else \
(time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
return UVWASI_ESUCCESS; \
} while (0)
#define UVWASI__SLOW_GETRES_AND_RETURN(time) \
do { \
/* Assume a "worst case" of 1000000 ns resolution. */ \
(time) = 1000000; \
return UVWASI_ESUCCESS; \
} while (0)
uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time) {
uv_timeval64_t tv;
int r;
r = uv_gettimeofday(&tv);
if (r != 0)
return uvwasi__translate_uv_error(r);
*time = (tv.tv_sec * NANOS_PER_SEC) + (tv.tv_usec * 1000);
return UVWASI_ESUCCESS;
}
uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time) {
#if defined(_WIN32)
UVWASI__WIN_TIME_AND_RETURN(GetCurrentProcess(), *time);
#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
!defined(__APPLE__) && \
!defined(__sun)
UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
#else
UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_SELF, *time);
#endif
}
uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time) {
#if defined(_WIN32)
UVWASI__WIN_TIME_AND_RETURN(GetCurrentThread(), *time);
#elif defined(__APPLE__)
UVWASI__OSX_THREADTIME_AND_RETURN(*time);
#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
#else
# if defined(RUSAGE_LWP)
UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_LWP, *time);
# elif defined(RUSAGE_THREAD)
UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_THREAD, *time);
# else
return UVWASI_ENOSYS;
# endif /* RUSAGE_LWP */
#endif
}
uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time) {
#if defined(_WIN32)
UVWASI__WIN_GETRES_AND_RETURN(*time);
#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
!defined(__APPLE__) && \
!defined(__sun)
UVWASI__CLOCK_GETRES_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
#else
UVWASI__SLOW_GETRES_AND_RETURN(*time);
#endif
}
uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time) {
#if defined(_WIN32)
UVWASI__WIN_GETRES_AND_RETURN(*time);
#elif defined(__APPLE__)
UVWASI__SLOW_GETRES_AND_RETURN(*time);
#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
#elif defined(RUSAGE_THREAD) || defined(RUSAGE_LWP)
UVWASI__SLOW_GETRES_AND_RETURN(*time);
#else
return UVWASI_ENOSYS;
#endif
}

422
deps/uvwasi/src/fd_table.c vendored Normal file
View file

@ -0,0 +1,422 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#ifndef _WIN32
# include <sys/types.h>
#endif /* _WIN32 */
#include "uv.h"
#include "fd_table.h"
#include "wasi_types.h"
#include "uv_mapping.h"
#define UVWASI__RIGHTS_ALL (UVWASI_RIGHT_FD_DATASYNC | \
UVWASI_RIGHT_FD_READ | \
UVWASI_RIGHT_FD_SEEK | \
UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
UVWASI_RIGHT_FD_SYNC | \
UVWASI_RIGHT_FD_TELL | \
UVWASI_RIGHT_FD_WRITE | \
UVWASI_RIGHT_FD_ADVISE | \
UVWASI_RIGHT_FD_ALLOCATE | \
UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \
UVWASI_RIGHT_PATH_CREATE_FILE | \
UVWASI_RIGHT_PATH_LINK_SOURCE | \
UVWASI_RIGHT_PATH_LINK_TARGET | \
UVWASI_RIGHT_PATH_OPEN | \
UVWASI_RIGHT_FD_READDIR | \
UVWASI_RIGHT_PATH_READLINK | \
UVWASI_RIGHT_PATH_RENAME_SOURCE | \
UVWASI_RIGHT_PATH_RENAME_TARGET | \
UVWASI_RIGHT_PATH_FILESTAT_GET | \
UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \
UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
UVWASI_RIGHT_FD_FILESTAT_GET | \
UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \
UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \
UVWASI_RIGHT_PATH_SYMLINK | \
UVWASI_RIGHT_PATH_UNLINK_FILE | \
UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \
UVWASI_RIGHT_POLL_FD_READWRITE | \
UVWASI_RIGHT_SOCK_SHUTDOWN)
#define UVWASI__RIGHTS_BLOCK_DEVICE_BASE UVWASI__RIGHTS_ALL
#define UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING UVWASI__RIGHTS_ALL
#define UVWASI__RIGHTS_CHARACTER_DEVICE_BASE UVWASI__RIGHTS_ALL
#define UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING UVWASI__RIGHTS_ALL
#define UVWASI__RIGHTS_REGULAR_FILE_BASE (UVWASI_RIGHT_FD_DATASYNC | \
UVWASI_RIGHT_FD_READ | \
UVWASI_RIGHT_FD_SEEK | \
UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
UVWASI_RIGHT_FD_SYNC | \
UVWASI_RIGHT_FD_TELL | \
UVWASI_RIGHT_FD_WRITE | \
UVWASI_RIGHT_FD_ADVISE | \
UVWASI_RIGHT_FD_ALLOCATE | \
UVWASI_RIGHT_FD_FILESTAT_GET | \
UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \
UVWASI_RIGHT_FD_FILESTAT_SET_TIMES |\
UVWASI_RIGHT_POLL_FD_READWRITE)
#define UVWASI__RIGHTS_REGULAR_FILE_INHERITING 0
#define UVWASI__RIGHTS_DIRECTORY_BASE (UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
UVWASI_RIGHT_FD_SYNC | \
UVWASI_RIGHT_FD_ADVISE | \
UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \
UVWASI_RIGHT_PATH_CREATE_FILE | \
UVWASI_RIGHT_PATH_LINK_SOURCE | \
UVWASI_RIGHT_PATH_LINK_TARGET | \
UVWASI_RIGHT_PATH_OPEN | \
UVWASI_RIGHT_FD_READDIR | \
UVWASI_RIGHT_PATH_READLINK | \
UVWASI_RIGHT_PATH_RENAME_SOURCE | \
UVWASI_RIGHT_PATH_RENAME_TARGET | \
UVWASI_RIGHT_PATH_FILESTAT_GET | \
UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \
UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
UVWASI_RIGHT_FD_FILESTAT_GET | \
UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \
UVWASI_RIGHT_PATH_SYMLINK | \
UVWASI_RIGHT_PATH_UNLINK_FILE | \
UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \
UVWASI_RIGHT_POLL_FD_READWRITE)
#define UVWASI__RIGHTS_DIRECTORY_INHERITING (UVWASI__RIGHTS_DIRECTORY_BASE | \
UVWASI__RIGHTS_REGULAR_FILE_BASE)
#define UVWASI__RIGHTS_SOCKET_BASE (UVWASI_RIGHT_FD_READ | \
UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
UVWASI_RIGHT_FD_WRITE | \
UVWASI_RIGHT_FD_FILESTAT_GET | \
UVWASI_RIGHT_POLL_FD_READWRITE | \
UVWASI_RIGHT_SOCK_SHUTDOWN)
#define UVWASI__RIGHTS_SOCKET_INHERITING UVWASI__RIGHTS_ALL;
#define UVWASI__RIGHTS_TTY_BASE (UVWASI_RIGHT_FD_READ | \
UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
UVWASI_RIGHT_FD_WRITE | \
UVWASI_RIGHT_FD_FILESTAT_GET | \
UVWASI_RIGHT_POLL_FD_READWRITE)
#define UVWASI__RIGHTS_TTY_INHERITING 0
static uvwasi_errno_t uvwasi__get_type_and_rights(uv_file fd,
int flags,
uvwasi_filetype_t* type,
uvwasi_rights_t* rights_base,
uvwasi_rights_t* rights_inheriting) {
uv_fs_t req;
uvwasi_filetype_t filetype;
int read_or_write_only;
int r;
r = uv_fs_fstat(NULL, &req, fd, NULL);
filetype = uvwasi__stat_to_filetype(&req.statbuf);
uv_fs_req_cleanup(&req);
if (r != 0)
return uvwasi__translate_uv_error(r);
*type = filetype;
switch (filetype) {
case UVWASI_FILETYPE_REGULAR_FILE:
*rights_base = UVWASI__RIGHTS_REGULAR_FILE_BASE;
*rights_inheriting = UVWASI__RIGHTS_REGULAR_FILE_INHERITING;
break;
case UVWASI_FILETYPE_DIRECTORY:
*rights_base = UVWASI__RIGHTS_DIRECTORY_BASE;
*rights_inheriting = UVWASI__RIGHTS_DIRECTORY_INHERITING;
break;
/* uvwasi__stat_to_filetype() cannot differentiate socket types. It only
returns UVWASI_FILETYPE_SOCKET_STREAM. */
case UVWASI_FILETYPE_SOCKET_STREAM:
if (uv_guess_handle(fd) == UV_UDP)
*type = UVWASI_FILETYPE_SOCKET_DGRAM;
*rights_base = UVWASI__RIGHTS_SOCKET_BASE;
*rights_inheriting = UVWASI__RIGHTS_SOCKET_INHERITING;
break;
case UVWASI_FILETYPE_CHARACTER_DEVICE:
if (uv_guess_handle(fd) == UV_TTY) {
*rights_base = UVWASI__RIGHTS_TTY_BASE;
*rights_inheriting = UVWASI__RIGHTS_TTY_INHERITING;
} else {
*rights_base = UVWASI__RIGHTS_CHARACTER_DEVICE_BASE;
*rights_inheriting = UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING;
}
break;
case UVWASI_FILETYPE_BLOCK_DEVICE:
*rights_base = UVWASI__RIGHTS_BLOCK_DEVICE_BASE;
*rights_inheriting = UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING;
break;
default:
*rights_base = 0;
*rights_inheriting = 0;
}
if (*type == UVWASI_FILETYPE_UNKNOWN)
return UVWASI_EINVAL;
/* Disable read/write bits depending on access mode. */
read_or_write_only = flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
if (read_or_write_only == UV_FS_O_RDONLY)
*rights_base &= ~UVWASI_RIGHT_FD_WRITE;
else if (read_or_write_only == UV_FS_O_WRONLY)
*rights_base &= ~UVWASI_RIGHT_FD_READ;
return UVWASI_ESUCCESS;
}
static uvwasi_errno_t uvwasi__fd_table_insert(struct uvwasi_fd_table_t* table,
uv_file fd,
const char* mapped_path,
const char* real_path,
uvwasi_filetype_t type,
uvwasi_rights_t rights_base,
uvwasi_rights_t rights_inheriting,
int preopen,
struct uvwasi_fd_wrap_t** wrap) {
struct uvwasi_fd_wrap_t* entry;
struct uvwasi_fd_wrap_t* new_fds;
uint32_t new_size;
int index;
uint32_t i;
/* Check that there is room for a new item. If there isn't, grow the table. */
if (table->used >= table->size) {
new_size = table->size * 2;
new_fds = realloc(table->fds, new_size * sizeof(*new_fds));
if (new_fds == NULL)
return UVWASI_ENOMEM;
for (i = table->size; i < new_size; ++i)
new_fds[i].valid = 0;
index = table->size;
table->fds = new_fds;
table->size = new_size;
} else {
/* The table is big enough, so find an empty slot for the new data. */
index = -1;
for (i = 0; i < table->size; ++i) {
if (table->fds[i].valid != 1) {
index = i;
break;
}
}
/* index should never be -1. */
if (index == -1)
return UVWASI_ENOSPC;
}
entry = &table->fds[index];
entry->id = index;
entry->fd = fd;
strcpy(entry->path, mapped_path);
strcpy(entry->real_path, real_path);
entry->type = type;
entry->rights_base = rights_base;
entry->rights_inheriting = rights_inheriting;
entry->preopen = preopen;
entry->valid = 1;
table->used++;
if (wrap != NULL)
*wrap = entry;
return UVWASI_ESUCCESS;
}
uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_fd_table_t* table,
uint32_t init_size) {
struct uvwasi_fd_wrap_t* wrap;
uvwasi_filetype_t type;
uvwasi_rights_t base;
uvwasi_rights_t inheriting;
uvwasi_errno_t err;
uvwasi_fd_t i;
/* Require an initial size of at least three to store the stdio FDs. */
if (table == NULL || init_size < 3)
return UVWASI_EINVAL;
table->used = 0;
table->size = init_size;
table->fds = calloc(init_size, sizeof(struct uvwasi_fd_wrap_t));
if (table->fds == NULL)
return UVWASI_ENOMEM;
/* Create the stdio FDs. */
for (i = 0; i < 3; ++i) {
err = uvwasi__get_type_and_rights(i,
UV_FS_O_RDWR,
&type,
&base,
&inheriting);
if (err != UVWASI_ESUCCESS)
goto error_exit;
err = uvwasi__fd_table_insert(table,
i,
"",
"",
type,
base,
inheriting,
0,
&wrap);
if (err != UVWASI_ESUCCESS)
goto error_exit;
if (wrap->id != i || wrap->id != (uvwasi_fd_t) wrap->fd) {
err = UVWASI_EBADF;
goto error_exit;
}
}
return UVWASI_ESUCCESS;
error_exit:
uvwasi_fd_table_free(table);
return err;
}
void uvwasi_fd_table_free(struct uvwasi_fd_table_t* table) {
if (table == NULL)
return;
free(table->fds);
table->fds = NULL;
table->size = 0;
table->used = 0;
}
uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_fd_table_t* table,
const uv_file fd,
const char* path,
const char* real_path) {
uvwasi_filetype_t type;
uvwasi_rights_t base;
uvwasi_rights_t inheriting;
uvwasi_errno_t err;
if (table == NULL || path == NULL || real_path == NULL)
return UVWASI_EINVAL;
err = uvwasi__get_type_and_rights(fd, 0, &type, &base, &inheriting);
if (err != UVWASI_ESUCCESS)
return err;
if (type != UVWASI_FILETYPE_DIRECTORY)
return UVWASI_ENOTDIR;
err = uvwasi__fd_table_insert(table,
fd,
path,
real_path,
UVWASI_FILETYPE_DIRECTORY,
UVWASI__RIGHTS_DIRECTORY_BASE,
UVWASI__RIGHTS_DIRECTORY_INHERITING,
1,
NULL);
if (err != UVWASI_ESUCCESS)
return err;
return UVWASI_ESUCCESS;
}
uvwasi_errno_t uvwasi_fd_table_insert_fd(struct uvwasi_fd_table_t* table,
const uv_file fd,
const int flags,
const char* path,
uvwasi_rights_t rights_base,
uvwasi_rights_t rights_inheriting,
struct uvwasi_fd_wrap_t* wrap) {
struct uvwasi_fd_wrap_t* fd_wrap;
uvwasi_filetype_t type;
uvwasi_rights_t max_base;
uvwasi_rights_t max_inheriting;
uvwasi_errno_t r;
if (table == NULL || path == NULL || wrap == NULL)
return UVWASI_EINVAL;
r = uvwasi__get_type_and_rights(fd, flags, &type, &max_base, &max_inheriting);
if (r != UVWASI_ESUCCESS)
return r;
r = uvwasi__fd_table_insert(table,
fd,
path,
path,
type,
rights_base & max_base,
rights_inheriting & max_inheriting,
0,
&fd_wrap);
if (r != UVWASI_ESUCCESS)
return r;
*wrap = *fd_wrap;
return UVWASI_ESUCCESS;
}
uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table,
const uvwasi_fd_t id,
struct uvwasi_fd_wrap_t** wrap,
uvwasi_rights_t rights_base,
uvwasi_rights_t rights_inheriting) {
struct uvwasi_fd_wrap_t* entry;
if (table == NULL || wrap == NULL)
return UVWASI_EINVAL;
if (id >= table->size)
return UVWASI_EBADF;
entry = &table->fds[id];
if (entry->valid != 1 || entry->id != id)
return UVWASI_EBADF;
/* Validate that the fd has the necessary rights. */
if ((~entry->rights_base & rights_base) != 0 ||
(~entry->rights_inheriting & rights_inheriting) != 0)
return UVWASI_ENOTCAPABLE;
*wrap = entry;
return UVWASI_ESUCCESS;
}
uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_fd_table_t* table,
const uvwasi_fd_t id) {
struct uvwasi_fd_wrap_t* entry;
if (table == NULL)
return UVWASI_EINVAL;
if (id >= table->size)
return UVWASI_EBADF;
entry = &table->fds[id];
if (entry->valid != 1 || entry->id != id)
return UVWASI_EBADF;
entry->valid = 0;
table->used--;
return UVWASI_ESUCCESS;
}

243
deps/uvwasi/src/uv_mapping.c vendored Normal file
View file

@ -0,0 +1,243 @@
#include <sys/stat.h>
#ifndef _WIN32
# include <sys/types.h>
#endif /* _WIN32 */
#include "uv.h"
#include "wasi_types.h"
#include "uv_mapping.h"
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
#if !defined(S_ISCHR) && defined(S_IFMT) && defined(S_IFCHR)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif
#if !defined(S_ISLNK) && defined(S_IFMT) && defined(S_IFLNK)
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif
uvwasi_errno_t uvwasi__translate_uv_error(int err) {
switch (err) {
case UV_E2BIG: return UVWASI_E2BIG;
case UV_EACCES: return UVWASI_EACCES;
case UV_EADDRINUSE: return UVWASI_EADDRINUSE;
case UV_EADDRNOTAVAIL: return UVWASI_EADDRNOTAVAIL;
case UV_EAFNOSUPPORT: return UVWASI_EAFNOSUPPORT;
case UV_EAGAIN: return UVWASI_EAGAIN;
case UV_EALREADY: return UVWASI_EALREADY;
case UV_EBADF: return UVWASI_EBADF;
case UV_EBUSY: return UVWASI_EBUSY;
case UV_ECANCELED: return UVWASI_ECANCELED;
case UV_ECONNABORTED: return UVWASI_ECONNABORTED;
case UV_ECONNREFUSED: return UVWASI_ECONNREFUSED;
case UV_ECONNRESET: return UVWASI_ECONNRESET;
case UV_EDESTADDRREQ: return UVWASI_EDESTADDRREQ;
case UV_EEXIST: return UVWASI_EEXIST;
case UV_EFAULT: return UVWASI_EFAULT;
case UV_EFBIG: return UVWASI_EFBIG;
case UV_EHOSTUNREACH: return UVWASI_EHOSTUNREACH;
case UV_EINTR: return UVWASI_EINTR;
case UV_EINVAL: return UVWASI_EINVAL;
case UV_EIO: return UVWASI_EIO;
case UV_EISCONN: return UVWASI_EISCONN;
case UV_EISDIR: return UVWASI_EISDIR;
case UV_ELOOP: return UVWASI_ELOOP;
case UV_EMFILE: return UVWASI_EMFILE;
case UV_EMLINK: return UVWASI_EMLINK;
case UV_EMSGSIZE: return UVWASI_EMSGSIZE;
case UV_ENAMETOOLONG: return UVWASI_ENAMETOOLONG;
case UV_ENETDOWN: return UVWASI_ENETDOWN;
case UV_ENETUNREACH: return UVWASI_ENETUNREACH;
case UV_ENFILE: return UVWASI_ENFILE;
case UV_ENOBUFS: return UVWASI_ENOBUFS;
case UV_ENODEV: return UVWASI_ENODEV;
case UV_ENOENT: return UVWASI_ENOENT;
case UV_ENOMEM: return UVWASI_ENOMEM;
case UV_ENOPROTOOPT: return UVWASI_ENOPROTOOPT;
case UV_ENOSPC: return UVWASI_ENOSPC;
case UV_ENOSYS: return UVWASI_ENOSYS;
case UV_ENOTCONN: return UVWASI_ENOTCONN;
case UV_ENOTDIR: return UVWASI_ENOTDIR;
/* On at least some AIX machines, ENOTEMPTY and EEXIST are equivalent. */
#if ENOTEMPTY != EEXIST
case UV_ENOTEMPTY: return UVWASI_ENOTEMPTY;
#endif /* ENOTEMPTY != EEXIST */
case UV_ENOTSOCK: return UVWASI_ENOTSOCK;
case UV_ENOTSUP: return UVWASI_ENOTSUP;
case UV_ENXIO: return UVWASI_ENXIO;
case UV_EPERM: return UVWASI_EPERM;
case UV_EPIPE: return UVWASI_EPIPE;
case UV_EPROTO: return UVWASI_EPROTO;
case UV_EPROTONOSUPPORT: return UVWASI_EPROTONOSUPPORT;
case UV_EPROTOTYPE: return UVWASI_EPROTOTYPE;
case UV_ERANGE: return UVWASI_ERANGE;
case UV_EROFS: return UVWASI_EROFS;
case UV_ESPIPE: return UVWASI_ESPIPE;
case UV_ESRCH: return UVWASI_ESRCH;
case UV_ETIMEDOUT: return UVWASI_ETIMEDOUT;
case UV_ETXTBSY: return UVWASI_ETXTBSY;
case UV_EXDEV: return UVWASI_EXDEV;
case 0: return UVWASI_ESUCCESS;
/* The following libuv error codes have no corresponding WASI error code:
UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS, UV_EAI_BADHINTS,
UV_EAI_CANCELED, UV_EAI_FAIL, UV_EAI_FAMILY, UV_EAI_MEMORY,
UV_EAI_NODATA, UV_EAI_NONAME, UV_EAI_OVERFLOW, UV_EAI_PROTOCOL,
UV_EAI_SERVICE, UV_EAI_SOCKTYPE, UV_ECHARSET, UV_ENONET, UV_EOF,
UV_ESHUTDOWN, UV_UNKNOWN
*/
default:
/* libuv errors are < 0 */
if (err > 0)
return err;
return UVWASI_ENOSYS;
}
}
int uvwasi__translate_to_uv_signal(uvwasi_signal_t sig) {
switch (sig) {
#ifdef SIGABRT
case UVWASI_SIGABRT: return SIGABRT;
#endif
#ifdef SIGALRM
case UVWASI_SIGALRM: return SIGALRM;
#endif
#ifdef SIGBUS
case UVWASI_SIGBUS: return SIGBUS;
#endif
#ifdef SIGCHLD
case UVWASI_SIGCHLD: return SIGCHLD;
#endif
#ifdef SIGCONT
case UVWASI_SIGCONT: return SIGCONT;
#endif
#ifdef SIGFPE
case UVWASI_SIGFPE: return SIGFPE;
#endif
#ifdef SIGHUP
case UVWASI_SIGHUP: return SIGHUP;
#endif
#ifdef SIGILL
case UVWASI_SIGILL: return SIGILL;
#endif
#ifdef SIGINT
case UVWASI_SIGINT: return SIGINT;
#endif
#ifdef SIGKILL
case UVWASI_SIGKILL: return SIGKILL;
#endif
#ifdef SIGPIPE
case UVWASI_SIGPIPE: return SIGPIPE;
#endif
#ifdef SIGQUIT
case UVWASI_SIGQUIT: return SIGQUIT;
#endif
#ifdef SIGSEGV
case UVWASI_SIGSEGV: return SIGSEGV;
#endif
#ifdef SIGSTOP
case UVWASI_SIGSTOP: return SIGSTOP;
#endif
#ifdef SIGSYS
case UVWASI_SIGSYS: return SIGSYS;
#endif
#ifdef SIGTERM
case UVWASI_SIGTERM: return SIGTERM;
#endif
#ifdef SIGTRAP
case UVWASI_SIGTRAP: return SIGTRAP;
#endif
#ifdef SIGTSTP
case UVWASI_SIGTSTP: return SIGTSTP;
#endif
#ifdef SIGTTIN
case UVWASI_SIGTTIN: return SIGTTIN;
#endif
#ifdef SIGTTOU
case UVWASI_SIGTTOU: return SIGTTOU;
#endif
#ifdef SIGURG
case UVWASI_SIGURG: return SIGURG;
#endif
#ifdef SIGUSR1
case UVWASI_SIGUSR1: return SIGUSR1;
#endif
#ifdef SIGUSR2
case UVWASI_SIGUSR2: return SIGUSR2;
#endif
#ifdef SIGVTALRM
case UVWASI_SIGVTALRM: return SIGVTALRM;
#endif
#ifdef SIGXCPU
case UVWASI_SIGXCPU: return SIGXCPU;
#endif
#ifdef SIGXFSZ
case UVWASI_SIGXFSZ: return SIGXFSZ;
#endif
default: return -1;
}
}
uvwasi_timestamp_t uvwasi__timespec_to_timestamp(const uv_timespec_t* ts) {
/* TODO(cjihrig): Handle overflow. */
return (uvwasi_timestamp_t) ts->tv_sec * NANOS_PER_SEC + ts->tv_nsec;
}
uvwasi_filetype_t uvwasi__stat_to_filetype(const uv_stat_t* stat) {
uint64_t mode;
mode = stat->st_mode;
if (S_ISREG(mode))
return UVWASI_FILETYPE_REGULAR_FILE;
if (S_ISDIR(mode))
return UVWASI_FILETYPE_DIRECTORY;
if (S_ISCHR(mode))
return UVWASI_FILETYPE_CHARACTER_DEVICE;
if (S_ISLNK(mode))
return UVWASI_FILETYPE_SYMBOLIC_LINK;
#ifdef S_ISSOCK
if (S_ISSOCK(mode))
return UVWASI_FILETYPE_SOCKET_STREAM;
#endif /* S_ISSOCK */
#ifdef S_ISFIFO
if (S_ISFIFO(mode))
return UVWASI_FILETYPE_SOCKET_STREAM;
#endif /* S_ISFIFO */
#ifdef S_ISBLK
if (S_ISBLK(mode))
return UVWASI_FILETYPE_BLOCK_DEVICE;
#endif /* S_ISBLK */
return UVWASI_FILETYPE_UNKNOWN;
}
void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs) {
fs->st_dev = stat->st_dev;
fs->st_ino = stat->st_ino;
fs->st_nlink = stat->st_nlink;
fs->st_size = stat->st_size;
fs->st_filetype = uvwasi__stat_to_filetype(stat);
fs->st_atim = uvwasi__timespec_to_timestamp(&stat->st_atim);
fs->st_mtim = uvwasi__timespec_to_timestamp(&stat->st_mtim);
fs->st_ctim = uvwasi__timespec_to_timestamp(&stat->st_ctim);
}

1918
deps/uvwasi/src/uvwasi.c vendored Normal file

File diff suppressed because it is too large Load diff

25
deps/uvwasi/uvwasi.gyp vendored Normal file
View file

@ -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']
},
}
]
}

View file

@ -230,6 +230,13 @@ added: v9.6.0
Enable experimental ES Module support in the `vm` module.
### `--experimental-wasi-unstable-preview0`
<!-- YAML
added: REPLACEME
-->
Enable experimental WebAssembly System Interface (WASI) support.
### `--experimental-wasm-modules`
<!-- YAML
added: v12.3.0
@ -1048,6 +1055,7 @@ Node.js options that are allowed are:
* `--experimental-report`
* `--experimental-resolve-self`
* `--experimental-vm-modules`
* `--experimental-wasi-unstable-preview0`
* `--experimental-wasm-modules`
* `--force-context-aware`
* `--force-fips`

View file

@ -1992,6 +1992,11 @@ The fulfilled value of a linking promise is not a `vm.Module` object.
The current module's status does not allow for this operation. The specific
meaning of the error depends on the specific function.
<a id="ERR_WASI_ALREADY_STARTED"></a>
### ERR_WASI_ALREADY_STARTED
The WASI instance has already started.
<a id="ERR_WORKER_INVALID_EXEC_ARGV"></a>
### ERR_WORKER_INVALID_EXEC_ARGV

View file

@ -57,6 +57,7 @@
* [Utilities](util.html)
* [V8](v8.html)
* [VM](vm.html)
* [WASI](wasi.html)
* [Worker Threads](worker_threads.html)
* [Zlib](zlib.html)

90
doc/api/wasi.md Normal file
View file

@ -0,0 +1,90 @@
# WebAssembly System Interface (WASI)
<!--introduced_in=REPLACEME-->
> 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
<!-- YAML
added: REPLACEME
-->
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\])
<!-- YAML
added: REPLACEME
-->
* `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)
<!-- YAML
added: REPLACEME
-->
* `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
<!-- YAML
added: REPLACEME
-->
* {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/

View file

@ -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.
.

View file

@ -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.

View file

@ -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);

View file

@ -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();

105
lib/wasi.js Normal file
View file

@ -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 };

View file

@ -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' ],

View file

@ -1102,6 +1102,21 @@ inline void Environment::SetProtoMethodNoSideEffect(
t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility.
}
inline void Environment::SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
v8::Local<v8::FunctionTemplate> 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<v8::String> 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_++

View file

@ -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<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);
// Safe variants denote the function has no side effects.
inline void SetMethodNoSideEffect(v8::Local<v8::Object> that,
const char* name,

View file

@ -85,6 +85,7 @@
V(util) \
V(uv) \
V(v8) \
V(wasi) \
V(worker) \
V(zlib)

View file

@ -84,6 +84,9 @@ static void Initialize(Local<Object> 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

View file

@ -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",

View file

@ -151,6 +151,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;

1802
src/node_wasi.cc Normal file

File diff suppressed because it is too large Load diff

103
src/node_wasi.h Normal file
View file

@ -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<v8::Object> object,
uvwasi_options_t* options);
static void New(const v8::FunctionCallbackInfo<v8::Value>& 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<v8::Value>& args);
static void ArgsSizesGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ClockResGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ClockTimeGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EnvironGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EnvironSizesGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdAdvise(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdAllocate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdClose(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdDatasync(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFdstatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFdstatSetFlags(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFdstatSetRights(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFilestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFilestatSetSize(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdFilestatSetTimes(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdPread(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdPrestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdPrestatDirName(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdPwrite(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdRead(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdReaddir(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdRenumber(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdSeek(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdSync(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdTell(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FdWrite(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathCreateDirectory(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathFilestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathFilestatSetTimes(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathLink(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathOpen(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathReadlink(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathRemoveDirectory(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathRename(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathSymlink(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PathUnlinkFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PollOneoff(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ProcExit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ProcRaise(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RandomGet(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SchedYield(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SockRecv(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SockSend(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SockShutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
static void _SetMemory(const v8::FunctionCallbackInfo<v8::Value>& 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<v8::Object> memory_;
};
} // namespace wasi
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_WASI_H_

2
test/fixtures/outside.txt vendored Normal file
View file

@ -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.

1
test/fixtures/wasi/input.txt vendored Normal file
View file

@ -0,0 +1 @@
hello from input.txt

0
test/fixtures/wasi/notadir vendored Normal file
View file

BIN
test/fixtures/wasi/simple-wasi.wasm vendored Executable file

Binary file not shown.

6533
test/fixtures/wasi/simple-wasi.wat vendored Normal file

File diff suppressed because it is too large Load diff

1
test/fixtures/wasi/subdir/input_link.txt vendored Symbolic link
View file

@ -0,0 +1 @@
../input.txt

1
test/fixtures/wasi/subdir/loop1 vendored Symbolic link
View file

@ -0,0 +1 @@
./loop2

1
test/fixtures/wasi/subdir/loop2 vendored Symbolic link
View file

@ -0,0 +1 @@
./loop1

1
test/fixtures/wasi/subdir/outside.txt vendored Symbolic link
View file

@ -0,0 +1 @@
../../outside.txt

12
test/wasi/Makefile Normal file
View file

@ -0,0 +1,12 @@
CC = /opt/wasi-sdk/bin/clang
TARGET = wasm32-unknown-wasi
SYSROOT =
OBJ = $(patsubst c/%.c, wasm/%.wasm, $(wildcard c/*.c))
all: $(OBJ)
wasm/%.wasm : c/%.c
$(CC) $< --target=$(TARGET) --sysroot=$(SYSROOT) -s -o $@
.PHONY clean:
rm -f $(OBJ)

8
test/wasi/README.md Normal file
View file

@ -0,0 +1,8 @@
# WASI Tests
Compile with clang and `wasm32-wasi` target. The clang version used must be
built with wasi-libc. You can specify the location for clang and the sysroot
if needed when running make:
```console
$ make CC=/usr/local/opt/llvm/bin/clang SYSROOT=/path/to/wasi-libc/sysroot
```

11
test/wasi/c/cant_dotdot.c Normal file
View file

@ -0,0 +1,11 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
int main() {
FILE* file = fopen("/sandbox/../outside.txt", "r");
assert(file == NULL);
assert(errno == ENOTCAPABLE);
return 0;
}

View file

@ -0,0 +1,17 @@
#include <assert.h>
#include <time.h>
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);
}

3
test/wasi/c/exitcode.c Normal file
View file

@ -0,0 +1,3 @@
int main() {
return 120;
}

View file

@ -0,0 +1,8 @@
#include <unistd.h>
int main(void) {
isatty(1);
__builtin_wasm_memory_grow(0, 1);
isatty(1);
return 0;
}

View file

@ -0,0 +1,14 @@
#include <assert.h>
#include <stdio.h>
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);
}
}

18
test/wasi/c/getentropy.c Normal file
View file

@ -0,0 +1,18 @@
#include <assert.h>
#include <unistd.h>
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;
}

34
test/wasi/c/getrusage.c Normal file
View file

@ -0,0 +1,34 @@
#include <assert.h>
#include <sys/resource.h>
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);
}

View file

@ -0,0 +1,35 @@
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
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);
}

11
test/wasi/c/notdir.c Normal file
View file

@ -0,0 +1,11 @@
#include <assert.h>
#include <dirent.h>
#include <errno.h>
int main() {
DIR* dir = opendir("/sandbox/notadir");
assert(dir == NULL);
assert(errno == ENOTDIR);
return 0;
}

31
test/wasi/c/poll.c Normal file
View file

@ -0,0 +1,31 @@
#include <assert.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>
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;
}

View file

@ -0,0 +1,3 @@
int main(void) {
return 0;
}

14
test/wasi/c/read_file.c Normal file
View file

@ -0,0 +1,14 @@
#include <assert.h>
#include <stdio.h>
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);
}
}

View file

@ -0,0 +1,16 @@
#include <assert.h>
#include <stdio.h>
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);
}
}
}

53
test/wasi/c/stat.c Normal file
View file

@ -0,0 +1,53 @@
#include <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#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;
}

13
test/wasi/c/stdin.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdio.h>
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;
}

View file

@ -0,0 +1,9 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
int main() {
FILE* file = fopen("/sandbox/subdir/outside.txt", "r");
assert(file == NULL);
assert(errno == ENOTCAPABLE);
}

View file

@ -0,0 +1,9 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
int main() {
FILE* file = fopen("/sandbox/subdir/loop1", "r");
assert(file == NULL);
assert(errno == ELOOP);
}

15
test/wasi/c/write_file.c Normal file
View file

@ -0,0 +1,15 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
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);
}

View file

@ -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);
}));

View file

@ -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' });
}

81
test/wasi/test-wasi.js Normal file
View file

@ -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' });
}
}

6
test/wasi/testcfg.py Normal file
View file

@ -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')

7
test/wasi/wasi.status Normal file
View file

@ -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

BIN
test/wasi/wasm/cant_dotdot.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/clock_getres.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/exitcode.wasm Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
test/wasi/wasm/getentropy.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/getrusage.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/gettimeofday.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/notdir.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/poll.wasm Executable file

Binary file not shown.

Binary file not shown.

BIN
test/wasi/wasm/read_file.wasm Executable file

Binary file not shown.

Binary file not shown.

BIN
test/wasi/wasm/stat.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/stdin.wasm Executable file

Binary file not shown.

Binary file not shown.

BIN
test/wasi/wasm/symlink_loop.wasm Executable file

Binary file not shown.

BIN
test/wasi/wasm/write_file.wasm Executable file

Binary file not shown.

View file

@ -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 = {

View file

@ -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