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