From c13ff70a6031b17bce481571db6bb0a6622ae400 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Aug 2020 12:50:53 -0400 Subject: [PATCH 1/2] deps: update to uvwasi 0.0.10 Notable changes: - The uvwasi_preopen_t now uses const char* for the mapped_path and real_path fields. Previously, these were not `const`. - uvwasi_path_filestat_get() now properly handles the UVWASI_LOOKUP_SYMLINK_FOLLOW flag. - uvwasi_options_init() has been added to reduce the boilerplate code associated with initializing uvwasi_options_t's. - The DEBUG() macro has been renamed to UVWASI_DEBUG() to reduce naming conflicts with other projects. - A compilation error on NetBSD 8.2 has been fixed. - The uvwasi_fd_filestat_set_times() and uvwasi_path_filestat_set_times() functions now have proper implementations. Fixes: /~https://github.com/nodejs/node/issues/34510 --- deps/uvwasi/include/uvwasi.h | 7 +- deps/uvwasi/include/wasi_serdes.h | 14 +- deps/uvwasi/src/debug.h | 6 +- deps/uvwasi/src/uvwasi.c | 610 ++++++++++++++++++------------ src/node_wasi.cc | 6 +- 5 files changed, 387 insertions(+), 256 deletions(-) diff --git a/deps/uvwasi/include/uvwasi.h b/deps/uvwasi/include/uvwasi.h index 0090313c8af2eb..9a0f8aa3c61711 100644 --- a/deps/uvwasi/include/uvwasi.h +++ b/deps/uvwasi/include/uvwasi.h @@ -10,7 +10,7 @@ extern "C" { #define UVWASI_VERSION_MAJOR 0 #define UVWASI_VERSION_MINOR 0 -#define UVWASI_VERSION_PATCH 9 +#define UVWASI_VERSION_PATCH 10 #define UVWASI_VERSION_HEX ((UVWASI_VERSION_MAJOR << 16) | \ (UVWASI_VERSION_MINOR << 8) | \ (UVWASI_VERSION_PATCH)) @@ -50,8 +50,8 @@ typedef struct uvwasi_s { } uvwasi_t; typedef struct uvwasi_preopen_s { - char* mapped_path; - char* real_path; + const char* mapped_path; + const char* real_path; } uvwasi_preopen_t; typedef struct uvwasi_options_s { @@ -70,6 +70,7 @@ typedef struct uvwasi_options_s { /* Embedder API. */ uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, uvwasi_options_t* options); void uvwasi_destroy(uvwasi_t* uvwasi); +void uvwasi_options_init(uvwasi_options_t* options); /* Use int instead of uv_file to avoid needing uv.h */ uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi, const uvwasi_fd_t fd, diff --git a/deps/uvwasi/include/wasi_serdes.h b/deps/uvwasi/include/wasi_serdes.h index f927b82bac9cbc..ed80e4a88e6ee4 100644 --- a/deps/uvwasi/include/wasi_serdes.h +++ b/deps/uvwasi/include/wasi_serdes.h @@ -5,21 +5,20 @@ /* Basic uint{8,16,32,64}_t read/write functions. */ -#define BASIC_TYPE_(name, type) \ +#define BASIC_TYPE(name, type) \ void uvwasi_serdes_write_##name(void* ptr, size_t offset, type value); \ type uvwasi_serdes_read_##name(const void* ptr, size_t offset); \ -#define BASIC_TYPE(type) BASIC_TYPE_(type, type) -#define BASIC_TYPE_UVWASI(type) BASIC_TYPE_(type, uvwasi_##type) +#define BASIC_TYPE_UVWASI(type) BASIC_TYPE(type, uvwasi_##type) #define UVWASI_SERDES_SIZE_uint8_t sizeof(uint8_t) -BASIC_TYPE(uint8_t) +BASIC_TYPE(uint8_t, uint8_t) #define UVWASI_SERDES_SIZE_uint16_t sizeof(uint16_t) -BASIC_TYPE(uint16_t) +BASIC_TYPE(uint16_t, uint16_t) #define UVWASI_SERDES_SIZE_uint32_t sizeof(uint32_t) -BASIC_TYPE(uint32_t) +BASIC_TYPE(uint32_t, uint32_t) #define UVWASI_SERDES_SIZE_uint64_t sizeof(uint64_t) -BASIC_TYPE(uint64_t) +BASIC_TYPE(uint64_t, uint64_t) #define UVWASI_SERDES_SIZE_advice_t sizeof(uvwasi_advice_t) BASIC_TYPE_UVWASI(advice_t) @@ -80,7 +79,6 @@ BASIC_TYPE_UVWASI(whence_t) #undef BASIC_TYPE_UVWASI #undef BASIC_TYPE -#undef BASIC_TYPE_ /* WASI structure read/write functions. */ diff --git a/deps/uvwasi/src/debug.h b/deps/uvwasi/src/debug.h index 16bc2732ec90cd..8ef5a99a231518 100644 --- a/deps/uvwasi/src/debug.h +++ b/deps/uvwasi/src/debug.h @@ -2,12 +2,14 @@ #define __UVWASI_DEBUG_H__ #ifdef UVWASI_DEBUG_LOG +#ifndef __STDC_FORMAT_MACROS # define __STDC_FORMAT_MACROS +#endif # include -# define DEBUG(fmt, ...) \ +# define UVWASI_DEBUG(fmt, ...) \ do { fprintf(stderr, fmt, __VA_ARGS__); } while (0) #else -# define DEBUG(fmt, ...) +# define UVWASI_DEBUG(fmt, ...) #endif #endif /* __UVWASI_DEBUG_H__ */ diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c index fc8f0ee4844b9e..acc25c3dba2f73 100644 --- a/deps/uvwasi/src/uvwasi.c +++ b/deps/uvwasi/src/uvwasi.c @@ -29,6 +29,78 @@ # undef POSIX_FADV_NORMAL #endif +#define VALIDATE_FSTFLAGS_OR_RETURN(flags) \ + do { \ + if ((flags) & ~(UVWASI_FILESTAT_SET_ATIM | \ + UVWASI_FILESTAT_SET_ATIM_NOW | \ + UVWASI_FILESTAT_SET_MTIM | \ + UVWASI_FILESTAT_SET_MTIM_NOW)) { \ + return UVWASI_EINVAL; \ + } \ + } while (0) + +static uvwasi_errno_t uvwasi__get_filestat_set_times( + uvwasi_timestamp_t* st_atim, + uvwasi_timestamp_t* st_mtim, + uvwasi_fstflags_t fst_flags, + uv_file* fd, + char* path + ) { + uvwasi_filestat_t stat; + uvwasi_timestamp_t now; + uvwasi_errno_t err; + uv_fs_t req; + int r; + + /* Check if either value requires the current time. */ + if ((fst_flags & + (UVWASI_FILESTAT_SET_ATIM_NOW | UVWASI_FILESTAT_SET_MTIM_NOW)) != 0) { + err = uvwasi__clock_gettime_realtime(&now); + if (err != UVWASI_ESUCCESS) + return err; + } + + /* Check if either value is omitted. libuv doesn't have an 'omitted' option, + so get the current stats for the file. This approach isn't perfect, but it + will do until libuv can get better support here. */ + if ((fst_flags & + (UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW)) == 0 || + (fst_flags & + (UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) == 0) { + + if (fd != NULL) + r = uv_fs_fstat(NULL, &req, *fd, NULL); + else + r = uv_fs_lstat(NULL, &req, path, NULL); + + if (r != 0) { + uv_fs_req_cleanup(&req); + return uvwasi__translate_uv_error(r); + } + + uvwasi__stat_to_filestat(&req.statbuf, &stat); + uv_fs_req_cleanup(&req); + } + + /* Choose the provided time or 'now' and convert WASI timestamps from + nanoseconds to seconds due to libuv. */ + if ((fst_flags & UVWASI_FILESTAT_SET_ATIM_NOW) != 0) + *st_atim = now / NANOS_PER_SEC; + else if ((fst_flags & UVWASI_FILESTAT_SET_ATIM) != 0) + *st_atim = *st_atim / NANOS_PER_SEC; + else + *st_atim = stat.st_atim / NANOS_PER_SEC; + + if ((fst_flags & UVWASI_FILESTAT_SET_MTIM_NOW) != 0) + *st_mtim = now / NANOS_PER_SEC; + else if ((fst_flags & UVWASI_FILESTAT_SET_MTIM) != 0) + *st_mtim = *st_mtim / NANOS_PER_SEC; + else + *st_mtim = stat.st_mtim / NANOS_PER_SEC; + + return UVWASI_ESUCCESS; +} + static void* default_malloc(size_t size, void* mem_user_data) { return malloc(size); } @@ -308,6 +380,23 @@ void uvwasi_destroy(uvwasi_t* uvwasi) { } +void uvwasi_options_init(uvwasi_options_t* options) { + if (options == NULL) + return; + + options->in = 0; + options->out = 1; + options->err = 2; + options->fd_table_size = 3; + options->argc = 0; + options->argv = NULL; + options->envp = NULL; + options->preopenc = 0; + options->preopens = NULL; + options->allocator = NULL; +} + + uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi, const uvwasi_fd_t fd, uv_file new_host_fd) { @@ -330,10 +419,10 @@ uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf) { uvwasi_size_t i; - DEBUG("uvwasi_args_get(uvwasi=%p, argv=%p, argv_buf=%p)\n", - uvwasi, - argv, - argv_buf); + UVWASI_DEBUG("uvwasi_args_get(uvwasi=%p, argv=%p, argv_buf=%p)\n", + uvwasi, + argv, + argv_buf); if (uvwasi == NULL || argv == NULL || argv_buf == NULL) return UVWASI_EINVAL; @@ -350,10 +439,10 @@ uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf) { uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi, uvwasi_size_t* argc, uvwasi_size_t* argv_buf_size) { - DEBUG("uvwasi_args_sizes_get(uvwasi=%p, argc=%p, argv_buf_size=%p)\n", - uvwasi, - argc, - argv_buf_size); + UVWASI_DEBUG("uvwasi_args_sizes_get(uvwasi=%p, argc=%p, argv_buf_size=%p)\n", + uvwasi, + argc, + argv_buf_size); if (uvwasi == NULL || argc == NULL || argv_buf_size == NULL) return UVWASI_EINVAL; @@ -367,10 +456,10 @@ uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi, uvwasi_clockid_t clock_id, uvwasi_timestamp_t* resolution) { - DEBUG("uvwasi_clock_res_get(uvwasi=%p, clock_id=%d, resolution=%p)\n", - uvwasi, - clock_id, - resolution); + UVWASI_DEBUG("uvwasi_clock_res_get(uvwasi=%p, clock_id=%d, resolution=%p)\n", + uvwasi, + clock_id, + resolution); if (uvwasi == NULL || resolution == NULL) return UVWASI_EINVAL; @@ -394,12 +483,12 @@ uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi, uvwasi_clockid_t clock_id, uvwasi_timestamp_t precision, uvwasi_timestamp_t* time) { - DEBUG("uvwasi_clock_time_get(uvwasi=%p, clock_id=%d, " - "precision=%"PRIu64", time=%p)\n", - uvwasi, - clock_id, - precision, - time); + UVWASI_DEBUG("uvwasi_clock_time_get(uvwasi=%p, clock_id=%d, " + "precision=%"PRIu64", time=%p)\n", + uvwasi, + clock_id, + precision, + time); if (uvwasi == NULL || time == NULL) return UVWASI_EINVAL; @@ -425,10 +514,11 @@ uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi, char* environ_buf) { uvwasi_size_t i; - DEBUG("uvwasi_environ_get(uvwasi=%p, environment=%p, environ_buf=%p)\n", - uvwasi, - environment, - environ_buf); + UVWASI_DEBUG("uvwasi_environ_get(uvwasi=%p, environment=%p, " + "environ_buf=%p)\n", + uvwasi, + environment, + environ_buf); if (uvwasi == NULL || environment == NULL || environ_buf == NULL) return UVWASI_EINVAL; @@ -445,11 +535,11 @@ uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi, uvwasi_size_t* environ_count, uvwasi_size_t* environ_buf_size) { - DEBUG("uvwasi_environ_sizes_get(uvwasi=%p, environ_count=%p, " - "environ_buf_size=%p)\n", - uvwasi, - environ_count, - environ_buf_size); + UVWASI_DEBUG("uvwasi_environ_sizes_get(uvwasi=%p, environ_count=%p, " + "environ_buf_size=%p)\n", + uvwasi, + environ_count, + environ_buf_size); if (uvwasi == NULL || environ_count == NULL || environ_buf_size == NULL) return UVWASI_EINVAL; @@ -472,13 +562,13 @@ uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi, int r; #endif /* POSIX_FADV_NORMAL */ - DEBUG("uvwasi_fd_advise(uvwasi=%p, fd=%d, offset=%"PRIu64", len=%"PRIu64", " - "advice=%d)\n", - uvwasi, - fd, - offset, - len, - advice); + UVWASI_DEBUG("uvwasi_fd_advise(uvwasi=%p, fd=%d, offset=%"PRIu64", " + "len=%"PRIu64", advice=%d)\n", + uvwasi, + fd, + offset, + len, + advice); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -546,12 +636,12 @@ uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_fd_allocate(uvwasi=%p, fd=%d, offset=%"PRIu64", " - "len=%"PRIu64")\n", - uvwasi, - fd, - offset, - len); + UVWASI_DEBUG("uvwasi_fd_allocate(uvwasi=%p, fd=%d, offset=%"PRIu64", " + "len=%"PRIu64")\n", + uvwasi, + fd, + offset, + len); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -603,7 +693,7 @@ uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd) { uv_fs_t req; int r; - DEBUG("uvwasi_fd_close(uvwasi=%p, fd=%d)\n", uvwasi, fd); + UVWASI_DEBUG("uvwasi_fd_close(uvwasi=%p, fd=%d)\n", uvwasi, fd); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -637,7 +727,7 @@ uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd) { uv_fs_t req; int r; - DEBUG("uvwasi_fd_datasync(uvwasi=%p, fd=%d)\n", uvwasi, fd); + UVWASI_DEBUG("uvwasi_fd_datasync(uvwasi=%p, fd=%d)\n", uvwasi, fd); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -670,7 +760,10 @@ uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi, int r; #endif - DEBUG("uvwasi_fd_fdstat_get(uvwasi=%p, fd=%d, buf=%p)\n", uvwasi, fd, buf); + UVWASI_DEBUG("uvwasi_fd_fdstat_get(uvwasi=%p, fd=%d, buf=%p)\n", + uvwasi, + fd, + buf); if (uvwasi == NULL || buf == NULL) return UVWASI_EINVAL; @@ -703,10 +796,10 @@ uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi, uvwasi_fd_t fd, uvwasi_fdflags_t flags) { #ifdef _WIN32 - DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n", - uvwasi, - fd, - flags); + UVWASI_DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n", + uvwasi, + fd, + flags); /* TODO(cjihrig): Windows is not supported. */ return UVWASI_ENOSYS; @@ -716,10 +809,10 @@ uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi, int mapped_flags; int r; - DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n", - uvwasi, - fd, - flags); + UVWASI_DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n", + uvwasi, + fd, + flags); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -777,12 +870,12 @@ uvwasi_errno_t uvwasi_fd_fdstat_set_rights(uvwasi_t* uvwasi, struct uvwasi_fd_wrap_t* wrap; uvwasi_errno_t err; - DEBUG("uvwasi_fd_fdstat_set_rights(uvwasi=%p, fd=%d, " - "fs_rights_base=%"PRIu64", fs_rights_inheriting=%"PRIu64")\n", - uvwasi, - fd, - fs_rights_base, - fs_rights_inheriting); + UVWASI_DEBUG("uvwasi_fd_fdstat_set_rights(uvwasi=%p, fd=%d, " + "fs_rights_base=%"PRIu64", fs_rights_inheriting=%"PRIu64")\n", + uvwasi, + fd, + fs_rights_base, + fs_rights_inheriting); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -820,7 +913,10 @@ uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_fd_filestat_get(uvwasi=%p, fd=%d, buf=%p)\n", uvwasi, fd, buf); + UVWASI_DEBUG("uvwasi_fd_filestat_get(uvwasi=%p, fd=%d, buf=%p)\n", + uvwasi, + fd, + buf); if (uvwasi == NULL || buf == NULL) return UVWASI_EINVAL; @@ -857,10 +953,11 @@ uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_fd_filestat_set_size(uvwasi=%p, fd=%d, st_size=%"PRIu64")\n", - uvwasi, - fd, - st_size); + UVWASI_DEBUG("uvwasi_fd_filestat_set_size(uvwasi=%p, fd=%d, " + "st_size=%"PRIu64")\n", + uvwasi, + fd, + st_size); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -889,27 +986,25 @@ uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi, 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; + uvwasi_timestamp_t atim; + uvwasi_timestamp_t mtim; uv_fs_t req; uvwasi_errno_t err; int r; - DEBUG("uvwasi_fd_filestat_set_times(uvwasi=%p, fd=%d, st_atim=%"PRIu64", " - "st_mtim=%"PRIu64", fst_flags=%d)\n", - uvwasi, - fd, - st_atim, - st_mtim, - fst_flags); + UVWASI_DEBUG("uvwasi_fd_filestat_set_times(uvwasi=%p, fd=%d, " + "st_atim=%"PRIu64", st_mtim=%"PRIu64", fst_flags=%d)\n", + uvwasi, + fd, + st_atim, + st_mtim, + fst_flags); 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; - } + VALIDATE_FSTFLAGS_OR_RETURN(fst_flags); err = uvwasi_fd_table_get(uvwasi->fds, fd, @@ -919,8 +1014,20 @@ uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi, 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); + atim = st_atim; + mtim = st_mtim; + err = uvwasi__get_filestat_set_times(&atim, + &mtim, + fst_flags, + &wrap->fd, + NULL); + if (err != UVWASI_ESUCCESS) { + uv_mutex_unlock(&wrap->mutex); + return err; + } + + /* libuv does not currently support nanosecond precision. */ + r = uv_fs_futime(NULL, &req, wrap->fd, atim, mtim, NULL); uv_mutex_unlock(&wrap->mutex); uv_fs_req_cleanup(&req); @@ -944,14 +1051,14 @@ uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi, size_t uvread; int r; - DEBUG("uvwasi_fd_pread(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%zu, " - "offset=%"PRIu64", nread=%p)\n", - uvwasi, - fd, - iovs, - iovs_len, - offset, - nread); + UVWASI_DEBUG("uvwasi_fd_pread(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, " + "offset=%"PRIu64", nread=%p)\n", + uvwasi, + fd, + iovs, + iovs_len, + offset, + nread); if (uvwasi == NULL || iovs == NULL || nread == NULL) return UVWASI_EINVAL; @@ -990,10 +1097,10 @@ uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi, struct uvwasi_fd_wrap_t* wrap; uvwasi_errno_t err; - DEBUG("uvwasi_fd_prestat_get(uvwasi=%p, fd=%d, buf=%p)\n", - uvwasi, - fd, - buf); + UVWASI_DEBUG("uvwasi_fd_prestat_get(uvwasi=%p, fd=%d, buf=%p)\n", + uvwasi, + fd, + buf); if (uvwasi == NULL || buf == NULL) return UVWASI_EINVAL; @@ -1023,11 +1130,12 @@ uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi, uvwasi_errno_t err; size_t size; - DEBUG("uvwasi_fd_prestat_dir_name(uvwasi=%p, fd=%d, path=%p, path_len=%zu)\n", - uvwasi, - fd, - path, - path_len); + UVWASI_DEBUG("uvwasi_fd_prestat_dir_name(uvwasi=%p, fd=%d, path=%p, " + "path_len=%d)\n", + uvwasi, + fd, + path, + path_len); if (uvwasi == NULL || path == NULL) return UVWASI_EINVAL; @@ -1067,14 +1175,14 @@ uvwasi_errno_t uvwasi_fd_pwrite(uvwasi_t* uvwasi, size_t uvwritten; int r; - DEBUG("uvwasi_fd_pwrite(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%zu, " - "offset=%"PRIu64", nwritten=%p)\n", - uvwasi, - fd, - iovs, - iovs_len, - offset, - nwritten); + UVWASI_DEBUG("uvwasi_fd_pwrite(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, " + "offset=%"PRIu64", nwritten=%p)\n", + uvwasi, + fd, + iovs, + iovs_len, + offset, + nwritten); if (uvwasi == NULL || iovs == NULL || nwritten == NULL) return UVWASI_EINVAL; @@ -1119,12 +1227,13 @@ uvwasi_errno_t uvwasi_fd_read(uvwasi_t* uvwasi, size_t uvread; int r; - DEBUG("uvwasi_fd_read(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%zu, nread=%p)\n", - uvwasi, - fd, - iovs, - iovs_len, - nread); + UVWASI_DEBUG("uvwasi_fd_read(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, " + "nread=%p)\n", + uvwasi, + fd, + iovs, + iovs_len, + nread); if (uvwasi == NULL || iovs == NULL || nread == NULL) return UVWASI_EINVAL; @@ -1174,14 +1283,14 @@ uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi, int i; int r; - DEBUG("uvwasi_fd_readdir(uvwasi=%p, fd=%d, buf=%p, buf_len=%zu, " - "cookie=%"PRIu64", bufused=%p)\n", - uvwasi, - fd, - buf, - buf_len, - cookie, - bufused); + UVWASI_DEBUG("uvwasi_fd_readdir(uvwasi=%p, fd=%d, buf=%p, buf_len=%d, " + "cookie=%"PRIu64", bufused=%p)\n", + uvwasi, + fd, + buf, + buf_len, + cookie, + bufused); if (uvwasi == NULL || buf == NULL || bufused == NULL) return UVWASI_EINVAL; @@ -1305,7 +1414,10 @@ uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi, uvwasi_fd_t from, uvwasi_fd_t to) { - DEBUG("uvwasi_fd_renumber(uvwasi=%p, from=%d, to=%d)\n", uvwasi, from, to); + UVWASI_DEBUG("uvwasi_fd_renumber(uvwasi=%p, from=%d, to=%d)\n", + uvwasi, + from, + to); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -1322,13 +1434,13 @@ uvwasi_errno_t uvwasi_fd_seek(uvwasi_t* uvwasi, struct uvwasi_fd_wrap_t* wrap; uvwasi_errno_t err; - DEBUG("uvwasi_fd_seek(uvwasi=%p, fd=%d, offset=%"PRId64", " - "whence=%d, newoffset=%p)\n", - uvwasi, - fd, - offset, - whence, - newoffset); + UVWASI_DEBUG("uvwasi_fd_seek(uvwasi=%p, fd=%d, offset=%"PRId64", " + "whence=%d, newoffset=%p)\n", + uvwasi, + fd, + offset, + whence, + newoffset); if (uvwasi == NULL || newoffset == NULL) return UVWASI_EINVAL; @@ -1349,7 +1461,7 @@ uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd) { uvwasi_errno_t err; int r; - DEBUG("uvwasi_fd_sync(uvwasi=%p, fd=%d)\n", uvwasi, fd); + UVWASI_DEBUG("uvwasi_fd_sync(uvwasi=%p, fd=%d)\n", uvwasi, fd); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -1379,7 +1491,10 @@ uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi, struct uvwasi_fd_wrap_t* wrap; uvwasi_errno_t err; - DEBUG("uvwasi_fd_tell(uvwasi=%p, fd=%d, offset=%p)\n", uvwasi, fd, offset); + UVWASI_DEBUG("uvwasi_fd_tell(uvwasi=%p, fd=%d, offset=%p)\n", + uvwasi, + fd, + offset); if (uvwasi == NULL || offset == NULL) return UVWASI_EINVAL; @@ -1406,13 +1521,13 @@ uvwasi_errno_t uvwasi_fd_write(uvwasi_t* uvwasi, size_t uvwritten; int r; - DEBUG("uvwasi_fd_write(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%zu, " - "nwritten=%p)\n", - uvwasi, - fd, - iovs, - iovs_len, - nwritten); + UVWASI_DEBUG("uvwasi_fd_write(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, " + "nwritten=%p)\n", + uvwasi, + fd, + iovs, + iovs_len, + nwritten); if (uvwasi == NULL || iovs == NULL || nwritten == NULL) return UVWASI_EINVAL; @@ -1451,12 +1566,12 @@ uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_path_create_directory(uvwasi=%p, fd=%d, path='%s', " - "path_len=%zu)\n", - uvwasi, - fd, - path, - path_len); + UVWASI_DEBUG("uvwasi_path_create_directory(uvwasi=%p, fd=%d, path='%s', " + "path_len=%d)\n", + uvwasi, + fd, + path, + path_len); if (uvwasi == NULL || path == NULL) return UVWASI_EINVAL; @@ -1501,14 +1616,14 @@ uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_path_filestat_get(uvwasi=%p, fd=%d, flags=%d, path='%s', " - "path_len=%zu, buf=%p)\n", - uvwasi, - fd, - flags, - path, - path_len, - buf); + UVWASI_DEBUG("uvwasi_path_filestat_get(uvwasi=%p, fd=%d, flags=%d, " + "path='%s', path_len=%d, buf=%p)\n", + uvwasi, + fd, + flags, + path, + path_len, + buf); if (uvwasi == NULL || path == NULL || buf == NULL) return UVWASI_EINVAL; @@ -1530,7 +1645,7 @@ uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi, if (err != UVWASI_ESUCCESS) goto exit; - r = uv_fs_stat(NULL, &req, resolved_path, NULL); + r = uv_fs_lstat(NULL, &req, resolved_path, NULL); uvwasi__free(uvwasi, resolved_path); if (r != 0) { uv_fs_req_cleanup(&req); @@ -1555,31 +1670,30 @@ uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi, 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; struct uvwasi_fd_wrap_t* wrap; + uvwasi_timestamp_t atim; + uvwasi_timestamp_t mtim; uv_fs_t req; uvwasi_errno_t err; int r; - DEBUG("uvwasi_path_filestat_set_times(uvwasi=%p, fd=%d, flags=%d, path='%s', " - "path_len=%zu, st_atim=%"PRIu64", st_mtim=%"PRIu64", fst_flags=%d)\n", - uvwasi, - fd, - flags, - path, - path_len, - st_atim, - st_mtim, - fst_flags); + UVWASI_DEBUG("uvwasi_path_filestat_set_times(uvwasi=%p, fd=%d, " + "flags=%d, path='%s', path_len=%d, " + "st_atim=%"PRIu64", st_mtim=%"PRIu64", fst_flags=%d)\n", + uvwasi, + fd, + flags, + path, + path_len, + st_atim, + st_mtim, + fst_flags); 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; - } + VALIDATE_FSTFLAGS_OR_RETURN(fst_flags); err = uvwasi_fd_table_get(uvwasi->fds, fd, @@ -1598,8 +1712,20 @@ uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi, if (err != UVWASI_ESUCCESS) goto exit; - /* 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); + atim = st_atim; + mtim = st_mtim; + err = uvwasi__get_filestat_set_times(&atim, + &mtim, + fst_flags, + NULL, + resolved_path); + if (err != UVWASI_ESUCCESS) { + uvwasi__free(uvwasi, resolved_path); + goto exit; + } + + /* libuv does not currently support nanosecond precision. */ + r = uv_fs_lutime(NULL, &req, resolved_path, atim, mtim, NULL); uvwasi__free(uvwasi, resolved_path); uv_fs_req_cleanup(&req); @@ -1631,16 +1757,17 @@ uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi, uv_fs_t req; int r; - DEBUG("uvwasi_path_link(uvwasi=%p, old_fd=%d, old_flags=%d, old_path='%s', " - "old_path_len=%zu, new_fd=%d, new_path='%s', new_path_len=%zu)\n", - uvwasi, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len); + UVWASI_DEBUG("uvwasi_path_link(uvwasi=%p, old_fd=%d, old_flags=%d, " + "old_path='%s', old_path_len=%d, new_fd=%d, new_path='%s', " + "new_path_len=%d)\n", + uvwasi, + old_fd, + old_flags, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len); if (uvwasi == NULL || old_path == NULL || new_path == NULL) return UVWASI_EINVAL; @@ -1745,19 +1872,19 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi, int write; int r; - DEBUG("uvwasi_path_open(uvwasi=%p, dirfd=%d, dirflags=%d, path='%s', " - "path_len=%zu, o_flags=%d, fs_rights_base=%"PRIu64", " - "fs_rights_inheriting=%"PRIu64", fs_flags=%d, fd=%p)\n", - uvwasi, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd); + UVWASI_DEBUG("uvwasi_path_open(uvwasi=%p, dirfd=%d, dirflags=%d, path='%s', " + "path_len=%d, o_flags=%d, fs_rights_base=%"PRIu64", " + "fs_rights_inheriting=%"PRIu64", fs_flags=%d, fd=%p)\n", + uvwasi, + dirfd, + dirflags, + path, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd); if (uvwasi == NULL || path == NULL || fd == NULL) return UVWASI_EINVAL; @@ -1892,15 +2019,15 @@ uvwasi_errno_t uvwasi_path_readlink(uvwasi_t* uvwasi, size_t len; int r; - DEBUG("uvwasi_path_readlink(uvwasi=%p, fd=%d, path='%s', path_len=%zu, " - "buf=%p, buf_len=%zu, bufused=%p)\n", - uvwasi, - fd, - path, - path_len, - buf, - buf_len, - bufused); + UVWASI_DEBUG("uvwasi_path_readlink(uvwasi=%p, fd=%d, path='%s', path_len=%d, " + "buf=%p, buf_len=%d, bufused=%p)\n", + uvwasi, + fd, + path, + path_len, + buf, + buf_len, + bufused); if (uvwasi == NULL || path == NULL || buf == NULL || bufused == NULL) return UVWASI_EINVAL; @@ -1951,12 +2078,12 @@ uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_path_remove_directory(uvwasi=%p, fd=%d, path='%s', " - "path_len=%zu)\n", - uvwasi, - fd, - path, - path_len); + UVWASI_DEBUG("uvwasi_path_remove_directory(uvwasi=%p, fd=%d, path='%s', " + "path_len=%d)\n", + uvwasi, + fd, + path, + path_len); if (uvwasi == NULL || path == NULL) return UVWASI_EINVAL; @@ -2002,15 +2129,15 @@ uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi, uv_fs_t req; int r; - DEBUG("uvwasi_path_rename(uvwasi=%p, old_fd=%d, old_path='%s', " - "old_path_len=%zu, new_fd=%d, new_path='%s', new_path_len=%zu)\n", - uvwasi, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len); + UVWASI_DEBUG("uvwasi_path_rename(uvwasi=%p, old_fd=%d, old_path='%s', " + "old_path_len=%d, new_fd=%d, new_path='%s', new_path_len=%d)\n", + uvwasi, + old_fd, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len); if (uvwasi == NULL || old_path == NULL || new_path == NULL) return UVWASI_EINVAL; @@ -2102,14 +2229,14 @@ uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi, uv_fs_t req; int r; - DEBUG("uvwasi_path_symlink(uvwasi=%p, old_path='%s', old_path_len=%zu, " - "fd=%d, new_path='%s', new_path_len=%zu)\n", - uvwasi, - old_path, - old_path_len, - fd, - new_path, - new_path_len); + UVWASI_DEBUG("uvwasi_path_symlink(uvwasi=%p, old_path='%s', old_path_len=%d, " + "fd=%d, new_path='%s', new_path_len=%d)\n", + uvwasi, + old_path, + old_path_len, + fd, + new_path, + new_path_len); if (uvwasi == NULL || old_path == NULL || new_path == NULL) return UVWASI_EINVAL; @@ -2155,11 +2282,12 @@ uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi, uvwasi_errno_t err; int r; - DEBUG("uvwasi_path_unlink_file(uvwasi=%p, fd=%d, path='%s', path_len=%zu)\n", - uvwasi, - fd, - path, - path_len); + UVWASI_DEBUG("uvwasi_path_unlink_file(uvwasi=%p, fd=%d, path='%s', " + "path_len=%d)\n", + uvwasi, + fd, + path, + path_len); if (uvwasi == NULL || path == NULL) return UVWASI_EINVAL; @@ -2207,13 +2335,13 @@ uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi, int has_timeout; uvwasi_size_t i; - DEBUG("uvwasi_poll_oneoff(uvwasi=%p, in=%p, out=%p, nsubscriptions=%zu, " - "nevents=%p)\n", - uvwasi, - in, - out, - nsubscriptions, - nevents); + UVWASI_DEBUG("uvwasi_poll_oneoff(uvwasi=%p, in=%p, out=%p, " + "nsubscriptions=%d, nevents=%p)\n", + uvwasi, + in, + out, + nsubscriptions, + nevents); if (uvwasi == NULL || in == NULL || out == NULL || nsubscriptions == 0 || nevents == NULL) { @@ -2313,7 +2441,7 @@ uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval) { - DEBUG("uvwasi_proc_exit(uvwasi=%p, rval=%d)\n", uvwasi, rval); + UVWASI_DEBUG("uvwasi_proc_exit(uvwasi=%p, rval=%d)\n", uvwasi, rval); exit(rval); return UVWASI_ESUCCESS; /* This doesn't happen. */ } @@ -2322,7 +2450,7 @@ 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) { int r; - DEBUG("uvwasi_proc_raise(uvwasi=%p, sig=%d)\n", uvwasi, sig); + UVWASI_DEBUG("uvwasi_proc_raise(uvwasi=%p, sig=%d)\n", uvwasi, sig); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -2344,10 +2472,10 @@ uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, uvwasi_size_t buf_len) { int r; - DEBUG("uvwasi_random_get(uvwasi=%p, buf=%p, buf_len=%zu)\n", - uvwasi, - buf, - buf_len); + UVWASI_DEBUG("uvwasi_random_get(uvwasi=%p, buf=%p, buf_len=%d)\n", + uvwasi, + buf, + buf_len); if (uvwasi == NULL || buf == NULL) return UVWASI_EINVAL; @@ -2361,7 +2489,7 @@ uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi) { - DEBUG("uvwasi_sched_yield(uvwasi=%p)\n", uvwasi); + UVWASI_DEBUG("uvwasi_sched_yield(uvwasi=%p)\n", uvwasi); if (uvwasi == NULL) return UVWASI_EINVAL; @@ -2386,7 +2514,7 @@ uvwasi_errno_t uvwasi_sock_recv(uvwasi_t* uvwasi, uvwasi_roflags_t* ro_flags) { /* TODO(cjihrig): Waiting to implement, pending /~https://github.com/WebAssembly/WASI/issues/4 */ - DEBUG("uvwasi_sock_recv(uvwasi=%p, unimplemented)\n", uvwasi); + UVWASI_DEBUG("uvwasi_sock_recv(uvwasi=%p, unimplemented)\n", uvwasi); return UVWASI_ENOTSUP; } @@ -2399,7 +2527,7 @@ uvwasi_errno_t uvwasi_sock_send(uvwasi_t* uvwasi, uvwasi_size_t* so_datalen) { /* TODO(cjihrig): Waiting to implement, pending /~https://github.com/WebAssembly/WASI/issues/4 */ - DEBUG("uvwasi_sock_send(uvwasi=%p, unimplemented)\n", uvwasi); + UVWASI_DEBUG("uvwasi_sock_send(uvwasi=%p, unimplemented)\n", uvwasi); return UVWASI_ENOTSUP; } @@ -2409,7 +2537,7 @@ uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi, uvwasi_sdflags_t how) { /* TODO(cjihrig): Waiting to implement, pending /~https://github.com/WebAssembly/WASI/issues/4 */ - DEBUG("uvwasi_sock_shutdown(uvwasi=%p, unimplemented)\n", uvwasi); + UVWASI_DEBUG("uvwasi_sock_shutdown(uvwasi=%p, unimplemented)\n", uvwasi); return UVWASI_ENOTSUP; } diff --git a/src/node_wasi.cc b/src/node_wasi.cc index 48ef82bd088d6a..80182724afea9c 100644 --- a/src/node_wasi.cc +++ b/src/node_wasi.cc @@ -175,6 +175,8 @@ void WASI::New(const FunctionCallbackInfo& args) { const uint32_t argc = argv->Length(); uvwasi_options_t options; + uvwasi_options_init(&options); + Local stdio = args[3].As(); CHECK_EQ(stdio->Length(), 3); options.in = stdio->Get(context, 0).ToLocalChecked()-> @@ -244,8 +246,8 @@ void WASI::New(const FunctionCallbackInfo& args) { if (options.preopens != nullptr) { for (uint32_t i = 0; i < options.preopenc; i++) { - free(options.preopens[i].mapped_path); - free(options.preopens[i].real_path); + free(const_cast(options.preopens[i].mapped_path)); + free(const_cast(options.preopens[i].real_path)); } free(options.preopens); From 9b7f9fbbb9649eb4ceb71980b7f8a065dd10ea14 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Aug 2020 14:28:47 -0400 Subject: [PATCH 2/2] wasi: add __wasi_fd_filestat_set_times() test --- test/wasi/c/stat.c | 10 ++++++++++ test/wasi/wasm/stat.wasm | Bin 34898 -> 37857 bytes 2 files changed, 10 insertions(+) diff --git a/test/wasi/c/stat.c b/test/wasi/c/stat.c index e4fcafd713d855..877e5b68a130a2 100644 --- a/test/wasi/c/stat.c +++ b/test/wasi/c/stat.c @@ -11,6 +11,7 @@ #define SIZE 500 int main(void) { + struct timespec times[2]; struct stat st; int fd; int ret; @@ -33,6 +34,15 @@ int main(void) { assert(ret == 0); assert(st.st_size == SIZE); + times[0].tv_sec = 4; + times[0].tv_nsec = 0; + times[1].tv_sec = 9; + times[1].tv_nsec = 0; + assert(0 == futimens(fd, times)); + assert(0 == fstat(fd, &st)); + assert(4 == st.st_atime); + assert(9 == st.st_mtime); + ret = close(fd); assert(ret == 0); diff --git a/test/wasi/wasm/stat.wasm b/test/wasi/wasm/stat.wasm index 6209314793834776987c37738131f9e1ead9daaa..4a50c0282bb60a43d9bb04291a01ec1461213c16 100755 GIT binary patch delta 9528 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 o^@+~ie)lOy`;hGgx-_@CTvjK#S7pe#vH