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