• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <string.h>
3 
4 #ifndef _WIN32
5 # include <sched.h>
6 # include <sys/types.h>
7 # include <unistd.h>
8 # include <dirent.h>
9 # include <time.h>
10 #else
11 # include <io.h>
12 #endif /* _WIN32 */
13 
14 #define UVWASI__READDIR_NUM_ENTRIES 1
15 
16 #if !defined(_WIN32) && !defined(__ANDROID__)
17 # define UVWASI_FD_READDIR_SUPPORTED 1
18 #endif
19 
20 #include "uvwasi.h"
21 #include "uvwasi_alloc.h"
22 #include "uv.h"
23 #include "uv_mapping.h"
24 #include "fd_table.h"
25 #include "clocks.h"
26 #include "path_resolver.h"
27 #include "poll_oneoff.h"
28 #include "sync_helpers.h"
29 #include "wasi_rights.h"
30 #include "wasi_serdes.h"
31 #include "debug.h"
32 
33 /* IBMi PASE does not support posix_fadvise() */
34 #ifdef __PASE__
35 # undef POSIX_FADV_NORMAL
36 #endif
37 
38 #define VALIDATE_FSTFLAGS_OR_RETURN(flags)                                    \
39   do {                                                                        \
40     if ((flags) & ~(UVWASI_FILESTAT_SET_ATIM |                                \
41                     UVWASI_FILESTAT_SET_ATIM_NOW |                            \
42                     UVWASI_FILESTAT_SET_MTIM |                                \
43                     UVWASI_FILESTAT_SET_MTIM_NOW)) {                          \
44       return UVWASI_EINVAL;                                                   \
45     }                                                                         \
46   } while (0)
47 
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)48 static uvwasi_errno_t uvwasi__get_filestat_set_times(
49                                                     uvwasi_timestamp_t* st_atim,
50                                                     uvwasi_timestamp_t* st_mtim,
51                                                     uvwasi_fstflags_t fst_flags,
52                                                     uv_file* fd,
53                                                     char* path
54                                                   ) {
55   uvwasi_filestat_t stat;
56   uvwasi_timestamp_t now;
57   uvwasi_errno_t err;
58   uv_fs_t req;
59   int r;
60 
61   /* Check if either value requires the current time. */
62   if ((fst_flags &
63       (UVWASI_FILESTAT_SET_ATIM_NOW | UVWASI_FILESTAT_SET_MTIM_NOW)) != 0) {
64     err = uvwasi__clock_gettime_realtime(&now);
65     if (err != UVWASI_ESUCCESS)
66       return err;
67   }
68 
69   /* Check if either value is omitted. libuv doesn't have an 'omitted' option,
70      so get the current stats for the file. This approach isn't perfect, but it
71      will do until libuv can get better support here. */
72   if ((fst_flags &
73        (UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW)) == 0 ||
74       (fst_flags &
75        (UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) == 0) {
76 
77     if (fd != NULL)
78       r = uv_fs_fstat(NULL, &req, *fd, NULL);
79     else
80       r = uv_fs_lstat(NULL, &req, path, NULL);
81 
82     if (r != 0) {
83       uv_fs_req_cleanup(&req);
84       return uvwasi__translate_uv_error(r);
85     }
86 
87     uvwasi__stat_to_filestat(&req.statbuf, &stat);
88     uv_fs_req_cleanup(&req);
89   }
90 
91   /* Choose the provided time or 'now' and convert WASI timestamps from
92      nanoseconds to seconds due to libuv. */
93   if ((fst_flags & UVWASI_FILESTAT_SET_ATIM_NOW) != 0)
94     *st_atim = now / NANOS_PER_SEC;
95   else if ((fst_flags & UVWASI_FILESTAT_SET_ATIM) != 0)
96     *st_atim = *st_atim / NANOS_PER_SEC;
97   else
98     *st_atim = stat.st_atim / NANOS_PER_SEC;
99 
100   if ((fst_flags & UVWASI_FILESTAT_SET_MTIM_NOW) != 0)
101     *st_mtim = now / NANOS_PER_SEC;
102   else if ((fst_flags & UVWASI_FILESTAT_SET_MTIM) != 0)
103     *st_mtim = *st_mtim / NANOS_PER_SEC;
104   else
105     *st_mtim = stat.st_mtim / NANOS_PER_SEC;
106 
107   return UVWASI_ESUCCESS;
108 }
109 
default_malloc(size_t size,void * mem_user_data)110 static void* default_malloc(size_t size, void* mem_user_data) {
111   return malloc(size);
112 }
113 
default_free(void * ptr,void * mem_user_data)114 static void default_free(void* ptr, void* mem_user_data) {
115   free(ptr);
116 }
117 
default_calloc(size_t nmemb,size_t size,void * mem_user_data)118 static void* default_calloc(size_t nmemb, size_t size, void* mem_user_data) {
119   return calloc(nmemb, size);
120 }
121 
default_realloc(void * ptr,size_t size,void * mem_user_data)122 static void* default_realloc(void* ptr, size_t size, void* mem_user_data) {
123   return realloc(ptr, size);
124 }
125 
uvwasi__malloc(const uvwasi_t * uvwasi,size_t size)126 void* uvwasi__malloc(const uvwasi_t* uvwasi, size_t size) {
127   return uvwasi->allocator->malloc(size, uvwasi->allocator->mem_user_data);
128 }
129 
uvwasi__free(const uvwasi_t * uvwasi,void * ptr)130 void uvwasi__free(const uvwasi_t* uvwasi, void* ptr) {
131   if (ptr == NULL)
132     return;
133 
134   uvwasi->allocator->free(ptr, uvwasi->allocator->mem_user_data);
135 }
136 
uvwasi__calloc(const uvwasi_t * uvwasi,size_t nmemb,size_t size)137 void* uvwasi__calloc(const uvwasi_t* uvwasi, size_t nmemb, size_t size) {
138   return uvwasi->allocator->calloc(nmemb,
139                                    size,
140                                    uvwasi->allocator->mem_user_data);
141 }
142 
uvwasi__realloc(const uvwasi_t * uvwasi,void * ptr,size_t size)143 void* uvwasi__realloc(const uvwasi_t* uvwasi, void* ptr, size_t size) {
144   return uvwasi->allocator->realloc(ptr,
145                                     size,
146                                     uvwasi->allocator->mem_user_data);
147 }
148 
149 static const uvwasi_mem_t default_allocator = {
150   NULL,
151   default_malloc,
152   default_free,
153   default_calloc,
154   default_realloc,
155 };
156 
157 
uvwasi__lseek(uv_file fd,uvwasi_filedelta_t offset,uvwasi_whence_t whence,uvwasi_filesize_t * newoffset)158 static uvwasi_errno_t uvwasi__lseek(uv_file fd,
159                                     uvwasi_filedelta_t offset,
160                                     uvwasi_whence_t whence,
161                                     uvwasi_filesize_t* newoffset) {
162   int real_whence;
163 
164   if (whence == UVWASI_WHENCE_CUR)
165     real_whence = SEEK_CUR;
166   else if (whence == UVWASI_WHENCE_END)
167     real_whence = SEEK_END;
168   else if (whence == UVWASI_WHENCE_SET)
169     real_whence = SEEK_SET;
170   else
171     return UVWASI_EINVAL;
172 
173 #ifdef _WIN32
174   int64_t r;
175 
176   r = _lseeki64(fd, offset, real_whence);
177   if (-1L == r)
178     return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
179 #else
180   off_t r;
181 
182   r = lseek(fd, offset, real_whence);
183   if ((off_t) -1 == r)
184     return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
185 #endif /* _WIN32 */
186 
187   *newoffset = r;
188   return UVWASI_ESUCCESS;
189 }
190 
191 
uvwasi__setup_iovs(const uvwasi_t * uvwasi,uv_buf_t ** buffers,const uvwasi_iovec_t * iovs,uvwasi_size_t iovs_len)192 static uvwasi_errno_t uvwasi__setup_iovs(const uvwasi_t* uvwasi,
193                                          uv_buf_t** buffers,
194                                          const uvwasi_iovec_t* iovs,
195                                          uvwasi_size_t iovs_len) {
196   uv_buf_t* bufs;
197   uvwasi_size_t i;
198 
199   if ((iovs_len * sizeof(*bufs)) / (sizeof(*bufs)) != iovs_len)
200     return UVWASI_ENOMEM;
201 
202   bufs = uvwasi__malloc(uvwasi, iovs_len * sizeof(*bufs));
203   if (bufs == NULL)
204     return UVWASI_ENOMEM;
205 
206   for (i = 0; i < iovs_len; ++i)
207     bufs[i] = uv_buf_init(iovs[i].buf, iovs[i].buf_len);
208 
209   *buffers = bufs;
210   return UVWASI_ESUCCESS;
211 }
212 
213 
uvwasi__setup_ciovs(const uvwasi_t * uvwasi,uv_buf_t ** buffers,const uvwasi_ciovec_t * iovs,uvwasi_size_t iovs_len)214 static uvwasi_errno_t uvwasi__setup_ciovs(const uvwasi_t* uvwasi,
215                                           uv_buf_t** buffers,
216                                           const uvwasi_ciovec_t* iovs,
217                                           uvwasi_size_t iovs_len) {
218   uv_buf_t* bufs;
219   uvwasi_size_t i;
220 
221   if ((iovs_len * sizeof(*bufs)) / (sizeof(*bufs)) != iovs_len)
222     return UVWASI_ENOMEM;
223 
224   bufs = uvwasi__malloc(uvwasi, iovs_len * sizeof(*bufs));
225   if (bufs == NULL)
226     return UVWASI_ENOMEM;
227 
228   for (i = 0; i < iovs_len; ++i)
229     bufs[i] = uv_buf_init((char*)iovs[i].buf, iovs[i].buf_len);
230 
231   *buffers = bufs;
232   return UVWASI_ESUCCESS;
233 }
234 
235 typedef struct new_connection_data_s {
236   int done;
237 } new_connection_data_t;
238 
on_new_connection(uv_stream_t * server,int status)239 void on_new_connection(uv_stream_t *server, int status) {
240   // just do nothing
241 }
242 
uvwasi_init(uvwasi_t * uvwasi,const uvwasi_options_t * options)243 uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, const uvwasi_options_t* options) {
244   uv_fs_t realpath_req;
245   uv_fs_t open_req;
246   uvwasi_errno_t err;
247   uvwasi_size_t args_size;
248   uvwasi_size_t size;
249   uvwasi_size_t offset;
250   uvwasi_size_t env_count;
251   uvwasi_size_t env_buf_size;
252   uvwasi_size_t i;
253   int r;
254   struct sockaddr_in addr;
255 
256   if (uvwasi == NULL || options == NULL || options->fd_table_size == 0)
257     return UVWASI_EINVAL;
258 
259   // loop is only needed if there were pre-open sockets
260   uvwasi->loop = NULL;
261 
262   uvwasi->allocator = options->allocator;
263 
264   if (uvwasi->allocator == NULL)
265     uvwasi->allocator = &default_allocator;
266 
267   uvwasi->argv_buf = NULL;
268   uvwasi->argv = NULL;
269   uvwasi->env_buf = NULL;
270   uvwasi->env = NULL;
271   uvwasi->fds = NULL;
272 
273   args_size = 0;
274   for (i = 0; i < options->argc; ++i)
275     args_size += strlen(options->argv[i]) + 1;
276 
277   uvwasi->argc = options->argc;
278   uvwasi->argv_buf_size = args_size;
279 
280   if (args_size > 0) {
281     uvwasi->argv_buf = uvwasi__malloc(uvwasi, args_size);
282     if (uvwasi->argv_buf == NULL) {
283       err = UVWASI_ENOMEM;
284       goto exit;
285     }
286 
287     uvwasi->argv = uvwasi__calloc(uvwasi, options->argc, sizeof(char*));
288     if (uvwasi->argv == NULL) {
289       err = UVWASI_ENOMEM;
290       goto exit;
291     }
292 
293     offset = 0;
294     for (i = 0; i < options->argc; ++i) {
295       size = strlen(options->argv[i]) + 1;
296       memcpy(uvwasi->argv_buf + offset, options->argv[i], size);
297       uvwasi->argv[i] = uvwasi->argv_buf + offset;
298       offset += size;
299     }
300   }
301 
302   env_count = 0;
303   env_buf_size = 0;
304   if (options->envp != NULL) {
305     while (options->envp[env_count] != NULL) {
306       env_buf_size += strlen(options->envp[env_count]) + 1;
307       env_count++;
308     }
309   }
310 
311   uvwasi->envc = env_count;
312   uvwasi->env_buf_size = env_buf_size;
313 
314   if (env_buf_size > 0) {
315     uvwasi->env_buf = uvwasi__malloc(uvwasi, env_buf_size);
316     if (uvwasi->env_buf == NULL) {
317       err = UVWASI_ENOMEM;
318       goto exit;
319     }
320 
321     uvwasi->env = uvwasi__calloc(uvwasi, env_count, sizeof(char*));
322     if (uvwasi->env == NULL) {
323       err = UVWASI_ENOMEM;
324       goto exit;
325     }
326 
327     offset = 0;
328     for (i = 0; i < env_count; ++i) {
329       size = strlen(options->envp[i]) + 1;
330       memcpy(uvwasi->env_buf + offset, options->envp[i], size);
331       uvwasi->env[i] = uvwasi->env_buf + offset;
332       offset += size;
333     }
334   }
335 
336   for (i = 0; i < options->preopenc; ++i) {
337     if (options->preopens[i].real_path == NULL ||
338         options->preopens[i].mapped_path == NULL) {
339       err = UVWASI_EINVAL;
340       goto exit;
341     }
342   }
343 
344   for (i = 0; i < options->preopen_socketc; ++i) {
345     if (options->preopen_sockets[i].address == NULL ||
346         options->preopen_sockets[i].port > 65535) {
347       err = UVWASI_EINVAL;
348       goto exit;
349     }
350   }
351 
352   err = uvwasi_fd_table_init(uvwasi, options);
353   if (err != UVWASI_ESUCCESS)
354     goto exit;
355 
356   for (i = 0; i < options->preopenc; ++i) {
357     r = uv_fs_realpath(NULL,
358                        &realpath_req,
359                        options->preopens[i].real_path,
360                        NULL);
361     if (r != 0) {
362       err = uvwasi__translate_uv_error(r);
363       uv_fs_req_cleanup(&realpath_req);
364       goto exit;
365     }
366 
367     r = uv_fs_open(NULL, &open_req, realpath_req.ptr, 0, 0666, NULL);
368     if (r < 0) {
369       err = uvwasi__translate_uv_error(r);
370       uv_fs_req_cleanup(&realpath_req);
371       uv_fs_req_cleanup(&open_req);
372       goto exit;
373     }
374 
375     err = uvwasi_fd_table_insert_preopen(uvwasi,
376                                          uvwasi->fds,
377                                          open_req.result,
378                                          options->preopens[i].mapped_path,
379                                          realpath_req.ptr);
380     uv_fs_req_cleanup(&realpath_req);
381     uv_fs_req_cleanup(&open_req);
382 
383     if (err != UVWASI_ESUCCESS)
384       goto exit;
385   }
386 
387   if (options->preopen_socketc > 0) {
388     uvwasi->loop = uvwasi__malloc(uvwasi, sizeof(uv_loop_t));
389     r = uv_loop_init(uvwasi->loop);
390     if (r != 0) {
391       err = uvwasi__translate_uv_error(r);
392       goto exit;
393     }
394   }
395 
396   for (i = 0; i < options->preopen_socketc; ++i) {
397     uv_tcp_t* socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
398     uv_tcp_init(uvwasi->loop, socket);
399 
400     uv_ip4_addr(options->preopen_sockets[i].address, options->preopen_sockets[i].port, &addr);
401 
402     uv_tcp_bind(socket, (const struct sockaddr*)&addr, 0);
403     r = uv_listen((uv_stream_t*) socket, 128, on_new_connection);
404     if (r != 0) {
405       err = uvwasi__translate_uv_error(r);
406       goto exit;
407     }
408 
409     err = uvwasi_fd_table_insert_preopen_socket(uvwasi,
410                                          uvwasi->fds,
411                                          socket);
412 
413     if (err != UVWASI_ESUCCESS)
414       goto exit;
415   }
416 
417   return UVWASI_ESUCCESS;
418 
419 exit:
420   uvwasi_destroy(uvwasi);
421   return err;
422 }
423 
424 
uvwasi_destroy(uvwasi_t * uvwasi)425 void uvwasi_destroy(uvwasi_t* uvwasi) {
426   if (uvwasi == NULL)
427     return;
428 
429   uvwasi_fd_table_free(uvwasi, uvwasi->fds);
430   uvwasi__free(uvwasi, uvwasi->argv_buf);
431   uvwasi__free(uvwasi, uvwasi->argv);
432   uvwasi__free(uvwasi, uvwasi->env_buf);
433   uvwasi__free(uvwasi, uvwasi->env);
434   if (uvwasi->loop != NULL) {
435     uv_stop(uvwasi->loop);
436     uv_loop_close(uvwasi->loop);
437     uvwasi__free(uvwasi, uvwasi->loop);
438     uvwasi->loop = NULL;
439   }
440   uvwasi->fds = NULL;
441   uvwasi->argv_buf = NULL;
442   uvwasi->argv = NULL;
443   uvwasi->env_buf = NULL;
444   uvwasi->env = NULL;
445 }
446 
447 
uvwasi_options_init(uvwasi_options_t * options)448 void uvwasi_options_init(uvwasi_options_t* options) {
449   if (options == NULL)
450     return;
451 
452   options->in = 0;
453   options->out = 1;
454   options->err = 2;
455   options->fd_table_size = 3;
456   options->argc = 0;
457   options->argv = NULL;
458   options->envp = NULL;
459   options->preopenc = 0;
460   options->preopens = NULL;
461   options->preopen_socketc = 0;
462   options->preopen_sockets = NULL;
463   options->allocator = NULL;
464 }
465 
466 
uvwasi_embedder_remap_fd(uvwasi_t * uvwasi,const uvwasi_fd_t fd,uv_file new_host_fd)467 uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi,
468                                         const uvwasi_fd_t fd,
469                                         uv_file new_host_fd) {
470   struct uvwasi_fd_wrap_t* wrap;
471   uvwasi_errno_t err;
472 
473   if (uvwasi == NULL)
474     return UVWASI_EINVAL;
475 
476   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, 0, 0);
477   if (err != UVWASI_ESUCCESS)
478     return err;
479 
480   wrap->fd = new_host_fd;
481   uv_mutex_unlock(&wrap->mutex);
482   return UVWASI_ESUCCESS;
483 }
484 
485 
uvwasi_args_get(uvwasi_t * uvwasi,char ** argv,char * argv_buf)486 uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf) {
487   uvwasi_size_t i;
488 
489   UVWASI_DEBUG("uvwasi_args_get(uvwasi=%p, argv=%p, argv_buf=%p)\n",
490                uvwasi,
491                argv,
492                argv_buf);
493 
494   if (uvwasi == NULL || argv == NULL || argv_buf == NULL)
495     return UVWASI_EINVAL;
496 
497   for (i = 0; i < uvwasi->argc; ++i) {
498     argv[i] = argv_buf + (uvwasi->argv[i] - uvwasi->argv_buf);
499   }
500 
501   memcpy(argv_buf, uvwasi->argv_buf, uvwasi->argv_buf_size);
502   return UVWASI_ESUCCESS;
503 }
504 
505 
uvwasi_args_sizes_get(uvwasi_t * uvwasi,uvwasi_size_t * argc,uvwasi_size_t * argv_buf_size)506 uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi,
507                                      uvwasi_size_t* argc,
508                                      uvwasi_size_t* argv_buf_size) {
509   UVWASI_DEBUG("uvwasi_args_sizes_get(uvwasi=%p, argc=%p, argv_buf_size=%p)\n",
510                uvwasi,
511                argc,
512                argv_buf_size);
513 
514   if (uvwasi == NULL || argc == NULL || argv_buf_size == NULL)
515     return UVWASI_EINVAL;
516 
517   *argc = uvwasi->argc;
518   *argv_buf_size = uvwasi->argv_buf_size;
519   return UVWASI_ESUCCESS;
520 }
521 
522 
uvwasi_clock_res_get(uvwasi_t * uvwasi,uvwasi_clockid_t clock_id,uvwasi_timestamp_t * resolution)523 uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi,
524                                     uvwasi_clockid_t clock_id,
525                                     uvwasi_timestamp_t* resolution) {
526   UVWASI_DEBUG("uvwasi_clock_res_get(uvwasi=%p, clock_id=%d, resolution=%p)\n",
527                uvwasi,
528                clock_id,
529                resolution);
530 
531   if (uvwasi == NULL || resolution == NULL)
532     return UVWASI_EINVAL;
533 
534   switch (clock_id) {
535     case UVWASI_CLOCK_MONOTONIC:
536     case UVWASI_CLOCK_REALTIME:
537       *resolution = 1;  /* Nanosecond precision. */
538       return UVWASI_ESUCCESS;
539     case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
540       return uvwasi__clock_getres_process_cputime(resolution);
541     case UVWASI_CLOCK_THREAD_CPUTIME_ID:
542       return uvwasi__clock_getres_thread_cputime(resolution);
543     default:
544       return UVWASI_EINVAL;
545   }
546 }
547 
548 
uvwasi_clock_time_get(uvwasi_t * uvwasi,uvwasi_clockid_t clock_id,uvwasi_timestamp_t precision,uvwasi_timestamp_t * time)549 uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi,
550                                      uvwasi_clockid_t clock_id,
551                                      uvwasi_timestamp_t precision,
552                                      uvwasi_timestamp_t* time) {
553   UVWASI_DEBUG("uvwasi_clock_time_get(uvwasi=%p, clock_id=%d, "
554                "precision=%"PRIu64", time=%p)\n",
555                uvwasi,
556                clock_id,
557                precision,
558                time);
559 
560   if (uvwasi == NULL || time == NULL)
561     return UVWASI_EINVAL;
562 
563   switch (clock_id) {
564     case UVWASI_CLOCK_MONOTONIC:
565       *time = uv_hrtime();
566       return UVWASI_ESUCCESS;
567     case UVWASI_CLOCK_REALTIME:
568       return uvwasi__clock_gettime_realtime(time);
569     case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
570       return uvwasi__clock_gettime_process_cputime(time);
571     case UVWASI_CLOCK_THREAD_CPUTIME_ID:
572       return uvwasi__clock_gettime_thread_cputime(time);
573     default:
574       return UVWASI_EINVAL;
575   }
576 }
577 
578 
uvwasi_environ_get(uvwasi_t * uvwasi,char ** environment,char * environ_buf)579 uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi,
580                                   char** environment,
581                                   char* environ_buf) {
582   uvwasi_size_t i;
583 
584   UVWASI_DEBUG("uvwasi_environ_get(uvwasi=%p, environment=%p, "
585                "environ_buf=%p)\n",
586                uvwasi,
587                environment,
588                environ_buf);
589 
590   if (uvwasi == NULL || environment == NULL || environ_buf == NULL)
591     return UVWASI_EINVAL;
592 
593   for (i = 0; i < uvwasi->envc; ++i) {
594     environment[i] = environ_buf + (uvwasi->env[i] - uvwasi->env_buf);
595   }
596 
597   memcpy(environ_buf, uvwasi->env_buf, uvwasi->env_buf_size);
598   return UVWASI_ESUCCESS;
599 }
600 
601 
uvwasi_environ_sizes_get(uvwasi_t * uvwasi,uvwasi_size_t * environ_count,uvwasi_size_t * environ_buf_size)602 uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi,
603                                         uvwasi_size_t* environ_count,
604                                         uvwasi_size_t* environ_buf_size) {
605   UVWASI_DEBUG("uvwasi_environ_sizes_get(uvwasi=%p, environ_count=%p, "
606                "environ_buf_size=%p)\n",
607                uvwasi,
608                environ_count,
609                environ_buf_size);
610 
611   if (uvwasi == NULL || environ_count == NULL || environ_buf_size == NULL)
612     return UVWASI_EINVAL;
613 
614   *environ_count = uvwasi->envc;
615   *environ_buf_size = uvwasi->env_buf_size;
616   return UVWASI_ESUCCESS;
617 }
618 
619 
uvwasi_fd_advise(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filesize_t offset,uvwasi_filesize_t len,uvwasi_advice_t advice)620 uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
621                                 uvwasi_fd_t fd,
622                                 uvwasi_filesize_t offset,
623                                 uvwasi_filesize_t len,
624                                 uvwasi_advice_t advice) {
625   struct uvwasi_fd_wrap_t* wrap;
626   uvwasi_errno_t err;
627 #ifdef POSIX_FADV_NORMAL
628   int mapped_advice;
629   int r;
630 #endif /* POSIX_FADV_NORMAL */
631 
632   UVWASI_DEBUG("uvwasi_fd_advise(uvwasi=%p, fd=%d, offset=%"PRIu64", "
633                "len=%"PRIu64", advice=%d)\n",
634                uvwasi,
635                fd,
636                offset,
637                len,
638                advice);
639 
640   if (uvwasi == NULL)
641     return UVWASI_EINVAL;
642 
643   switch (advice) {
644     case UVWASI_ADVICE_DONTNEED:
645 #ifdef POSIX_FADV_NORMAL
646       mapped_advice = POSIX_FADV_DONTNEED;
647 #endif /* POSIX_FADV_NORMAL */
648       break;
649     case UVWASI_ADVICE_NOREUSE:
650 #ifdef POSIX_FADV_NORMAL
651       mapped_advice = POSIX_FADV_NOREUSE;
652 #endif /* POSIX_FADV_NORMAL */
653       break;
654     case UVWASI_ADVICE_NORMAL:
655 #ifdef POSIX_FADV_NORMAL
656       mapped_advice = POSIX_FADV_NORMAL;
657 #endif /* POSIX_FADV_NORMAL */
658       break;
659     case UVWASI_ADVICE_RANDOM:
660 #ifdef POSIX_FADV_NORMAL
661       mapped_advice = POSIX_FADV_RANDOM;
662 #endif /* POSIX_FADV_NORMAL */
663       break;
664     case UVWASI_ADVICE_SEQUENTIAL:
665 #ifdef POSIX_FADV_NORMAL
666       mapped_advice = POSIX_FADV_SEQUENTIAL;
667 #endif /* POSIX_FADV_NORMAL */
668       break;
669     case UVWASI_ADVICE_WILLNEED:
670 #ifdef POSIX_FADV_NORMAL
671       mapped_advice = POSIX_FADV_WILLNEED;
672 #endif /* POSIX_FADV_NORMAL */
673       break;
674     default:
675       return UVWASI_EINVAL;
676   }
677 
678   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_ADVISE, 0);
679   if (err != UVWASI_ESUCCESS)
680     return err;
681 
682   err = UVWASI_ESUCCESS;
683 
684 #ifdef POSIX_FADV_NORMAL
685   r = posix_fadvise(wrap->fd, offset, len, mapped_advice);
686   if (r != 0)
687     err = uvwasi__translate_uv_error(uv_translate_sys_error(r));
688 #endif /* POSIX_FADV_NORMAL */
689   uv_mutex_unlock(&wrap->mutex);
690   return err;
691 }
692 
693 
uvwasi_fd_allocate(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filesize_t offset,uvwasi_filesize_t len)694 uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi,
695                                   uvwasi_fd_t fd,
696                                   uvwasi_filesize_t offset,
697                                   uvwasi_filesize_t len) {
698 #if !defined(__POSIX__)
699   uv_fs_t req;
700   uint64_t st_size;
701 #endif /* !__POSIX__ */
702   struct uvwasi_fd_wrap_t* wrap;
703   uvwasi_errno_t err;
704   int r;
705 
706   UVWASI_DEBUG("uvwasi_fd_allocate(uvwasi=%p, fd=%d, offset=%"PRIu64", "
707                "len=%"PRIu64")\n",
708                uvwasi,
709                fd,
710                offset,
711                len);
712 
713   if (uvwasi == NULL)
714     return UVWASI_EINVAL;
715 
716   err = uvwasi_fd_table_get(uvwasi->fds,
717                             fd,
718                             &wrap,
719                             UVWASI_RIGHT_FD_ALLOCATE,
720                             0);
721   if (err != UVWASI_ESUCCESS)
722     return err;
723 
724   /* Try to use posix_fallocate(). If that's not an option, fall back to the
725      race condition prone combination of fstat() + ftruncate(). */
726 #if defined(__POSIX__)
727   r = posix_fallocate(wrap->fd, offset, len);
728   if (r != 0) {
729     err = uvwasi__translate_uv_error(uv_translate_sys_error(r));
730     goto exit;
731   }
732 #else
733   r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
734   st_size = req.statbuf.st_size;
735   uv_fs_req_cleanup(&req);
736   if (r != 0) {
737     err = uvwasi__translate_uv_error(r);
738     goto exit;
739   }
740 
741   if (st_size < offset + len) {
742     r = uv_fs_ftruncate(NULL, &req, wrap->fd, offset + len, NULL);
743     if (r != 0) {
744       err = uvwasi__translate_uv_error(r);
745       goto exit;
746     }
747   }
748 #endif /* __POSIX__ */
749 
750   err = UVWASI_ESUCCESS;
751 exit:
752   uv_mutex_unlock(&wrap->mutex);
753   return err;
754 }
755 
uvwasi_fd_close(uvwasi_t * uvwasi,uvwasi_fd_t fd)756 uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
757   struct uvwasi_fd_wrap_t* wrap;
758   uvwasi_errno_t err = 0;
759   uv_fs_t req;
760   int r;
761 
762   UVWASI_DEBUG("uvwasi_fd_close(uvwasi=%p, fd=%d)\n", uvwasi, fd);
763 
764   if (uvwasi == NULL)
765     return UVWASI_EINVAL;
766 
767   uvwasi_fd_table_lock(uvwasi->fds);
768 
769   err = uvwasi_fd_table_get_nolock(uvwasi->fds, fd, &wrap, 0, 0);
770   if (err != UVWASI_ESUCCESS)
771     goto exit;
772 
773   if (wrap->sock == NULL) {
774     r = uv_fs_close(NULL, &req, wrap->fd, NULL);
775     uv_mutex_unlock(&wrap->mutex);
776     uv_fs_req_cleanup(&req);
777   } else {
778     r = 0;
779     err = free_handle_sync(uvwasi, (uv_handle_t*) wrap->sock);
780     uv_mutex_unlock(&wrap->mutex);
781     if (err != UVWASI_ESUCCESS) {
782       goto exit;
783     }
784   }
785 
786   if (r != 0) {
787     err = uvwasi__translate_uv_error(r);
788     goto exit;
789   }
790 
791   err = uvwasi_fd_table_remove_nolock(uvwasi, uvwasi->fds, fd);
792 
793 exit:
794   uvwasi_fd_table_unlock(uvwasi->fds);
795   return err;
796 }
797 
798 
uvwasi_fd_datasync(uvwasi_t * uvwasi,uvwasi_fd_t fd)799 uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
800   struct uvwasi_fd_wrap_t* wrap;
801   uvwasi_errno_t err;
802   uv_fs_t req;
803   int r;
804 
805   UVWASI_DEBUG("uvwasi_fd_datasync(uvwasi=%p, fd=%d)\n", uvwasi, fd);
806 
807   if (uvwasi == NULL)
808     return UVWASI_EINVAL;
809 
810   err = uvwasi_fd_table_get(uvwasi->fds,
811                             fd,
812                             &wrap,
813                             UVWASI_RIGHT_FD_DATASYNC,
814                             0);
815   if (err != UVWASI_ESUCCESS)
816     return err;
817 
818   r = uv_fs_fdatasync(NULL, &req, wrap->fd, NULL);
819   uv_mutex_unlock(&wrap->mutex);
820   uv_fs_req_cleanup(&req);
821 
822   if (r != 0)
823     return uvwasi__translate_uv_error(r);
824 
825   return UVWASI_ESUCCESS;
826 }
827 
828 
uvwasi_fd_fdstat_get(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_fdstat_t * buf)829 uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi,
830                                     uvwasi_fd_t fd,
831                                     uvwasi_fdstat_t* buf) {
832   struct uvwasi_fd_wrap_t* wrap;
833   uvwasi_errno_t err;
834 #ifndef _WIN32
835   int r;
836 #endif
837 
838   UVWASI_DEBUG("uvwasi_fd_fdstat_get(uvwasi=%p, fd=%d, buf=%p)\n",
839                uvwasi,
840                fd,
841                buf);
842 
843   if (uvwasi == NULL || buf == NULL)
844     return UVWASI_EINVAL;
845 
846   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, 0, 0);
847   if (err != UVWASI_ESUCCESS)
848     return err;
849 
850   buf->fs_filetype = wrap->type;
851   buf->fs_rights_base = wrap->rights_base;
852   buf->fs_rights_inheriting = wrap->rights_inheriting;
853 #ifdef _WIN32
854   buf->fs_flags = 0;  /* TODO(cjihrig): Missing Windows support. */
855 #else
856   r = fcntl(wrap->fd, F_GETFL);
857   if (r < 0) {
858     err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
859     uv_mutex_unlock(&wrap->mutex);
860     return err;
861   }
862   buf->fs_flags = r;
863 #endif /* _WIN32 */
864 
865   uv_mutex_unlock(&wrap->mutex);
866   return UVWASI_ESUCCESS;
867 }
868 
869 
uvwasi_fd_fdstat_set_flags(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_fdflags_t flags)870 uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi,
871                                           uvwasi_fd_t fd,
872                                           uvwasi_fdflags_t flags) {
873 #ifdef _WIN32
874   UVWASI_DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n",
875                uvwasi,
876                fd,
877                flags);
878 
879   /* TODO(cjihrig): Windows is not supported. */
880   return UVWASI_ENOSYS;
881 #else
882   struct uvwasi_fd_wrap_t* wrap;
883   uvwasi_errno_t err;
884   int mapped_flags;
885   int r;
886 
887   UVWASI_DEBUG("uvwasi_fd_fdstat_set_flags(uvwasi=%p, fd=%d, flags=%d)\n",
888                uvwasi,
889                fd,
890                flags);
891 
892   if (uvwasi == NULL)
893     return UVWASI_EINVAL;
894 
895   err = uvwasi_fd_table_get(uvwasi->fds,
896                             fd,
897                             &wrap,
898                             UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS,
899                             0);
900   if (err != UVWASI_ESUCCESS)
901     return err;
902 
903   mapped_flags = 0;
904 
905   if ((flags & UVWASI_FDFLAG_APPEND) == UVWASI_FDFLAG_APPEND)
906     mapped_flags |= O_APPEND;
907 
908   if ((flags & UVWASI_FDFLAG_DSYNC) == UVWASI_FDFLAG_DSYNC)
909 #ifdef O_DSYNC
910     mapped_flags |= O_DSYNC;
911 #else
912     mapped_flags |= O_SYNC;
913 #endif /* O_DSYNC */
914 
915   if ((flags & UVWASI_FDFLAG_NONBLOCK) == UVWASI_FDFLAG_NONBLOCK)
916     mapped_flags |= O_NONBLOCK;
917 
918   if ((flags & UVWASI_FDFLAG_RSYNC) == UVWASI_FDFLAG_RSYNC)
919 #ifdef O_RSYNC
920     mapped_flags |= O_RSYNC;
921 #else
922     mapped_flags |= O_SYNC;
923 #endif /* O_RSYNC */
924 
925   if ((flags & UVWASI_FDFLAG_SYNC) == UVWASI_FDFLAG_SYNC)
926     mapped_flags |= O_SYNC;
927 
928   r = fcntl(wrap->fd, F_SETFL, mapped_flags);
929   if (r < 0)
930     err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
931   else
932     err = UVWASI_ESUCCESS;
933 
934   uv_mutex_unlock(&wrap->mutex);
935   return err;
936 #endif /* _WIN32 */
937 }
938 
939 
uvwasi_fd_fdstat_set_rights(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_rights_t fs_rights_base,uvwasi_rights_t fs_rights_inheriting)940 uvwasi_errno_t uvwasi_fd_fdstat_set_rights(uvwasi_t* uvwasi,
941                                            uvwasi_fd_t fd,
942                                            uvwasi_rights_t fs_rights_base,
943                                            uvwasi_rights_t fs_rights_inheriting
944                                           ) {
945   struct uvwasi_fd_wrap_t* wrap;
946   uvwasi_errno_t err;
947 
948   UVWASI_DEBUG("uvwasi_fd_fdstat_set_rights(uvwasi=%p, fd=%d, "
949                "fs_rights_base=%"PRIu64", fs_rights_inheriting=%"PRIu64")\n",
950                uvwasi,
951                fd,
952                fs_rights_base,
953                fs_rights_inheriting);
954 
955   if (uvwasi == NULL)
956     return UVWASI_EINVAL;
957 
958   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, 0, 0);
959   if (err != UVWASI_ESUCCESS)
960     return err;
961 
962   /* Check for attempts to add new permissions. */
963   if ((fs_rights_base | wrap->rights_base) > wrap->rights_base) {
964     err = UVWASI_ENOTCAPABLE;
965     goto exit;
966   }
967 
968   if ((fs_rights_inheriting | wrap->rights_inheriting) >
969       wrap->rights_inheriting) {
970     err = UVWASI_ENOTCAPABLE;
971     goto exit;
972   }
973 
974   wrap->rights_base = fs_rights_base;
975   wrap->rights_inheriting = fs_rights_inheriting;
976   err = UVWASI_ESUCCESS;
977 exit:
978   uv_mutex_unlock(&wrap->mutex);
979   return err;
980 }
981 
982 
uvwasi_fd_filestat_get(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filestat_t * buf)983 uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi,
984                                       uvwasi_fd_t fd,
985                                       uvwasi_filestat_t* buf) {
986   struct uvwasi_fd_wrap_t* wrap;
987   uv_fs_t req;
988   uvwasi_errno_t err;
989   int r;
990 
991   UVWASI_DEBUG("uvwasi_fd_filestat_get(uvwasi=%p, fd=%d, buf=%p)\n",
992                uvwasi,
993                fd,
994                buf);
995 
996   if (uvwasi == NULL || buf == NULL)
997     return UVWASI_EINVAL;
998 
999   err = uvwasi_fd_table_get(uvwasi->fds,
1000                             fd,
1001                             &wrap,
1002                             UVWASI_RIGHT_FD_FILESTAT_GET,
1003                             0);
1004   if (err != UVWASI_ESUCCESS)
1005     return err;
1006 
1007   r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
1008   if (r != 0) {
1009     err = uvwasi__translate_uv_error(r);
1010     goto exit;
1011   }
1012 
1013   uvwasi__stat_to_filestat(&req.statbuf, buf);
1014   err = UVWASI_ESUCCESS;
1015 exit:
1016   uv_mutex_unlock(&wrap->mutex);
1017   uv_fs_req_cleanup(&req);
1018   return err;
1019 }
1020 
1021 
uvwasi_fd_filestat_set_size(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filesize_t st_size)1022 uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi,
1023                                            uvwasi_fd_t fd,
1024                                            uvwasi_filesize_t st_size) {
1025   /* TODO(cjihrig): uv_fs_ftruncate() takes an int64_t. st_size is uint64_t. */
1026   struct uvwasi_fd_wrap_t* wrap;
1027   uv_fs_t req;
1028   uvwasi_errno_t err;
1029   int r;
1030 
1031   UVWASI_DEBUG("uvwasi_fd_filestat_set_size(uvwasi=%p, fd=%d, "
1032                "st_size=%"PRIu64")\n",
1033                uvwasi,
1034                fd,
1035                st_size);
1036 
1037   if (uvwasi == NULL)
1038     return UVWASI_EINVAL;
1039 
1040   err = uvwasi_fd_table_get(uvwasi->fds,
1041                             fd,
1042                             &wrap,
1043                             UVWASI_RIGHT_FD_FILESTAT_SET_SIZE,
1044                             0);
1045   if (err != UVWASI_ESUCCESS)
1046     return err;
1047 
1048   r = uv_fs_ftruncate(NULL, &req, wrap->fd, st_size, NULL);
1049   uv_mutex_unlock(&wrap->mutex);
1050   uv_fs_req_cleanup(&req);
1051 
1052   if (r != 0)
1053     return uvwasi__translate_uv_error(r);
1054 
1055   return UVWASI_ESUCCESS;
1056 }
1057 
1058 
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)1059 uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi,
1060                                             uvwasi_fd_t fd,
1061                                             uvwasi_timestamp_t st_atim,
1062                                             uvwasi_timestamp_t st_mtim,
1063                                             uvwasi_fstflags_t fst_flags) {
1064   struct uvwasi_fd_wrap_t* wrap;
1065   uvwasi_timestamp_t atim;
1066   uvwasi_timestamp_t mtim;
1067   uv_fs_t req;
1068   uvwasi_errno_t err;
1069   int r;
1070 
1071   UVWASI_DEBUG("uvwasi_fd_filestat_set_times(uvwasi=%p, fd=%d, "
1072                "st_atim=%"PRIu64", st_mtim=%"PRIu64", fst_flags=%d)\n",
1073                uvwasi,
1074                fd,
1075                st_atim,
1076                st_mtim,
1077                fst_flags);
1078 
1079   if (uvwasi == NULL)
1080     return UVWASI_EINVAL;
1081 
1082   VALIDATE_FSTFLAGS_OR_RETURN(fst_flags);
1083 
1084   err = uvwasi_fd_table_get(uvwasi->fds,
1085                             fd,
1086                             &wrap,
1087                             UVWASI_RIGHT_FD_FILESTAT_SET_TIMES,
1088                             0);
1089   if (err != UVWASI_ESUCCESS)
1090     return err;
1091 
1092   atim = st_atim;
1093   mtim = st_mtim;
1094   err = uvwasi__get_filestat_set_times(&atim,
1095                                        &mtim,
1096                                        fst_flags,
1097                                        &wrap->fd,
1098                                        NULL);
1099   if (err != UVWASI_ESUCCESS) {
1100     uv_mutex_unlock(&wrap->mutex);
1101     return err;
1102   }
1103 
1104   /* libuv does not currently support nanosecond precision. */
1105   r = uv_fs_futime(NULL, &req, wrap->fd, atim, mtim, NULL);
1106   uv_mutex_unlock(&wrap->mutex);
1107   uv_fs_req_cleanup(&req);
1108 
1109   if (r != 0)
1110     return uvwasi__translate_uv_error(r);
1111 
1112   return UVWASI_ESUCCESS;
1113 }
1114 
1115 
uvwasi_fd_pread(uvwasi_t * uvwasi,uvwasi_fd_t fd,const uvwasi_iovec_t * iovs,uvwasi_size_t iovs_len,uvwasi_filesize_t offset,uvwasi_size_t * nread)1116 uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi,
1117                                uvwasi_fd_t fd,
1118                                const uvwasi_iovec_t* iovs,
1119                                uvwasi_size_t iovs_len,
1120                                uvwasi_filesize_t offset,
1121                                uvwasi_size_t* nread) {
1122   struct uvwasi_fd_wrap_t* wrap;
1123   uv_buf_t* bufs;
1124   uv_fs_t req;
1125   uvwasi_errno_t err;
1126   size_t uvread;
1127   int r;
1128 
1129   UVWASI_DEBUG("uvwasi_fd_pread(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, "
1130                "offset=%"PRIu64", nread=%p)\n",
1131                uvwasi,
1132                fd,
1133                iovs,
1134                iovs_len,
1135                offset,
1136                nread);
1137 
1138   if (uvwasi == NULL || iovs == NULL || nread == NULL)
1139     return UVWASI_EINVAL;
1140 
1141   err = uvwasi_fd_table_get(uvwasi->fds,
1142                             fd,
1143                             &wrap,
1144                             UVWASI_RIGHT_FD_READ | UVWASI_RIGHT_FD_SEEK,
1145                             0);
1146   if (err != UVWASI_ESUCCESS)
1147     return err;
1148 
1149   err = uvwasi__setup_iovs(uvwasi, &bufs, iovs, iovs_len);
1150   if (err != UVWASI_ESUCCESS) {
1151     uv_mutex_unlock(&wrap->mutex);
1152     return err;
1153   }
1154 
1155   r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
1156   uv_mutex_unlock(&wrap->mutex);
1157   uvread = req.result;
1158   uv_fs_req_cleanup(&req);
1159   uvwasi__free(uvwasi, bufs);
1160 
1161   if (r < 0)
1162     return uvwasi__translate_uv_error(r);
1163 
1164   *nread = (uvwasi_size_t) uvread;
1165   return UVWASI_ESUCCESS;
1166 }
1167 
1168 
uvwasi_fd_prestat_get(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_prestat_t * buf)1169 uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi,
1170                                      uvwasi_fd_t fd,
1171                                      uvwasi_prestat_t* buf) {
1172   struct uvwasi_fd_wrap_t* wrap;
1173   uvwasi_errno_t err;
1174 
1175   UVWASI_DEBUG("uvwasi_fd_prestat_get(uvwasi=%p, fd=%d, buf=%p)\n",
1176                uvwasi,
1177                fd,
1178                buf);
1179 
1180   if (uvwasi == NULL || buf == NULL)
1181     return UVWASI_EINVAL;
1182 
1183   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, 0, 0);
1184   if (err != UVWASI_ESUCCESS)
1185     return err;
1186   if (wrap->preopen != 1) {
1187     err = UVWASI_EINVAL;
1188     goto exit;
1189   }
1190 
1191   buf->pr_type = UVWASI_PREOPENTYPE_DIR;
1192   buf->u.dir.pr_name_len = strlen(wrap->path);
1193   err = UVWASI_ESUCCESS;
1194 exit:
1195   uv_mutex_unlock(&wrap->mutex);
1196   return err;
1197 }
1198 
1199 
uvwasi_fd_prestat_dir_name(uvwasi_t * uvwasi,uvwasi_fd_t fd,char * path,uvwasi_size_t path_len)1200 uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi,
1201                                           uvwasi_fd_t fd,
1202                                           char* path,
1203                                           uvwasi_size_t path_len) {
1204   struct uvwasi_fd_wrap_t* wrap;
1205   uvwasi_errno_t err;
1206   size_t size;
1207 
1208   UVWASI_DEBUG("uvwasi_fd_prestat_dir_name(uvwasi=%p, fd=%d, path=%p, "
1209                "path_len=%d)\n",
1210                uvwasi,
1211                fd,
1212                path,
1213                path_len);
1214 
1215   if (uvwasi == NULL || path == NULL)
1216     return UVWASI_EINVAL;
1217 
1218   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, 0, 0);
1219   if (err != UVWASI_ESUCCESS)
1220     return err;
1221   if (wrap->preopen != 1) {
1222     err = UVWASI_EBADF;
1223     goto exit;
1224   }
1225 
1226   size = strlen(wrap->path);
1227   if (size > (size_t) path_len) {
1228     err = UVWASI_ENOBUFS;
1229     goto exit;
1230   }
1231 
1232   memcpy(path, wrap->path, size);
1233   err = UVWASI_ESUCCESS;
1234 exit:
1235   uv_mutex_unlock(&wrap->mutex);
1236   return err;
1237 }
1238 
1239 
uvwasi_fd_pwrite(uvwasi_t * uvwasi,uvwasi_fd_t fd,const uvwasi_ciovec_t * iovs,uvwasi_size_t iovs_len,uvwasi_filesize_t offset,uvwasi_size_t * nwritten)1240 uvwasi_errno_t uvwasi_fd_pwrite(uvwasi_t* uvwasi,
1241                                 uvwasi_fd_t fd,
1242                                 const uvwasi_ciovec_t* iovs,
1243                                 uvwasi_size_t iovs_len,
1244                                 uvwasi_filesize_t offset,
1245                                 uvwasi_size_t* nwritten) {
1246   struct uvwasi_fd_wrap_t* wrap;
1247   uv_buf_t* bufs;
1248   uv_fs_t req;
1249   uvwasi_errno_t err;
1250   size_t uvwritten;
1251   int r;
1252 
1253   UVWASI_DEBUG("uvwasi_fd_pwrite(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, "
1254                "offset=%"PRIu64", nwritten=%p)\n",
1255                uvwasi,
1256                fd,
1257                iovs,
1258                iovs_len,
1259                offset,
1260                nwritten);
1261 
1262   if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
1263     return UVWASI_EINVAL;
1264 
1265   err = uvwasi_fd_table_get(uvwasi->fds,
1266                             fd,
1267                             &wrap,
1268                             UVWASI_RIGHT_FD_WRITE | UVWASI_RIGHT_FD_SEEK,
1269                             0);
1270   if (err != UVWASI_ESUCCESS)
1271     return err;
1272 
1273   err = uvwasi__setup_ciovs(uvwasi, &bufs, iovs, iovs_len);
1274   if (err != UVWASI_ESUCCESS) {
1275     uv_mutex_unlock(&wrap->mutex);
1276     return err;
1277   }
1278 
1279   r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
1280   uv_mutex_unlock(&wrap->mutex);
1281   uvwritten = req.result;
1282   uv_fs_req_cleanup(&req);
1283   uvwasi__free(uvwasi, bufs);
1284 
1285   if (r < 0)
1286     return uvwasi__translate_uv_error(r);
1287 
1288   *nwritten = (uvwasi_size_t) uvwritten;
1289   return UVWASI_ESUCCESS;
1290 }
1291 
1292 
uvwasi_fd_read(uvwasi_t * uvwasi,uvwasi_fd_t fd,const uvwasi_iovec_t * iovs,uvwasi_size_t iovs_len,uvwasi_size_t * nread)1293 uvwasi_errno_t uvwasi_fd_read(uvwasi_t* uvwasi,
1294                               uvwasi_fd_t fd,
1295                               const uvwasi_iovec_t* iovs,
1296                               uvwasi_size_t iovs_len,
1297                               uvwasi_size_t* nread) {
1298   struct uvwasi_fd_wrap_t* wrap;
1299   uv_buf_t* bufs;
1300   uv_fs_t req;
1301   uvwasi_errno_t err;
1302   size_t uvread;
1303   int r;
1304 
1305   UVWASI_DEBUG("uvwasi_fd_read(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, "
1306                "nread=%p)\n",
1307                uvwasi,
1308                fd,
1309                iovs,
1310                iovs_len,
1311                nread);
1312 
1313   if (uvwasi == NULL || iovs == NULL || nread == NULL)
1314     return UVWASI_EINVAL;
1315 
1316   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_READ, 0);
1317   if (err != UVWASI_ESUCCESS)
1318     return err;
1319 
1320   err = uvwasi__setup_iovs(uvwasi, &bufs, iovs, iovs_len);
1321   if (err != UVWASI_ESUCCESS) {
1322     uv_mutex_unlock(&wrap->mutex);
1323     return err;
1324   }
1325 
1326   r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
1327   uv_mutex_unlock(&wrap->mutex);
1328   uvread = req.result;
1329   uv_fs_req_cleanup(&req);
1330   uvwasi__free(uvwasi, bufs);
1331 
1332   if (r < 0)
1333     return uvwasi__translate_uv_error(r);
1334 
1335   *nread = (uvwasi_size_t) uvread;
1336   return UVWASI_ESUCCESS;
1337 }
1338 
1339 
uvwasi_fd_readdir(uvwasi_t * uvwasi,uvwasi_fd_t fd,void * buf,uvwasi_size_t buf_len,uvwasi_dircookie_t cookie,uvwasi_size_t * bufused)1340 uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi,
1341                                  uvwasi_fd_t fd,
1342                                  void* buf,
1343                                  uvwasi_size_t buf_len,
1344                                  uvwasi_dircookie_t cookie,
1345                                  uvwasi_size_t* bufused) {
1346 #if defined(UVWASI_FD_READDIR_SUPPORTED)
1347   /* TODO(cjihrig): Avoid opening and closing the directory on each call. */
1348   struct uvwasi_fd_wrap_t* wrap;
1349   uvwasi_dirent_t dirent;
1350   uv_dirent_t dirents[UVWASI__READDIR_NUM_ENTRIES];
1351   uv_dir_t* dir;
1352   uv_fs_t req;
1353   uvwasi_errno_t err;
1354   size_t name_len;
1355   size_t available;
1356   size_t size_to_cp;
1357   long tell;
1358   int i;
1359   int r;
1360 #endif /* defined(UVWASI_FD_READDIR_SUPPORTED) */
1361 
1362   UVWASI_DEBUG("uvwasi_fd_readdir(uvwasi=%p, fd=%d, buf=%p, buf_len=%d, "
1363                "cookie=%"PRIu64", bufused=%p)\n",
1364                uvwasi,
1365                fd,
1366                buf,
1367                buf_len,
1368                cookie,
1369                bufused);
1370 
1371   if (uvwasi == NULL || buf == NULL || bufused == NULL)
1372     return UVWASI_EINVAL;
1373 
1374 #if defined(UVWASI_FD_READDIR_SUPPORTED)
1375   err = uvwasi_fd_table_get(uvwasi->fds,
1376                             fd,
1377                             &wrap,
1378                             UVWASI_RIGHT_FD_READDIR,
1379                             0);
1380   if (err != UVWASI_ESUCCESS)
1381     return err;
1382 
1383   /* Open the directory. */
1384   r = uv_fs_opendir(NULL, &req, wrap->real_path, NULL);
1385   if (r != 0) {
1386     uv_mutex_unlock(&wrap->mutex);
1387     return uvwasi__translate_uv_error(r);
1388   }
1389 
1390   /* Setup for reading the directory. */
1391   dir = req.ptr;
1392   dir->dirents = dirents;
1393   dir->nentries = UVWASI__READDIR_NUM_ENTRIES;
1394   uv_fs_req_cleanup(&req);
1395 
1396   /* Seek to the proper location in the directory. */
1397   if (cookie != UVWASI_DIRCOOKIE_START)
1398     seekdir(dir->dir, cookie);
1399 
1400   /* Read the directory entries into the provided buffer. */
1401   err = UVWASI_ESUCCESS;
1402   *bufused = 0;
1403   while (0 != (r = uv_fs_readdir(NULL, &req, dir, NULL))) {
1404     if (r < 0) {
1405       err = uvwasi__translate_uv_error(r);
1406       uv_fs_req_cleanup(&req);
1407       goto exit;
1408     }
1409 
1410     available = 0;
1411 
1412     for (i = 0; i < r; i++) {
1413       tell = telldir(dir->dir);
1414       if (tell < 0) {
1415         err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
1416         uv_fs_req_cleanup(&req);
1417         goto exit;
1418       }
1419 
1420       name_len = strlen(dirents[i].name);
1421       dirent.d_next = (uvwasi_dircookie_t) tell;
1422       /* TODO(cjihrig): libuv doesn't provide d_ino, and d_type is not
1423                         supported on all platforms. Use stat()? */
1424       dirent.d_ino = 0;
1425       dirent.d_namlen = name_len;
1426 
1427       switch (dirents[i].type) {
1428         case UV_DIRENT_FILE:
1429           dirent.d_type = UVWASI_FILETYPE_REGULAR_FILE;
1430           break;
1431         case UV_DIRENT_DIR:
1432           dirent.d_type = UVWASI_FILETYPE_DIRECTORY;
1433           break;
1434         case UV_DIRENT_SOCKET:
1435           dirent.d_type = UVWASI_FILETYPE_SOCKET_STREAM;
1436           break;
1437         case UV_DIRENT_LINK:
1438           dirent.d_type = UVWASI_FILETYPE_SYMBOLIC_LINK;
1439           break;
1440         case UV_DIRENT_CHAR:
1441           dirent.d_type = UVWASI_FILETYPE_CHARACTER_DEVICE;
1442           break;
1443         case UV_DIRENT_BLOCK:
1444           dirent.d_type = UVWASI_FILETYPE_BLOCK_DEVICE;
1445           break;
1446         case UV_DIRENT_FIFO:
1447         case UV_DIRENT_UNKNOWN:
1448         default:
1449           dirent.d_type = UVWASI_FILETYPE_UNKNOWN;
1450           break;
1451       }
1452 
1453       /* Write dirent to the buffer if it will fit. */
1454       if (UVWASI_SERDES_SIZE_dirent_t + *bufused > buf_len) {
1455         /* If there are more entries to be written to the buffer we set
1456          * bufused, which is the return value, to the length of the buffer
1457          * which indicates that there are more entries to be read.
1458          */
1459         *bufused = buf_len;
1460         break;
1461       }
1462 
1463       uvwasi_serdes_write_dirent_t(buf, *bufused, &dirent);
1464       *bufused += UVWASI_SERDES_SIZE_dirent_t;
1465       available = buf_len - *bufused;
1466 
1467       /* Write as much of the entry name to the buffer as possible. */
1468       size_to_cp = name_len > available ? available : name_len;
1469       memcpy((char*)buf + *bufused, dirents[i].name, size_to_cp);
1470       *bufused += size_to_cp;
1471       available = buf_len - *bufused;
1472     }
1473 
1474     uv_fs_req_cleanup(&req);
1475 
1476     if (available == 0)
1477       break;
1478   }
1479 
1480 exit:
1481   /* Close the directory. */
1482   r = uv_fs_closedir(NULL, &req, dir, NULL);
1483   uv_mutex_unlock(&wrap->mutex);
1484   uv_fs_req_cleanup(&req);
1485   if (r != 0)
1486     return uvwasi__translate_uv_error(r);
1487 
1488   return err;
1489 #else
1490   /* TODO(cjihrig): Need a solution for Windows and Android. */
1491   return UVWASI_ENOSYS;
1492 #endif /* defined(UVWASI_FD_READDIR_SUPPORTED) */
1493 }
1494 
1495 
uvwasi_fd_renumber(uvwasi_t * uvwasi,uvwasi_fd_t from,uvwasi_fd_t to)1496 uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi,
1497                                   uvwasi_fd_t from,
1498                                   uvwasi_fd_t to) {
1499   UVWASI_DEBUG("uvwasi_fd_renumber(uvwasi=%p, from=%d, to=%d)\n",
1500                uvwasi,
1501                from,
1502                to);
1503 
1504   if (uvwasi == NULL)
1505     return UVWASI_EINVAL;
1506 
1507   return uvwasi_fd_table_renumber(uvwasi, uvwasi->fds, to, from);
1508 }
1509 
1510 
uvwasi_fd_seek(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filedelta_t offset,uvwasi_whence_t whence,uvwasi_filesize_t * newoffset)1511 uvwasi_errno_t uvwasi_fd_seek(uvwasi_t* uvwasi,
1512                               uvwasi_fd_t fd,
1513                               uvwasi_filedelta_t offset,
1514                               uvwasi_whence_t whence,
1515                               uvwasi_filesize_t* newoffset) {
1516   struct uvwasi_fd_wrap_t* wrap;
1517   uvwasi_errno_t err;
1518 
1519   UVWASI_DEBUG("uvwasi_fd_seek(uvwasi=%p, fd=%d, offset=%"PRId64", "
1520                "whence=%d, newoffset=%p)\n",
1521                uvwasi,
1522                fd,
1523                offset,
1524                whence,
1525                newoffset);
1526 
1527   if (uvwasi == NULL || newoffset == NULL)
1528     return UVWASI_EINVAL;
1529 
1530   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_SEEK, 0);
1531   if (err != UVWASI_ESUCCESS)
1532     return err;
1533 
1534   err = uvwasi__lseek(wrap->fd, offset, whence, newoffset);
1535   uv_mutex_unlock(&wrap->mutex);
1536   return err;
1537 }
1538 
1539 
uvwasi_fd_sync(uvwasi_t * uvwasi,uvwasi_fd_t fd)1540 uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
1541   struct uvwasi_fd_wrap_t* wrap;
1542   uv_fs_t req;
1543   uvwasi_errno_t err;
1544   int r;
1545 
1546   UVWASI_DEBUG("uvwasi_fd_sync(uvwasi=%p, fd=%d)\n", uvwasi, fd);
1547 
1548   if (uvwasi == NULL)
1549     return UVWASI_EINVAL;
1550 
1551   err = uvwasi_fd_table_get(uvwasi->fds,
1552                             fd,
1553                             &wrap,
1554                             UVWASI_RIGHT_FD_SYNC,
1555                             0);
1556   if (err != UVWASI_ESUCCESS)
1557     return err;
1558 
1559   r = uv_fs_fsync(NULL, &req, wrap->fd, NULL);
1560   uv_mutex_unlock(&wrap->mutex);
1561   uv_fs_req_cleanup(&req);
1562 
1563   if (r != 0)
1564     return uvwasi__translate_uv_error(r);
1565 
1566   return UVWASI_ESUCCESS;
1567 }
1568 
1569 
uvwasi_fd_tell(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_filesize_t * offset)1570 uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi,
1571                               uvwasi_fd_t fd,
1572                               uvwasi_filesize_t* offset) {
1573   struct uvwasi_fd_wrap_t* wrap;
1574   uvwasi_errno_t err;
1575 
1576   UVWASI_DEBUG("uvwasi_fd_tell(uvwasi=%p, fd=%d, offset=%p)\n",
1577                uvwasi,
1578                fd,
1579                offset);
1580 
1581   if (uvwasi == NULL || offset == NULL)
1582     return UVWASI_EINVAL;
1583 
1584   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_TELL, 0);
1585   if (err != UVWASI_ESUCCESS)
1586     return err;
1587 
1588   err = uvwasi__lseek(wrap->fd, 0, UVWASI_WHENCE_CUR, offset);
1589   uv_mutex_unlock(&wrap->mutex);
1590   return err;
1591 }
1592 
1593 
uvwasi_fd_write(uvwasi_t * uvwasi,uvwasi_fd_t fd,const uvwasi_ciovec_t * iovs,uvwasi_size_t iovs_len,uvwasi_size_t * nwritten)1594 uvwasi_errno_t uvwasi_fd_write(uvwasi_t* uvwasi,
1595                                uvwasi_fd_t fd,
1596                                const uvwasi_ciovec_t* iovs,
1597                                uvwasi_size_t iovs_len,
1598                                uvwasi_size_t* nwritten) {
1599   struct uvwasi_fd_wrap_t* wrap;
1600   uv_buf_t* bufs;
1601   uv_fs_t req;
1602   uvwasi_errno_t err;
1603   size_t uvwritten;
1604   int r;
1605 
1606   UVWASI_DEBUG("uvwasi_fd_write(uvwasi=%p, fd=%d, iovs=%p, iovs_len=%d, "
1607                "nwritten=%p)\n",
1608                uvwasi,
1609                fd,
1610                iovs,
1611                iovs_len,
1612                nwritten);
1613 
1614   if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
1615     return UVWASI_EINVAL;
1616 
1617   err = uvwasi_fd_table_get(uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_WRITE, 0);
1618   if (err != UVWASI_ESUCCESS)
1619     return err;
1620 
1621   err = uvwasi__setup_ciovs(uvwasi, &bufs, iovs, iovs_len);
1622   if (err != UVWASI_ESUCCESS) {
1623     uv_mutex_unlock(&wrap->mutex);
1624     return err;
1625   }
1626 
1627   r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
1628   uv_mutex_unlock(&wrap->mutex);
1629   uvwritten = req.result;
1630   uv_fs_req_cleanup(&req);
1631   uvwasi__free(uvwasi, bufs);
1632 
1633   if (r < 0)
1634     return uvwasi__translate_uv_error(r);
1635 
1636   *nwritten = (uvwasi_size_t) uvwritten;
1637   return UVWASI_ESUCCESS;
1638 }
1639 
1640 
uvwasi_path_create_directory(uvwasi_t * uvwasi,uvwasi_fd_t fd,const char * path,uvwasi_size_t path_len)1641 uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi,
1642                                             uvwasi_fd_t fd,
1643                                             const char* path,
1644                                             uvwasi_size_t path_len) {
1645   char* resolved_path;
1646   struct uvwasi_fd_wrap_t* wrap;
1647   uv_fs_t req;
1648   uvwasi_errno_t err;
1649   int r;
1650 
1651   UVWASI_DEBUG("uvwasi_path_create_directory(uvwasi=%p, fd=%d, path='%s', "
1652                "path_len=%d)\n",
1653                uvwasi,
1654                fd,
1655                path,
1656                path_len);
1657 
1658   if (uvwasi == NULL || path == NULL)
1659     return UVWASI_EINVAL;
1660 
1661   err = uvwasi_fd_table_get(uvwasi->fds,
1662                             fd,
1663                             &wrap,
1664                             UVWASI_RIGHT_PATH_CREATE_DIRECTORY,
1665                             0);
1666   if (err != UVWASI_ESUCCESS)
1667     return err;
1668 
1669   err = uvwasi__resolve_path(uvwasi, wrap, path, path_len, &resolved_path, 0);
1670   if (err != UVWASI_ESUCCESS)
1671     goto exit;
1672 
1673   r = uv_fs_mkdir(NULL, &req, resolved_path, 0777, NULL);
1674   uv_fs_req_cleanup(&req);
1675   uvwasi__free(uvwasi, resolved_path);
1676 
1677   if (r != 0) {
1678     err = uvwasi__translate_uv_error(r);
1679     goto exit;
1680   }
1681 
1682   err = UVWASI_ESUCCESS;
1683 exit:
1684   uv_mutex_unlock(&wrap->mutex);
1685   return err;
1686 }
1687 
1688 
uvwasi_path_filestat_get(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_lookupflags_t flags,const char * path,uvwasi_size_t path_len,uvwasi_filestat_t * buf)1689 uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi,
1690                                         uvwasi_fd_t fd,
1691                                         uvwasi_lookupflags_t flags,
1692                                         const char* path,
1693                                         uvwasi_size_t path_len,
1694                                         uvwasi_filestat_t* buf) {
1695   char* resolved_path;
1696   struct uvwasi_fd_wrap_t* wrap;
1697   uv_fs_t req;
1698   uvwasi_errno_t err;
1699   int r;
1700 
1701   UVWASI_DEBUG("uvwasi_path_filestat_get(uvwasi=%p, fd=%d, flags=%d, "
1702                "path='%s', path_len=%d, buf=%p)\n",
1703                uvwasi,
1704                fd,
1705                flags,
1706                path,
1707                path_len,
1708                buf);
1709 
1710   if (uvwasi == NULL || path == NULL || buf == NULL)
1711     return UVWASI_EINVAL;
1712 
1713   err = uvwasi_fd_table_get(uvwasi->fds,
1714                             fd,
1715                             &wrap,
1716                             UVWASI_RIGHT_PATH_FILESTAT_GET,
1717                             0);
1718   if (err != UVWASI_ESUCCESS)
1719     return err;
1720 
1721   err = uvwasi__resolve_path(uvwasi,
1722                              wrap,
1723                              path,
1724                              path_len,
1725                              &resolved_path,
1726                              flags);
1727   if (err != UVWASI_ESUCCESS)
1728     goto exit;
1729 
1730   r = uv_fs_lstat(NULL, &req, resolved_path, NULL);
1731   uvwasi__free(uvwasi, resolved_path);
1732   if (r != 0) {
1733     uv_fs_req_cleanup(&req);
1734     err = uvwasi__translate_uv_error(r);
1735     goto exit;
1736   }
1737 
1738   uvwasi__stat_to_filestat(&req.statbuf, buf);
1739   uv_fs_req_cleanup(&req);
1740   err = UVWASI_ESUCCESS;
1741 exit:
1742   uv_mutex_unlock(&wrap->mutex);
1743   return err;
1744 }
1745 
1746 
uvwasi_path_filestat_set_times(uvwasi_t * uvwasi,uvwasi_fd_t fd,uvwasi_lookupflags_t flags,const char * path,uvwasi_size_t path_len,uvwasi_timestamp_t st_atim,uvwasi_timestamp_t st_mtim,uvwasi_fstflags_t fst_flags)1747 uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
1748                                               uvwasi_fd_t fd,
1749                                               uvwasi_lookupflags_t flags,
1750                                               const char* path,
1751                                               uvwasi_size_t path_len,
1752                                               uvwasi_timestamp_t st_atim,
1753                                               uvwasi_timestamp_t st_mtim,
1754                                               uvwasi_fstflags_t fst_flags) {
1755   char* resolved_path;
1756   struct uvwasi_fd_wrap_t* wrap;
1757   uvwasi_timestamp_t atim;
1758   uvwasi_timestamp_t mtim;
1759   uv_fs_t req;
1760   uvwasi_errno_t err;
1761   int r;
1762 
1763   UVWASI_DEBUG("uvwasi_path_filestat_set_times(uvwasi=%p, fd=%d, "
1764                "flags=%d, path='%s', path_len=%d, "
1765                "st_atim=%"PRIu64", st_mtim=%"PRIu64", fst_flags=%d)\n",
1766                uvwasi,
1767                fd,
1768                flags,
1769                path,
1770                path_len,
1771                st_atim,
1772                st_mtim,
1773                fst_flags);
1774 
1775   if (uvwasi == NULL || path == NULL)
1776     return UVWASI_EINVAL;
1777 
1778   VALIDATE_FSTFLAGS_OR_RETURN(fst_flags);
1779 
1780   err = uvwasi_fd_table_get(uvwasi->fds,
1781                             fd,
1782                             &wrap,
1783                             UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES,
1784                             0);
1785   if (err != UVWASI_ESUCCESS)
1786     return err;
1787 
1788   err = uvwasi__resolve_path(uvwasi,
1789                              wrap,
1790                              path,
1791                              path_len,
1792                              &resolved_path,
1793                              flags);
1794   if (err != UVWASI_ESUCCESS)
1795     goto exit;
1796 
1797   atim = st_atim;
1798   mtim = st_mtim;
1799   err = uvwasi__get_filestat_set_times(&atim,
1800                                        &mtim,
1801                                        fst_flags,
1802                                        NULL,
1803                                        resolved_path);
1804   if (err != UVWASI_ESUCCESS) {
1805     uvwasi__free(uvwasi, resolved_path);
1806     goto exit;
1807   }
1808 
1809   /* libuv does not currently support nanosecond precision. */
1810   r = uv_fs_lutime(NULL, &req, resolved_path, atim, mtim, NULL);
1811   uvwasi__free(uvwasi, resolved_path);
1812   uv_fs_req_cleanup(&req);
1813 
1814   if (r != 0) {
1815     err = uvwasi__translate_uv_error(r);
1816     goto exit;
1817   }
1818 
1819   err = UVWASI_ESUCCESS;
1820 exit:
1821   uv_mutex_unlock(&wrap->mutex);
1822   return err;
1823 }
1824 
1825 
uvwasi_path_link(uvwasi_t * uvwasi,uvwasi_fd_t old_fd,uvwasi_lookupflags_t old_flags,const char * old_path,uvwasi_size_t old_path_len,uvwasi_fd_t new_fd,const char * new_path,uvwasi_size_t new_path_len)1826 uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi,
1827                                 uvwasi_fd_t old_fd,
1828                                 uvwasi_lookupflags_t old_flags,
1829                                 const char* old_path,
1830                                 uvwasi_size_t old_path_len,
1831                                 uvwasi_fd_t new_fd,
1832                                 const char* new_path,
1833                                 uvwasi_size_t new_path_len) {
1834   char* resolved_old_path;
1835   char* resolved_new_path;
1836   struct uvwasi_fd_wrap_t* old_wrap;
1837   struct uvwasi_fd_wrap_t* new_wrap;
1838   uvwasi_errno_t err;
1839   uv_fs_t req;
1840   int r;
1841 
1842   UVWASI_DEBUG("uvwasi_path_link(uvwasi=%p, old_fd=%d, old_flags=%d, "
1843                "old_path='%s', old_path_len=%d, new_fd=%d, new_path='%s', "
1844                "new_path_len=%d)\n",
1845                uvwasi,
1846                old_fd,
1847                old_flags,
1848                old_path,
1849                old_path_len,
1850                new_fd,
1851                new_path,
1852                new_path_len);
1853 
1854   if (uvwasi == NULL || old_path == NULL || new_path == NULL)
1855     return UVWASI_EINVAL;
1856 
1857   uvwasi_fd_table_lock(uvwasi->fds);
1858 
1859   if (old_fd == new_fd) {
1860     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
1861                                      old_fd,
1862                                      &old_wrap,
1863                                      UVWASI_RIGHT_PATH_LINK_SOURCE |
1864                                      UVWASI_RIGHT_PATH_LINK_TARGET,
1865                                      0);
1866     new_wrap = old_wrap;
1867   } else {
1868     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
1869                                      old_fd,
1870                                      &old_wrap,
1871                                      UVWASI_RIGHT_PATH_LINK_SOURCE,
1872                                      0);
1873     if (err != UVWASI_ESUCCESS) {
1874       uvwasi_fd_table_unlock(uvwasi->fds);
1875       return err;
1876     }
1877 
1878     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
1879                                      new_fd,
1880                                      &new_wrap,
1881                                      UVWASI_RIGHT_PATH_LINK_TARGET,
1882                                      0);
1883     if (err != UVWASI_ESUCCESS)
1884       uv_mutex_unlock(&old_wrap->mutex);
1885   }
1886 
1887   uvwasi_fd_table_unlock(uvwasi->fds);
1888 
1889   if (err != UVWASI_ESUCCESS)
1890     return err;
1891 
1892   resolved_old_path = NULL;
1893   resolved_new_path = NULL;
1894 
1895   err = uvwasi__resolve_path(uvwasi,
1896                              old_wrap,
1897                              old_path,
1898                              old_path_len,
1899                              &resolved_old_path,
1900                              old_flags);
1901   if (err != UVWASI_ESUCCESS)
1902     goto exit;
1903 
1904   err = uvwasi__resolve_path(uvwasi,
1905                              new_wrap,
1906                              new_path,
1907                              new_path_len,
1908                              &resolved_new_path,
1909                              0);
1910   if (err != UVWASI_ESUCCESS)
1911     goto exit;
1912 
1913   r = uv_fs_link(NULL, &req, resolved_old_path, resolved_new_path, NULL);
1914   uv_fs_req_cleanup(&req);
1915   if (r != 0) {
1916     err = uvwasi__translate_uv_error(r);
1917     goto exit;
1918   }
1919 
1920   err = UVWASI_ESUCCESS;
1921 exit:
1922   uv_mutex_unlock(&new_wrap->mutex);
1923   if (old_fd != new_fd)
1924     uv_mutex_unlock(&old_wrap->mutex);
1925 
1926   uvwasi__free(uvwasi, resolved_old_path);
1927   uvwasi__free(uvwasi, resolved_new_path);
1928   return err;
1929 }
1930 
1931 
uvwasi_path_open(uvwasi_t * uvwasi,uvwasi_fd_t dirfd,uvwasi_lookupflags_t dirflags,const char * path,uvwasi_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)1932 uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
1933                                 uvwasi_fd_t dirfd,
1934                                 uvwasi_lookupflags_t dirflags,
1935                                 const char* path,
1936                                 uvwasi_size_t path_len,
1937                                 uvwasi_oflags_t o_flags,
1938                                 uvwasi_rights_t fs_rights_base,
1939                                 uvwasi_rights_t fs_rights_inheriting,
1940                                 uvwasi_fdflags_t fs_flags,
1941                                 uvwasi_fd_t* fd) {
1942   char* resolved_path;
1943   uvwasi_rights_t needed_inheriting;
1944   uvwasi_rights_t needed_base;
1945   uvwasi_rights_t max_base;
1946   uvwasi_rights_t max_inheriting;
1947   struct uvwasi_fd_wrap_t* dirfd_wrap;
1948   struct uvwasi_fd_wrap_t *wrap;
1949   uvwasi_filetype_t filetype;
1950   uvwasi_errno_t err;
1951   uv_fs_t req;
1952   int flags;
1953   int read;
1954   int write;
1955   int r;
1956 
1957   UVWASI_DEBUG("uvwasi_path_open(uvwasi=%p, dirfd=%d, dirflags=%d, path='%s', "
1958                "path_len=%d, o_flags=%d, fs_rights_base=%"PRIu64", "
1959                "fs_rights_inheriting=%"PRIu64", fs_flags=%d, fd=%p)\n",
1960                uvwasi,
1961                dirfd,
1962                dirflags,
1963                path,
1964                path_len,
1965                o_flags,
1966                fs_rights_base,
1967                fs_rights_inheriting,
1968                fs_flags,
1969                fd);
1970 
1971   if (uvwasi == NULL || path == NULL || fd == NULL)
1972     return UVWASI_EINVAL;
1973 
1974   read = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_READ |
1975                                  UVWASI_RIGHT_FD_READDIR));
1976   write = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_DATASYNC |
1977                                   UVWASI_RIGHT_FD_WRITE |
1978                                   UVWASI_RIGHT_FD_ALLOCATE |
1979                                   UVWASI_RIGHT_FD_FILESTAT_SET_SIZE));
1980   flags = write ? read ? UV_FS_O_RDWR : UV_FS_O_WRONLY : UV_FS_O_RDONLY;
1981   needed_base = UVWASI_RIGHT_PATH_OPEN;
1982   needed_inheriting = fs_rights_base | fs_rights_inheriting;
1983 
1984   if ((o_flags & UVWASI_O_CREAT) != 0) {
1985     flags |= UV_FS_O_CREAT;
1986     needed_base |= UVWASI_RIGHT_PATH_CREATE_FILE;
1987   }
1988   if ((o_flags & UVWASI_O_DIRECTORY) != 0)
1989     flags |= UV_FS_O_DIRECTORY;
1990   if ((o_flags & UVWASI_O_EXCL) != 0)
1991     flags |= UV_FS_O_EXCL;
1992   if ((o_flags & UVWASI_O_TRUNC) != 0) {
1993     flags |= UV_FS_O_TRUNC;
1994     needed_base |= UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE;
1995   }
1996 
1997   if ((fs_flags & UVWASI_FDFLAG_APPEND) != 0)
1998     flags |= UV_FS_O_APPEND;
1999   if ((fs_flags & UVWASI_FDFLAG_DSYNC) != 0) {
2000     flags |= UV_FS_O_DSYNC;
2001     needed_inheriting |= UVWASI_RIGHT_FD_DATASYNC;
2002   }
2003   if ((fs_flags & UVWASI_FDFLAG_NONBLOCK) != 0)
2004     flags |= UV_FS_O_NONBLOCK;
2005   if ((fs_flags & UVWASI_FDFLAG_RSYNC) != 0) {
2006 #ifdef O_RSYNC
2007     flags |= O_RSYNC; /* libuv has no UV_FS_O_RSYNC. */
2008 #else
2009     flags |= UV_FS_O_SYNC;
2010 #endif
2011     needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
2012   }
2013   if ((fs_flags & UVWASI_FDFLAG_SYNC) != 0) {
2014     flags |= UV_FS_O_SYNC;
2015     needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
2016   }
2017   if (write && (flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC)) == 0)
2018     needed_inheriting |= UVWASI_RIGHT_FD_SEEK;
2019 
2020   err = uvwasi_fd_table_get(uvwasi->fds,
2021                             dirfd,
2022                             &dirfd_wrap,
2023                             needed_base,
2024                             needed_inheriting);
2025   if (err != UVWASI_ESUCCESS)
2026     return err;
2027 
2028   err = uvwasi__resolve_path(uvwasi,
2029                              dirfd_wrap,
2030                              path,
2031                              path_len,
2032                              &resolved_path,
2033                              dirflags);
2034   if (err != UVWASI_ESUCCESS) {
2035     uv_mutex_unlock(&dirfd_wrap->mutex);
2036     return err;
2037   }
2038 
2039   r = uv_fs_open(NULL, &req, resolved_path, flags, 0666, NULL);
2040   uv_mutex_unlock(&dirfd_wrap->mutex);
2041   uv_fs_req_cleanup(&req);
2042 
2043   if (r < 0) {
2044     uvwasi__free(uvwasi, resolved_path);
2045     return uvwasi__translate_uv_error(r);
2046   }
2047 
2048   /* Not all platforms support UV_FS_O_DIRECTORY, so get the file type and check
2049      it here. */
2050   err = uvwasi__get_filetype_by_fd(r, &filetype);
2051   if (err != UVWASI_ESUCCESS)
2052     goto close_file_and_error_exit;
2053 
2054   if ((o_flags & UVWASI_O_DIRECTORY) != 0 &&
2055       filetype != UVWASI_FILETYPE_DIRECTORY) {
2056     err = UVWASI_ENOTDIR;
2057     goto close_file_and_error_exit;
2058   }
2059 
2060   err = uvwasi__get_rights(r, flags, filetype, &max_base, &max_inheriting);
2061   if (err != UVWASI_ESUCCESS)
2062     goto close_file_and_error_exit;
2063 
2064   err = uvwasi_fd_table_insert(uvwasi,
2065                                uvwasi->fds,
2066                                r,
2067                                NULL,
2068                                resolved_path,
2069                                resolved_path,
2070                                filetype,
2071                                fs_rights_base & max_base,
2072                                fs_rights_inheriting & max_inheriting,
2073                                0,
2074                                &wrap);
2075   if (err != UVWASI_ESUCCESS)
2076     goto close_file_and_error_exit;
2077 
2078   *fd = wrap->id;
2079   uv_mutex_unlock(&wrap->mutex);
2080   uvwasi__free(uvwasi, resolved_path);
2081   return UVWASI_ESUCCESS;
2082 
2083 close_file_and_error_exit:
2084   uv_fs_close(NULL, &req, r, NULL);
2085   uv_fs_req_cleanup(&req);
2086   uvwasi__free(uvwasi, resolved_path);
2087   return err;
2088 }
2089 
2090 
uvwasi_path_readlink(uvwasi_t * uvwasi,uvwasi_fd_t fd,const char * path,uvwasi_size_t path_len,char * buf,uvwasi_size_t buf_len,uvwasi_size_t * bufused)2091 uvwasi_errno_t uvwasi_path_readlink(uvwasi_t* uvwasi,
2092                                     uvwasi_fd_t fd,
2093                                     const char* path,
2094                                     uvwasi_size_t path_len,
2095                                     char* buf,
2096                                     uvwasi_size_t buf_len,
2097                                     uvwasi_size_t* bufused) {
2098   char* resolved_path;
2099   struct uvwasi_fd_wrap_t* wrap;
2100   uvwasi_errno_t err;
2101   uv_fs_t req;
2102   size_t len;
2103   int r;
2104 
2105   UVWASI_DEBUG("uvwasi_path_readlink(uvwasi=%p, fd=%d, path='%s', path_len=%d, "
2106                "buf=%p, buf_len=%d, bufused=%p)\n",
2107                uvwasi,
2108                fd,
2109                path,
2110                path_len,
2111                buf,
2112                buf_len,
2113                bufused);
2114 
2115   if (uvwasi == NULL || path == NULL || buf == NULL || bufused == NULL)
2116     return UVWASI_EINVAL;
2117 
2118   err = uvwasi_fd_table_get(uvwasi->fds,
2119                             fd,
2120                             &wrap,
2121                             UVWASI_RIGHT_PATH_READLINK,
2122                             0);
2123   if (err != UVWASI_ESUCCESS)
2124     return err;
2125 
2126   err = uvwasi__resolve_path(uvwasi, wrap, path, path_len, &resolved_path, 0);
2127   if (err != UVWASI_ESUCCESS) {
2128     uv_mutex_unlock(&wrap->mutex);
2129     return err;
2130   }
2131 
2132   r = uv_fs_readlink(NULL, &req, resolved_path, NULL);
2133   uv_mutex_unlock(&wrap->mutex);
2134   uvwasi__free(uvwasi, resolved_path);
2135   if (r != 0) {
2136     uv_fs_req_cleanup(&req);
2137     return uvwasi__translate_uv_error(r);
2138   }
2139 
2140   len = strnlen(req.ptr, buf_len);
2141   if (len >= buf_len) {
2142     uv_fs_req_cleanup(&req);
2143     return UVWASI_ENOBUFS;
2144   }
2145 
2146   memcpy(buf, req.ptr, len);
2147   buf[len] = '\0';
2148   *bufused = len + 1;
2149   uv_fs_req_cleanup(&req);
2150   return UVWASI_ESUCCESS;
2151 }
2152 
2153 
uvwasi_path_remove_directory(uvwasi_t * uvwasi,uvwasi_fd_t fd,const char * path,uvwasi_size_t path_len)2154 uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi,
2155                                             uvwasi_fd_t fd,
2156                                             const char* path,
2157                                             uvwasi_size_t path_len) {
2158   char* resolved_path;
2159   struct uvwasi_fd_wrap_t* wrap;
2160   uv_fs_t req;
2161   uvwasi_errno_t err;
2162   int r;
2163 
2164   UVWASI_DEBUG("uvwasi_path_remove_directory(uvwasi=%p, fd=%d, path='%s', "
2165                "path_len=%d)\n",
2166                uvwasi,
2167                fd,
2168                path,
2169                path_len);
2170 
2171   if (uvwasi == NULL || path == NULL)
2172     return UVWASI_EINVAL;
2173 
2174   err = uvwasi_fd_table_get(uvwasi->fds,
2175                             fd,
2176                             &wrap,
2177                             UVWASI_RIGHT_PATH_REMOVE_DIRECTORY,
2178                             0);
2179   if (err != UVWASI_ESUCCESS)
2180     return err;
2181 
2182   err = uvwasi__resolve_path(uvwasi, wrap, path, path_len, &resolved_path, 0);
2183   if (err != UVWASI_ESUCCESS) {
2184     uv_mutex_unlock(&wrap->mutex);
2185     return err;
2186   }
2187 
2188   r = uv_fs_rmdir(NULL, &req, resolved_path, NULL);
2189   uv_mutex_unlock(&wrap->mutex);
2190   uvwasi__free(uvwasi, resolved_path);
2191   uv_fs_req_cleanup(&req);
2192 
2193   if (r != 0)
2194     return uvwasi__translate_uv_error(r);
2195 
2196   return UVWASI_ESUCCESS;
2197 }
2198 
2199 
uvwasi_path_rename(uvwasi_t * uvwasi,uvwasi_fd_t old_fd,const char * old_path,uvwasi_size_t old_path_len,uvwasi_fd_t new_fd,const char * new_path,uvwasi_size_t new_path_len)2200 uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi,
2201                                   uvwasi_fd_t old_fd,
2202                                   const char* old_path,
2203                                   uvwasi_size_t old_path_len,
2204                                   uvwasi_fd_t new_fd,
2205                                   const char* new_path,
2206                                   uvwasi_size_t new_path_len) {
2207   char* resolved_old_path;
2208   char* resolved_new_path;
2209   struct uvwasi_fd_wrap_t* old_wrap;
2210   struct uvwasi_fd_wrap_t* new_wrap;
2211   uvwasi_errno_t err;
2212   uv_fs_t req;
2213   int r;
2214 
2215   UVWASI_DEBUG("uvwasi_path_rename(uvwasi=%p, old_fd=%d, old_path='%s', "
2216                "old_path_len=%d, new_fd=%d, new_path='%s', new_path_len=%d)\n",
2217                uvwasi,
2218                old_fd,
2219                old_path,
2220                old_path_len,
2221                new_fd,
2222                new_path,
2223                new_path_len);
2224 
2225   if (uvwasi == NULL || old_path == NULL || new_path == NULL)
2226     return UVWASI_EINVAL;
2227 
2228   uvwasi_fd_table_lock(uvwasi->fds);
2229 
2230   if (old_fd == new_fd) {
2231     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
2232                                      old_fd,
2233                                      &old_wrap,
2234                                      UVWASI_RIGHT_PATH_RENAME_SOURCE |
2235                                      UVWASI_RIGHT_PATH_RENAME_TARGET,
2236                                      0);
2237     new_wrap = old_wrap;
2238   } else {
2239     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
2240                                      old_fd,
2241                                      &old_wrap,
2242                                      UVWASI_RIGHT_PATH_RENAME_SOURCE,
2243                                      0);
2244     if (err != UVWASI_ESUCCESS) {
2245       uvwasi_fd_table_unlock(uvwasi->fds);
2246       return err;
2247     }
2248 
2249     err = uvwasi_fd_table_get_nolock(uvwasi->fds,
2250                                      new_fd,
2251                                      &new_wrap,
2252                                      UVWASI_RIGHT_PATH_RENAME_TARGET,
2253                                      0);
2254     if (err != UVWASI_ESUCCESS)
2255       uv_mutex_unlock(&old_wrap->mutex);
2256   }
2257 
2258   uvwasi_fd_table_unlock(uvwasi->fds);
2259 
2260   if (err != UVWASI_ESUCCESS)
2261     return err;
2262 
2263   resolved_old_path = NULL;
2264   resolved_new_path = NULL;
2265 
2266   err = uvwasi__resolve_path(uvwasi,
2267                              old_wrap,
2268                              old_path,
2269                              old_path_len,
2270                              &resolved_old_path,
2271                              0);
2272   if (err != UVWASI_ESUCCESS)
2273     goto exit;
2274 
2275   err = uvwasi__resolve_path(uvwasi,
2276                              new_wrap,
2277                              new_path,
2278                              new_path_len,
2279                              &resolved_new_path,
2280                              0);
2281   if (err != UVWASI_ESUCCESS)
2282     goto exit;
2283 
2284   r = uv_fs_rename(NULL, &req, resolved_old_path, resolved_new_path, NULL);
2285   uv_fs_req_cleanup(&req);
2286   if (r != 0) {
2287     err = uvwasi__translate_uv_error(r);
2288     goto exit;
2289   }
2290 
2291   err = UVWASI_ESUCCESS;
2292 exit:
2293   uv_mutex_unlock(&new_wrap->mutex);
2294   if (old_fd != new_fd)
2295     uv_mutex_unlock(&old_wrap->mutex);
2296 
2297   uvwasi__free(uvwasi, resolved_old_path);
2298   uvwasi__free(uvwasi, resolved_new_path);
2299   return err;
2300 }
2301 
2302 
uvwasi_path_symlink(uvwasi_t * uvwasi,const char * old_path,uvwasi_size_t old_path_len,uvwasi_fd_t fd,const char * new_path,uvwasi_size_t new_path_len)2303 uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
2304                                    const char* old_path,
2305                                    uvwasi_size_t old_path_len,
2306                                    uvwasi_fd_t fd,
2307                                    const char* new_path,
2308                                    uvwasi_size_t new_path_len) {
2309   char* resolved_new_path;
2310   struct uvwasi_fd_wrap_t* wrap;
2311   uvwasi_errno_t err;
2312   uv_fs_t req;
2313   int r;
2314 
2315   UVWASI_DEBUG("uvwasi_path_symlink(uvwasi=%p, old_path='%s', old_path_len=%d, "
2316                "fd=%d, new_path='%s', new_path_len=%d)\n",
2317                uvwasi,
2318                old_path,
2319                old_path_len,
2320                fd,
2321                new_path,
2322                new_path_len);
2323 
2324   if (uvwasi == NULL || old_path == NULL || new_path == NULL)
2325     return UVWASI_EINVAL;
2326 
2327   err = uvwasi_fd_table_get(uvwasi->fds,
2328                             fd,
2329                             &wrap,
2330                             UVWASI_RIGHT_PATH_SYMLINK,
2331                             0);
2332   if (err != UVWASI_ESUCCESS)
2333     return err;
2334 
2335   err = uvwasi__resolve_path(uvwasi,
2336                              wrap,
2337                              new_path,
2338                              new_path_len,
2339                              &resolved_new_path,
2340                              0);
2341   if (err != UVWASI_ESUCCESS) {
2342     uv_mutex_unlock(&wrap->mutex);
2343     return err;
2344   }
2345 
2346   /* Windows support may require setting the flags option. */
2347   r = uv_fs_symlink(NULL, &req, old_path, resolved_new_path, 0, NULL);
2348   uv_mutex_unlock(&wrap->mutex);
2349   uvwasi__free(uvwasi, resolved_new_path);
2350   uv_fs_req_cleanup(&req);
2351   if (r != 0)
2352     return uvwasi__translate_uv_error(r);
2353 
2354   return UVWASI_ESUCCESS;
2355 }
2356 
2357 
uvwasi_path_unlink_file(uvwasi_t * uvwasi,uvwasi_fd_t fd,const char * path,uvwasi_size_t path_len)2358 uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi,
2359                                        uvwasi_fd_t fd,
2360                                        const char* path,
2361                                        uvwasi_size_t path_len) {
2362   char* resolved_path;
2363   struct uvwasi_fd_wrap_t* wrap;
2364   uv_fs_t req;
2365   uvwasi_errno_t err;
2366   int r;
2367 
2368   UVWASI_DEBUG("uvwasi_path_unlink_file(uvwasi=%p, fd=%d, path='%s', "
2369                "path_len=%d)\n",
2370                uvwasi,
2371                fd,
2372                path,
2373                path_len);
2374 
2375   if (uvwasi == NULL || path == NULL)
2376     return UVWASI_EINVAL;
2377 
2378   err = uvwasi_fd_table_get(uvwasi->fds,
2379                             fd,
2380                             &wrap,
2381                             UVWASI_RIGHT_PATH_UNLINK_FILE,
2382                             0);
2383   if (err != UVWASI_ESUCCESS)
2384     return err;
2385 
2386   err = uvwasi__resolve_path(uvwasi, wrap, path, path_len, &resolved_path, 0);
2387   if (err != UVWASI_ESUCCESS) {
2388     uv_mutex_unlock(&wrap->mutex);
2389     return err;
2390   }
2391 
2392   r = uv_fs_unlink(NULL, &req, resolved_path, NULL);
2393   uv_mutex_unlock(&wrap->mutex);
2394   uvwasi__free(uvwasi, resolved_path);
2395   uv_fs_req_cleanup(&req);
2396 
2397   if (r != 0)
2398     return uvwasi__translate_uv_error(r);
2399 
2400   return UVWASI_ESUCCESS;
2401 }
2402 
2403 
uvwasi_poll_oneoff(uvwasi_t * uvwasi,const uvwasi_subscription_t * in,uvwasi_event_t * out,uvwasi_size_t nsubscriptions,uvwasi_size_t * nevents)2404 uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi,
2405                                   const uvwasi_subscription_t* in,
2406                                   uvwasi_event_t* out,
2407                                   uvwasi_size_t nsubscriptions,
2408                                   uvwasi_size_t* nevents) {
2409   struct uvwasi_poll_oneoff_state_t state;
2410   struct uvwasi__poll_fdevent_t* fdevent;
2411   uvwasi_userdata_t timer_userdata;
2412   uvwasi_timestamp_t min_timeout;
2413   uvwasi_timestamp_t cur_timeout;
2414   uvwasi_timestamp_t now;
2415   uvwasi_subscription_t sub;
2416   uvwasi_event_t* event;
2417   uvwasi_errno_t err;
2418   int has_timeout;
2419   uvwasi_size_t i;
2420 
2421   UVWASI_DEBUG("uvwasi_poll_oneoff(uvwasi=%p, in=%p, out=%p, "
2422                "nsubscriptions=%d, nevents=%p)\n",
2423                uvwasi,
2424                in,
2425                out,
2426                nsubscriptions,
2427                nevents);
2428 
2429   if (uvwasi == NULL || in == NULL || out == NULL ||
2430       nsubscriptions == 0 || nevents == NULL) {
2431     return UVWASI_EINVAL;
2432   }
2433 
2434   *nevents = 0;
2435   err = uvwasi__poll_oneoff_state_init(uvwasi, &state, nsubscriptions);
2436   if (err != UVWASI_ESUCCESS)
2437     return err;
2438 
2439   timer_userdata = 0;
2440   has_timeout = 0;
2441   min_timeout = 0;
2442 
2443   for (i = 0; i < nsubscriptions; i++) {
2444     sub = in[i];
2445 
2446     switch (sub.type) {
2447       case UVWASI_EVENTTYPE_CLOCK:
2448         if (sub.u.clock.flags == UVWASI_SUBSCRIPTION_CLOCK_ABSTIME) {
2449           /* Convert absolute time to relative delay. */
2450           err = uvwasi__clock_gettime_realtime(&now);
2451           if (err != UVWASI_ESUCCESS)
2452             goto exit;
2453 
2454           cur_timeout = sub.u.clock.timeout - now;
2455         } else {
2456           cur_timeout = sub.u.clock.timeout;
2457         }
2458 
2459         if (has_timeout == 0 || cur_timeout < min_timeout) {
2460           min_timeout = cur_timeout;
2461           timer_userdata = sub.userdata;
2462           has_timeout = 1;
2463         }
2464 
2465         break;
2466       case UVWASI_EVENTTYPE_FD_READ:
2467       case UVWASI_EVENTTYPE_FD_WRITE:
2468         err = uvwasi__poll_oneoff_state_add_fdevent(&state, &sub);
2469         if (err != UVWASI_ESUCCESS)
2470           goto exit;
2471 
2472         break;
2473       default:
2474         err = UVWASI_EINVAL;
2475         goto exit;
2476     }
2477   }
2478 
2479   if (has_timeout == 1) {
2480     err = uvwasi__poll_oneoff_state_set_timer(&state, min_timeout);
2481     if (err != UVWASI_ESUCCESS)
2482       goto exit;
2483   }
2484 
2485   /* Handle poll() errors, then timeouts, then happy path. */
2486   err = uvwasi__poll_oneoff_run(&state);
2487   if (err != UVWASI_ESUCCESS) {
2488     goto exit;
2489   } else if (state.result == 0) {
2490     event = &out[0];
2491     event->userdata = timer_userdata;
2492     event->error = UVWASI_ESUCCESS;
2493     event->type = UVWASI_EVENTTYPE_CLOCK;
2494     *nevents = 1;
2495   } else {
2496     for (i = 0; i < state.fdevent_cnt; i++) {
2497       fdevent = &state.fdevents[i];
2498       event = &out[*nevents];
2499 
2500       event->userdata = fdevent->userdata;
2501       event->error = fdevent->error;
2502       event->type = fdevent->type;
2503       event->u.fd_readwrite.nbytes = 0;
2504       event->u.fd_readwrite.flags = 0;
2505 
2506       if (fdevent->error != UVWASI_ESUCCESS)
2507         ;
2508       else if ((fdevent->revents & UV_DISCONNECT) != 0)
2509         event->u.fd_readwrite.flags = UVWASI_EVENT_FD_READWRITE_HANGUP;
2510       else if ((fdevent->revents & (UV_READABLE | UV_WRITABLE)) != 0)
2511         ; /* TODO(cjihrig): Set nbytes if type is UVWASI_EVENTTYPE_FD_READ. */
2512       else
2513         continue;
2514 
2515       *nevents = *nevents + 1;
2516     }
2517   }
2518 
2519   err = UVWASI_ESUCCESS;
2520 
2521 exit:
2522   uvwasi__poll_oneoff_state_cleanup(&state);
2523   return err;
2524 }
2525 
2526 
uvwasi_proc_exit(uvwasi_t * uvwasi,uvwasi_exitcode_t rval)2527 uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval) {
2528   UVWASI_DEBUG("uvwasi_proc_exit(uvwasi=%p, rval=%d)\n", uvwasi, rval);
2529   exit(rval);
2530   return UVWASI_ESUCCESS; /* This doesn't happen. */
2531 }
2532 
2533 
uvwasi_proc_raise(uvwasi_t * uvwasi,uvwasi_signal_t sig)2534 uvwasi_errno_t uvwasi_proc_raise(uvwasi_t* uvwasi, uvwasi_signal_t sig) {
2535   int r;
2536 
2537   UVWASI_DEBUG("uvwasi_proc_raise(uvwasi=%p, sig=%d)\n", uvwasi, sig);
2538 
2539   if (uvwasi == NULL)
2540     return UVWASI_EINVAL;
2541 
2542   r = uvwasi__translate_to_uv_signal(sig);
2543   if (r == -1)
2544     return UVWASI_ENOSYS;
2545 
2546   r = uv_kill(uv_os_getpid(), r);
2547   if (r != 0)
2548     return uvwasi__translate_uv_error(r);
2549 
2550   return UVWASI_ESUCCESS;
2551 }
2552 
2553 
uvwasi_random_get(uvwasi_t * uvwasi,void * buf,uvwasi_size_t buf_len)2554 uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi,
2555                                  void* buf,
2556                                  uvwasi_size_t buf_len) {
2557   int r;
2558 
2559   UVWASI_DEBUG("uvwasi_random_get(uvwasi=%p, buf=%p, buf_len=%d)\n",
2560                uvwasi,
2561                buf,
2562                buf_len);
2563 
2564   if (uvwasi == NULL || buf == NULL)
2565     return UVWASI_EINVAL;
2566 
2567   r = uv_random(NULL, NULL, buf, buf_len, 0, NULL);
2568   if (r != 0)
2569     return uvwasi__translate_uv_error(r);
2570 
2571   return UVWASI_ESUCCESS;
2572 }
2573 
2574 
uvwasi_sched_yield(uvwasi_t * uvwasi)2575 uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi) {
2576   UVWASI_DEBUG("uvwasi_sched_yield(uvwasi=%p)\n", uvwasi);
2577 
2578   if (uvwasi == NULL)
2579     return UVWASI_EINVAL;
2580 
2581 #ifndef _WIN32
2582   if (0 != sched_yield())
2583     return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
2584 #else
2585   SwitchToThread();
2586 #endif /* _WIN32 */
2587 
2588   return UVWASI_ESUCCESS;
2589 }
2590 
uvwasi_sock_recv(uvwasi_t * uvwasi,uvwasi_fd_t sock,const uvwasi_iovec_t * ri_data,uvwasi_size_t ri_data_len,uvwasi_riflags_t ri_flags,uvwasi_size_t * ro_datalen,uvwasi_roflags_t * ro_flags)2591 uvwasi_errno_t uvwasi_sock_recv(uvwasi_t* uvwasi,
2592                                 uvwasi_fd_t sock,
2593                                 const uvwasi_iovec_t* ri_data,
2594                                 uvwasi_size_t ri_data_len,
2595                                 uvwasi_riflags_t ri_flags,
2596                                 uvwasi_size_t* ro_datalen,
2597                                 uvwasi_roflags_t* ro_flags) {
2598   struct uvwasi_fd_wrap_t* wrap;
2599   uvwasi_errno_t err = 0;
2600   recv_data_t recv_data;
2601 
2602   UVWASI_DEBUG("uvwasi_sock_recv(uvwasi=%p, sock=%d, ri_data=%p, "
2603 	       "ri_data_len=%d, ri_flags=%d, ro_datalen=%p, ro_flags=%p)\n",
2604                uvwasi,
2605                sock,
2606                ri_data,
2607                ri_data_len,
2608                ri_flags,
2609                ro_datalen,
2610                ro_flags);
2611 
2612   if (uvwasi == NULL || ri_data == NULL || ro_datalen == NULL || ro_flags == NULL)
2613     return UVWASI_EINVAL;
2614 
2615   if (ri_flags != 0)
2616     return UVWASI_ENOTSUP;
2617 
2618   err = uvwasi_fd_table_get(uvwasi->fds,
2619                             sock,
2620                             &wrap,
2621                             UVWASI__RIGHTS_SOCKET_BASE,
2622                             0);
2623   if (err != UVWASI_ESUCCESS)
2624     return err;
2625 
2626   recv_data.base = ri_data->buf;
2627   recv_data.len = ri_data->buf_len;
2628   err = read_stream_sync(uvwasi, (uv_stream_t*) wrap->sock, &recv_data);
2629   uv_mutex_unlock(&wrap->mutex);
2630   if (err != 0) {
2631     return err;
2632   }
2633 
2634   if (recv_data.nread == 0) {
2635     return UVWASI_EAGAIN;
2636   } else if (recv_data.nread < 0) {
2637     return uvwasi__translate_uv_error(recv_data.nread);
2638   }
2639 
2640   *ro_datalen = recv_data.nread;
2641   return UVWASI_ESUCCESS;
2642 }
2643 
2644 
uvwasi_sock_send(uvwasi_t * uvwasi,uvwasi_fd_t sock,const uvwasi_ciovec_t * si_data,uvwasi_size_t si_data_len,uvwasi_siflags_t si_flags,uvwasi_size_t * so_datalen)2645 uvwasi_errno_t uvwasi_sock_send(uvwasi_t* uvwasi,
2646                                 uvwasi_fd_t sock,
2647                                 const uvwasi_ciovec_t* si_data,
2648                                 uvwasi_size_t si_data_len,
2649                                 uvwasi_siflags_t si_flags,
2650                                 uvwasi_size_t* so_datalen) {
2651 
2652   struct uvwasi_fd_wrap_t* wrap;
2653   uvwasi_errno_t err = 0;
2654   uv_buf_t* bufs;
2655   int r = 0;
2656 
2657   UVWASI_DEBUG("uvwasi_sock_send(uvwasi=%p, sock=%d, si_data=%p, "
2658 	       "si_data_len=%d, si_flags=%d, so_datalen=%p)\n",
2659                uvwasi,
2660                sock,
2661                si_data,
2662                si_data_len,
2663                si_flags,
2664                so_datalen);
2665 
2666   if (uvwasi == NULL || si_data == NULL || so_datalen == NULL ||
2667       si_flags != 0)
2668     return UVWASI_EINVAL;
2669 
2670   err = uvwasi_fd_table_get(uvwasi->fds,
2671                             sock,
2672                             &wrap,
2673                             UVWASI__RIGHTS_SOCKET_BASE,
2674                             0);
2675   if (err != UVWASI_ESUCCESS)
2676     return err;
2677 
2678   err = uvwasi__setup_ciovs(uvwasi, &bufs, si_data, si_data_len);
2679   if (err != UVWASI_ESUCCESS) {
2680     uv_mutex_unlock(&wrap->mutex);
2681     return err;
2682   }
2683 
2684   r = uv_try_write((uv_stream_t*) wrap->sock, bufs, si_data_len);
2685   uvwasi__free(uvwasi, bufs);
2686   uv_mutex_unlock(&wrap->mutex);
2687   if (r < 0)
2688     return uvwasi__translate_uv_error(r);
2689 
2690   *so_datalen = (uvwasi_size_t) r;
2691   return UVWASI_ESUCCESS;
2692 }
2693 
uvwasi_sock_shutdown(uvwasi_t * uvwasi,uvwasi_fd_t sock,uvwasi_sdflags_t how)2694 uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi,
2695                                     uvwasi_fd_t sock,
2696                                     uvwasi_sdflags_t how) {
2697   struct uvwasi_fd_wrap_t* wrap;
2698   uvwasi_errno_t err = 0;
2699   shutdown_data_t shutdown_data;
2700 
2701   if (how & ~UVWASI_SHUT_WR)
2702     return UVWASI_ENOTSUP;
2703 
2704   UVWASI_DEBUG("uvwasi_sock_shutdown(uvwasi=%p, sock=%d, how=%d)\n",
2705                uvwasi,
2706                sock,
2707                how);
2708 
2709   if (uvwasi == NULL)
2710     return UVWASI_EINVAL;
2711 
2712   err = uvwasi_fd_table_get(uvwasi->fds,
2713                             sock,
2714                             &wrap,
2715                             UVWASI__RIGHTS_SOCKET_BASE,
2716                             0);
2717   if (err != UVWASI_ESUCCESS)
2718     return err;
2719 
2720   if (how & UVWASI_SHUT_WR) {
2721     err = shutdown_stream_sync(uvwasi, (uv_stream_t*) wrap->sock, &shutdown_data);
2722     if (err != UVWASI_ESUCCESS) {
2723       uv_mutex_unlock(&wrap->mutex);
2724       return err;
2725     }
2726   }
2727 
2728   uv_mutex_unlock(&wrap->mutex);
2729 
2730   if (shutdown_data.status != 0)
2731     return uvwasi__translate_uv_error(shutdown_data.status);
2732 
2733   return UVWASI_ESUCCESS;
2734 }
2735 
uvwasi_sock_accept(uvwasi_t * uvwasi,uvwasi_fd_t sock,uvwasi_fdflags_t flags,uvwasi_fd_t * connect_sock)2736 uvwasi_errno_t uvwasi_sock_accept(uvwasi_t* uvwasi,
2737                                   uvwasi_fd_t sock,
2738                                   uvwasi_fdflags_t flags,
2739                                   uvwasi_fd_t* connect_sock) {
2740   struct uvwasi_fd_wrap_t* wrap;
2741   struct uvwasi_fd_wrap_t* connected_wrap;
2742   uvwasi_errno_t err = 0;
2743   uv_loop_t* sock_loop = NULL;
2744   int r = 0;
2745 
2746   UVWASI_DEBUG("uvwasi_sock_accept(uvwasi=%p, sock=%d, flags=%d, "
2747                "connect_sock=%p)\n",
2748                uvwasi,
2749                sock,
2750                flags,
2751                connect_sock);
2752 
2753   if (uvwasi == NULL || connect_sock == NULL)
2754     return UVWASI_EINVAL;
2755 
2756   if (flags & ~UVWASI_FDFLAG_NONBLOCK)
2757     return UVWASI_ENOTSUP;
2758 
2759   err = uvwasi_fd_table_get(uvwasi->fds,
2760                             sock,
2761                             &wrap,
2762                             UVWASI__RIGHTS_SOCKET_BASE,
2763                             0);
2764   if (err != UVWASI_ESUCCESS)
2765     return err;
2766 
2767   sock_loop = uv_handle_get_loop((uv_handle_t*) wrap->sock);
2768   uv_tcp_t* uv_connect_sock = (uv_tcp_t*) uvwasi__malloc(uvwasi, sizeof(uv_tcp_t));
2769   uv_tcp_init(sock_loop, uv_connect_sock);
2770 
2771   r = uv_accept((uv_stream_t*) wrap->sock, (uv_stream_t*) uv_connect_sock);
2772   if (r != 0) {
2773     if (r == UV_EAGAIN) {
2774       // if not blocking then just return as we have to wait for a connection
2775       if (flags & UVWASI_FDFLAG_NONBLOCK) {
2776         err = free_handle_sync(uvwasi, (uv_handle_t*) uv_connect_sock);
2777         uv_mutex_unlock(&wrap->mutex);
2778         if (err != UVWASI_ESUCCESS) {
2779           return err;
2780 	}
2781         return UVWASI_EAGAIN;
2782       }
2783     } else {
2784       err = uvwasi__translate_uv_error(r);
2785       goto close_sock_and_error_exit;
2786     }
2787 
2788     // request was blocking and we have no connection yet. run
2789     // the loop until a connection comes in
2790     while (1) {
2791       err = 0;
2792       if (uv_run(sock_loop, UV_RUN_ONCE) == 0) {
2793         err = UVWASI_ECONNABORTED;
2794         goto close_sock_and_error_exit;
2795       }
2796 
2797       int r = uv_accept((uv_stream_t*) wrap->sock, (uv_stream_t*) uv_connect_sock);
2798       if (r == UV_EAGAIN) {
2799 	// still no connection or error so run the loop again
2800         continue;
2801       }
2802 
2803       if (r != 0) {
2804 	// An error occurred accepting the connection. Break out of the loop and
2805 	// report an error.
2806         err = uvwasi__translate_uv_error(r);
2807         goto close_sock_and_error_exit;
2808       }
2809 
2810       // if we get here a new connection was successfully accepted
2811       break;
2812     }
2813   }
2814 
2815   err = uvwasi_fd_table_insert(uvwasi,
2816                                uvwasi->fds,
2817                                -1,
2818                                uv_connect_sock,
2819                                NULL,
2820                                NULL,
2821                                UVWASI_FILETYPE_SOCKET_STREAM,
2822                                UVWASI__RIGHTS_SOCKET_BASE,
2823                                UVWASI__RIGHTS_SOCKET_INHERITING,
2824                                1,
2825                                &connected_wrap);
2826 
2827   if (err != UVWASI_ESUCCESS)
2828     goto close_sock_and_error_exit;
2829 
2830   *connect_sock = connected_wrap->id;
2831   uv_mutex_unlock(&wrap->mutex);
2832   uv_mutex_unlock(&connected_wrap->mutex);
2833   return UVWASI_ESUCCESS;
2834 
2835 close_sock_and_error_exit:
2836   uvwasi__free(uvwasi, uv_connect_sock);
2837   uv_mutex_unlock(&wrap->mutex);
2838   return err;
2839 }
2840 
2841 
uvwasi_embedder_err_code_to_string(uvwasi_errno_t code)2842 const char* uvwasi_embedder_err_code_to_string(uvwasi_errno_t code) {
2843   switch (code) {
2844 #define V(errcode) case errcode: return #errcode;
2845     V(UVWASI_E2BIG)
2846     V(UVWASI_EACCES)
2847     V(UVWASI_EADDRINUSE)
2848     V(UVWASI_EADDRNOTAVAIL)
2849     V(UVWASI_EAFNOSUPPORT)
2850     V(UVWASI_EAGAIN)
2851     V(UVWASI_EALREADY)
2852     V(UVWASI_EBADF)
2853     V(UVWASI_EBADMSG)
2854     V(UVWASI_EBUSY)
2855     V(UVWASI_ECANCELED)
2856     V(UVWASI_ECHILD)
2857     V(UVWASI_ECONNABORTED)
2858     V(UVWASI_ECONNREFUSED)
2859     V(UVWASI_ECONNRESET)
2860     V(UVWASI_EDEADLK)
2861     V(UVWASI_EDESTADDRREQ)
2862     V(UVWASI_EDOM)
2863     V(UVWASI_EDQUOT)
2864     V(UVWASI_EEXIST)
2865     V(UVWASI_EFAULT)
2866     V(UVWASI_EFBIG)
2867     V(UVWASI_EHOSTUNREACH)
2868     V(UVWASI_EIDRM)
2869     V(UVWASI_EILSEQ)
2870     V(UVWASI_EINPROGRESS)
2871     V(UVWASI_EINTR)
2872     V(UVWASI_EINVAL)
2873     V(UVWASI_EIO)
2874     V(UVWASI_EISCONN)
2875     V(UVWASI_EISDIR)
2876     V(UVWASI_ELOOP)
2877     V(UVWASI_EMFILE)
2878     V(UVWASI_EMLINK)
2879     V(UVWASI_EMSGSIZE)
2880     V(UVWASI_EMULTIHOP)
2881     V(UVWASI_ENAMETOOLONG)
2882     V(UVWASI_ENETDOWN)
2883     V(UVWASI_ENETRESET)
2884     V(UVWASI_ENETUNREACH)
2885     V(UVWASI_ENFILE)
2886     V(UVWASI_ENOBUFS)
2887     V(UVWASI_ENODEV)
2888     V(UVWASI_ENOENT)
2889     V(UVWASI_ENOEXEC)
2890     V(UVWASI_ENOLCK)
2891     V(UVWASI_ENOLINK)
2892     V(UVWASI_ENOMEM)
2893     V(UVWASI_ENOMSG)
2894     V(UVWASI_ENOPROTOOPT)
2895     V(UVWASI_ENOSPC)
2896     V(UVWASI_ENOSYS)
2897     V(UVWASI_ENOTCONN)
2898     V(UVWASI_ENOTDIR)
2899     V(UVWASI_ENOTEMPTY)
2900     V(UVWASI_ENOTRECOVERABLE)
2901     V(UVWASI_ENOTSOCK)
2902     V(UVWASI_ENOTSUP)
2903     V(UVWASI_ENOTTY)
2904     V(UVWASI_ENXIO)
2905     V(UVWASI_EOVERFLOW)
2906     V(UVWASI_EOWNERDEAD)
2907     V(UVWASI_EPERM)
2908     V(UVWASI_EPIPE)
2909     V(UVWASI_EPROTO)
2910     V(UVWASI_EPROTONOSUPPORT)
2911     V(UVWASI_EPROTOTYPE)
2912     V(UVWASI_ERANGE)
2913     V(UVWASI_EROFS)
2914     V(UVWASI_ESPIPE)
2915     V(UVWASI_ESRCH)
2916     V(UVWASI_ESTALE)
2917     V(UVWASI_ETIMEDOUT)
2918     V(UVWASI_ETXTBSY)
2919     V(UVWASI_EXDEV)
2920     V(UVWASI_ENOTCAPABLE)
2921     V(UVWASI_ESUCCESS)
2922 #undef V
2923     default:
2924       return "UVWASI_UNKNOWN_ERROR";
2925   }
2926 }
2927