1 //
2 // m3_api_wasi.c
3 //
4 // Created by Volodymyr Shymanskyy on 11/20/19.
5 // Copyright © 2019 Volodymyr Shymanskyy. All rights reserved.
6 //
7
8 #define _POSIX_C_SOURCE 200809L
9
10 #include "m3_api_wasi.h"
11
12 #include "m3_env.h"
13 #include "m3_exception.h"
14
15 #if defined(d_m3HasWASI)
16
17 // Fixup wasi_core.h
18 #if defined (M3_COMPILER_MSVC)
19 # define _Static_assert(...)
20 # define __attribute__(...)
21 # define _Noreturn
22 #endif
23
24 #include "extra/wasi_core.h"
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32
33 #if defined(APE)
34 // Actually Portable Executable
35 // All functions are already included in cosmopolitan.h
36 #elif defined(__wasi__) || defined(__APPLE__) || defined(__ANDROID_API__) || defined(__OpenBSD__) || defined(__linux__) || defined(__EMSCRIPTEN__)
37 # include <unistd.h>
38 # include <sys/uio.h>
39 # if defined(__APPLE__)
40 # include <TargetConditionals.h>
41 # if TARGET_OS_OSX // TARGET_OS_MAC includes iOS
42 # include <sys/random.h>
43 # else // iOS / Simulator
44 # include <Security/Security.h>
45 # endif
46 # else
47 # include <sys/random.h>
48 # endif
49 # define HAS_IOVEC
50 #elif defined(_WIN32)
51 # include <Windows.h>
52 # include <io.h>
53 // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
54 # define SystemFunction036 NTAPI SystemFunction036
55 # include <NTSecAPI.h>
56 # undef SystemFunction036
57 # define ssize_t SSIZE_T
58
59 # define open _open
60 # define read _read
61 # define write _write
62 # define close _close
63 #endif
64
65 static m3_wasi_context_t* wasi_context;
66
67 typedef struct wasi_iovec_t
68 {
69 __wasi_size_t buf;
70 __wasi_size_t buf_len;
71 } wasi_iovec_t;
72
73 #define PREOPEN_CNT 5
74
75 typedef struct Preopen {
76 int fd;
77 const char* path;
78 const char* real_path;
79 } Preopen;
80
81 Preopen preopen[PREOPEN_CNT] = {
82 { 0, "<stdin>" , "" },
83 { 1, "<stdout>", "" },
84 { 2, "<stderr>", "" },
85 { -1, "/" , "." },
86 { -1, "./" , "." },
87 };
88
89 #if defined(APE)
90 # define APE_SWITCH_BEG
91 # define APE_SWITCH_END {}
92 # define APE_CASE_RET(e1,e2) if (errnum == e1) return e2; else
93 #else
94 # define APE_SWITCH_BEG switch (errnum) {
95 # define APE_SWITCH_END }
96 # define APE_CASE_RET(e1,e2) case e1: return e2; break;
97 #endif
98
99 static
errno_to_wasi(int errnum)100 __wasi_errno_t errno_to_wasi(int errnum) {
101 APE_SWITCH_BEG
102 APE_CASE_RET( EPERM , __WASI_ERRNO_PERM )
103 APE_CASE_RET( ENOENT , __WASI_ERRNO_NOENT )
104 APE_CASE_RET( ESRCH , __WASI_ERRNO_SRCH )
105 APE_CASE_RET( EINTR , __WASI_ERRNO_INTR )
106 APE_CASE_RET( EIO , __WASI_ERRNO_IO )
107 APE_CASE_RET( ENXIO , __WASI_ERRNO_NXIO )
108 APE_CASE_RET( E2BIG , __WASI_ERRNO_2BIG )
109 APE_CASE_RET( ENOEXEC , __WASI_ERRNO_NOEXEC )
110 APE_CASE_RET( EBADF , __WASI_ERRNO_BADF )
111 APE_CASE_RET( ECHILD , __WASI_ERRNO_CHILD )
112 APE_CASE_RET( EAGAIN , __WASI_ERRNO_AGAIN )
113 APE_CASE_RET( ENOMEM , __WASI_ERRNO_NOMEM )
114 APE_CASE_RET( EACCES , __WASI_ERRNO_ACCES )
115 APE_CASE_RET( EFAULT , __WASI_ERRNO_FAULT )
116 APE_CASE_RET( EBUSY , __WASI_ERRNO_BUSY )
117 APE_CASE_RET( EEXIST , __WASI_ERRNO_EXIST )
118 APE_CASE_RET( EXDEV , __WASI_ERRNO_XDEV )
119 APE_CASE_RET( ENODEV , __WASI_ERRNO_NODEV )
120 APE_CASE_RET( ENOTDIR , __WASI_ERRNO_NOTDIR )
121 APE_CASE_RET( EISDIR , __WASI_ERRNO_ISDIR )
122 APE_CASE_RET( EINVAL , __WASI_ERRNO_INVAL )
123 APE_CASE_RET( ENFILE , __WASI_ERRNO_NFILE )
124 APE_CASE_RET( EMFILE , __WASI_ERRNO_MFILE )
125 APE_CASE_RET( ENOTTY , __WASI_ERRNO_NOTTY )
126 APE_CASE_RET( ETXTBSY , __WASI_ERRNO_TXTBSY )
127 APE_CASE_RET( EFBIG , __WASI_ERRNO_FBIG )
128 APE_CASE_RET( ENOSPC , __WASI_ERRNO_NOSPC )
129 APE_CASE_RET( ESPIPE , __WASI_ERRNO_SPIPE )
130 APE_CASE_RET( EROFS , __WASI_ERRNO_ROFS )
131 APE_CASE_RET( EMLINK , __WASI_ERRNO_MLINK )
132 APE_CASE_RET( EPIPE , __WASI_ERRNO_PIPE )
133 APE_CASE_RET( EDOM , __WASI_ERRNO_DOM )
134 APE_CASE_RET( ERANGE , __WASI_ERRNO_RANGE )
135 APE_SWITCH_END
136 return __WASI_ERRNO_INVAL;
137 }
138
139 #if defined(_WIN32)
140
141 #if !defined(__MINGW32__)
142
143 static inline
clock_gettime(int clk_id,struct timespec * spec)144 int clock_gettime(int clk_id, struct timespec *spec)
145 {
146 __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
147 wintime -= 116444736000000000i64; //1jan1601 to 1jan1970
148 spec->tv_sec = wintime / 10000000i64; //seconds
149 spec->tv_nsec = wintime % 10000000i64 *100; //nano-seconds
150 return 0;
151 }
152
153 static inline
clock_getres(int clk_id,struct timespec * spec)154 int clock_getres(int clk_id, struct timespec *spec) {
155 return -1; // Defaults to 1000000
156 }
157
158 #endif
159
160 static inline
convert_clockid(__wasi_clockid_t in)161 int convert_clockid(__wasi_clockid_t in) {
162 return 0;
163 }
164
165 #else // _WIN32
166
167 static inline
convert_clockid(__wasi_clockid_t in)168 int convert_clockid(__wasi_clockid_t in) {
169 switch (in) {
170 case __WASI_CLOCKID_MONOTONIC: return CLOCK_MONOTONIC;
171 case __WASI_CLOCKID_PROCESS_CPUTIME_ID: return CLOCK_PROCESS_CPUTIME_ID;
172 case __WASI_CLOCKID_REALTIME: return CLOCK_REALTIME;
173 case __WASI_CLOCKID_THREAD_CPUTIME_ID: return CLOCK_THREAD_CPUTIME_ID;
174 default: return -1;
175 }
176 }
177
178 #endif // _WIN32
179
180 static inline
convert_timespec(const struct timespec * ts)181 __wasi_timestamp_t convert_timespec(const struct timespec *ts) {
182 if (ts->tv_sec < 0)
183 return 0;
184 if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000)
185 return UINT64_MAX;
186 return (__wasi_timestamp_t)ts->tv_sec * 1000000000 + ts->tv_nsec;
187 }
188
189 #if defined(HAS_IOVEC)
190
191 static inline
copy_iov_to_host(void * _mem,struct iovec * host_iov,wasi_iovec_t * wasi_iov,int32_t iovs_len)192 void copy_iov_to_host(void* _mem, struct iovec* host_iov, wasi_iovec_t* wasi_iov, int32_t iovs_len)
193 {
194 // Convert wasi memory offsets to host addresses
195 for (int i = 0; i < iovs_len; i++) {
196 host_iov[i].iov_base = m3ApiOffsetToPtr(m3ApiReadMem32(&wasi_iov[i].buf));
197 host_iov[i].iov_len = m3ApiReadMem32(&wasi_iov[i].buf_len);
198 }
199 }
200
201 #endif
202
203 /*
204 * WASI API implementation
205 */
206
m3ApiRawFunction(m3_wasi_generic_args_get)207 m3ApiRawFunction(m3_wasi_generic_args_get)
208 {
209 m3ApiReturnType (uint32_t)
210 m3ApiGetArgMem (uint32_t * , argv)
211 m3ApiGetArgMem (char * , argv_buf)
212
213 m3_wasi_context_t* context = (m3_wasi_context_t*)(_ctx->userdata);
214
215 if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); }
216
217 m3ApiCheckMem(argv, context->argc * sizeof(uint32_t));
218
219 for (u32 i = 0; i < context->argc; ++i)
220 {
221 m3ApiWriteMem32(&argv[i], m3ApiPtrToOffset(argv_buf));
222
223 size_t len = strlen (context->argv[i]);
224
225 m3ApiCheckMem(argv_buf, len);
226 memcpy (argv_buf, context->argv[i], len);
227 argv_buf += len;
228 * argv_buf++ = 0;
229 }
230
231 m3ApiReturn(__WASI_ERRNO_SUCCESS);
232 }
233
m3ApiRawFunction(m3_wasi_generic_args_sizes_get)234 m3ApiRawFunction(m3_wasi_generic_args_sizes_get)
235 {
236 m3ApiReturnType (uint32_t)
237 m3ApiGetArgMem (__wasi_size_t * , argc)
238 m3ApiGetArgMem (__wasi_size_t * , argv_buf_size)
239
240 m3ApiCheckMem(argc, sizeof(__wasi_size_t));
241 m3ApiCheckMem(argv_buf_size, sizeof(__wasi_size_t));
242
243 m3_wasi_context_t* context = (m3_wasi_context_t*)(_ctx->userdata);
244
245 if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); }
246
247 __wasi_size_t buf_len = 0;
248 for (u32 i = 0; i < context->argc; ++i)
249 {
250 buf_len += strlen (context->argv[i]) + 1;
251 }
252
253 m3ApiWriteMem32(argc, context->argc);
254 m3ApiWriteMem32(argv_buf_size, buf_len);
255
256 m3ApiReturn(__WASI_ERRNO_SUCCESS);
257 }
258
m3ApiRawFunction(m3_wasi_generic_environ_get)259 m3ApiRawFunction(m3_wasi_generic_environ_get)
260 {
261 m3ApiReturnType (uint32_t)
262 m3ApiGetArgMem (uint32_t * , env)
263 m3ApiGetArgMem (char * , env_buf)
264
265 // TODO
266 m3ApiReturn(__WASI_ERRNO_SUCCESS);
267 }
268
m3ApiRawFunction(m3_wasi_generic_environ_sizes_get)269 m3ApiRawFunction(m3_wasi_generic_environ_sizes_get)
270 {
271 m3ApiReturnType (uint32_t)
272 m3ApiGetArgMem (__wasi_size_t * , env_count)
273 m3ApiGetArgMem (__wasi_size_t * , env_buf_size)
274
275 m3ApiCheckMem(env_count, sizeof(__wasi_size_t));
276 m3ApiCheckMem(env_buf_size, sizeof(__wasi_size_t));
277
278 // TODO
279 m3ApiWriteMem32(env_count, 0);
280 m3ApiWriteMem32(env_buf_size, 0);
281
282 m3ApiReturn(__WASI_ERRNO_SUCCESS);
283 }
284
m3ApiRawFunction(m3_wasi_generic_fd_prestat_dir_name)285 m3ApiRawFunction(m3_wasi_generic_fd_prestat_dir_name)
286 {
287 m3ApiReturnType (uint32_t)
288 m3ApiGetArg (__wasi_fd_t , fd)
289 m3ApiGetArgMem (char * , path)
290 m3ApiGetArg (__wasi_size_t , path_len)
291
292 m3ApiCheckMem(path, path_len);
293
294 if (fd < 3 || fd >= PREOPEN_CNT) { m3ApiReturn(__WASI_ERRNO_BADF); }
295 size_t slen = strlen(preopen[fd].path) + 1;
296 memcpy(path, preopen[fd].path, M3_MIN(slen, path_len));
297 m3ApiReturn(__WASI_ERRNO_SUCCESS);
298 }
299
m3ApiRawFunction(m3_wasi_generic_fd_prestat_get)300 m3ApiRawFunction(m3_wasi_generic_fd_prestat_get)
301 {
302 m3ApiReturnType (uint32_t)
303 m3ApiGetArg (__wasi_fd_t , fd)
304 m3ApiGetArgMem (uint8_t * , buf)
305
306 m3ApiCheckMem(buf, 8);
307
308 if (fd < 3 || fd >= PREOPEN_CNT) { m3ApiReturn(__WASI_ERRNO_BADF); }
309
310 m3ApiWriteMem32(buf+0, __WASI_PREOPENTYPE_DIR);
311 m3ApiWriteMem32(buf+4, strlen(preopen[fd].path) + 1);
312 m3ApiReturn(__WASI_ERRNO_SUCCESS);
313 }
314
m3ApiRawFunction(m3_wasi_generic_fd_fdstat_get)315 m3ApiRawFunction(m3_wasi_generic_fd_fdstat_get)
316 {
317 m3ApiReturnType (uint32_t)
318 m3ApiGetArg (__wasi_fd_t , fd)
319 m3ApiGetArgMem (__wasi_fdstat_t * , fdstat)
320
321 m3ApiCheckMem(fdstat, sizeof(__wasi_fdstat_t));
322
323 #ifdef _WIN32
324
325 // TODO: This needs a proper implementation
326 if (fd < PREOPEN_CNT) {
327 fdstat->fs_filetype= __WASI_FILETYPE_DIRECTORY;
328 } else {
329 fdstat->fs_filetype= __WASI_FILETYPE_REGULAR_FILE;
330 }
331
332 fdstat->fs_flags = 0;
333 fdstat->fs_rights_base = (uint64_t)-1; // all rights
334 fdstat->fs_rights_inheriting = (uint64_t)-1; // all rights
335 m3ApiReturn(__WASI_ERRNO_SUCCESS);
336 #else
337 struct stat fd_stat;
338
339 #if !defined(APE) // TODO: not implemented in Cosmopolitan
340 int fl = fcntl(fd, F_GETFL);
341 if (fl < 0) { m3ApiReturn(errno_to_wasi(errno)); }
342 #endif
343
344 fstat(fd, &fd_stat);
345 int mode = fd_stat.st_mode;
346 fdstat->fs_filetype = (S_ISBLK(mode) ? __WASI_FILETYPE_BLOCK_DEVICE : 0) |
347 (S_ISCHR(mode) ? __WASI_FILETYPE_CHARACTER_DEVICE : 0) |
348 (S_ISDIR(mode) ? __WASI_FILETYPE_DIRECTORY : 0) |
349 (S_ISREG(mode) ? __WASI_FILETYPE_REGULAR_FILE : 0) |
350 //(S_ISSOCK(mode) ? __WASI_FILETYPE_SOCKET_STREAM : 0) |
351 (S_ISLNK(mode) ? __WASI_FILETYPE_SYMBOLIC_LINK : 0);
352 #if !defined(APE)
353 m3ApiWriteMem16(&fdstat->fs_flags,
354 ((fl & O_APPEND) ? __WASI_FDFLAGS_APPEND : 0) |
355 ((fl & O_DSYNC) ? __WASI_FDFLAGS_DSYNC : 0) |
356 ((fl & O_NONBLOCK) ? __WASI_FDFLAGS_NONBLOCK : 0) |
357 //((fl & O_RSYNC) ? __WASI_FDFLAGS_RSYNC : 0) |
358 ((fl & O_SYNC) ? __WASI_FDFLAGS_SYNC : 0));
359 #endif // APE
360
361 fdstat->fs_rights_base = (uint64_t)-1; // all rights
362
363 // Make descriptors 0,1,2 look like a TTY
364 if (fd <= 2) {
365 fdstat->fs_rights_base &= ~(__WASI_RIGHTS_FD_SEEK | __WASI_RIGHTS_FD_TELL);
366 }
367
368 fdstat->fs_rights_inheriting = (uint64_t)-1; // all rights
369 m3ApiReturn(__WASI_ERRNO_SUCCESS);
370 #endif
371 }
372
m3ApiRawFunction(m3_wasi_generic_fd_fdstat_set_flags)373 m3ApiRawFunction(m3_wasi_generic_fd_fdstat_set_flags)
374 {
375 m3ApiReturnType (uint32_t)
376 m3ApiGetArg (__wasi_fd_t , fd)
377 m3ApiGetArg (__wasi_fdflags_t , flags)
378
379 // TODO
380
381 m3ApiReturn(__WASI_ERRNO_SUCCESS);
382 }
383
m3ApiRawFunction(m3_wasi_unstable_fd_seek)384 m3ApiRawFunction(m3_wasi_unstable_fd_seek)
385 {
386 m3ApiReturnType (uint32_t)
387 m3ApiGetArg (__wasi_fd_t , fd)
388 m3ApiGetArg (__wasi_filedelta_t , offset)
389 m3ApiGetArg (uint32_t , wasi_whence)
390 m3ApiGetArgMem (__wasi_filesize_t * , result)
391
392 m3ApiCheckMem(result, sizeof(__wasi_filesize_t));
393
394 int whence;
395
396 switch (wasi_whence) {
397 case 0: whence = SEEK_CUR; break;
398 case 1: whence = SEEK_END; break;
399 case 2: whence = SEEK_SET; break;
400 default: m3ApiReturn(__WASI_ERRNO_INVAL);
401 }
402
403 int64_t ret;
404 #if defined(M3_COMPILER_MSVC) || defined(__MINGW32__)
405 ret = _lseeki64(fd, offset, whence);
406 #else
407 ret = lseek(fd, offset, whence);
408 #endif
409 if (ret < 0) { m3ApiReturn(errno_to_wasi(errno)); }
410 m3ApiWriteMem64(result, ret);
411 m3ApiReturn(__WASI_ERRNO_SUCCESS);
412 }
413
m3ApiRawFunction(m3_wasi_snapshot_preview1_fd_seek)414 m3ApiRawFunction(m3_wasi_snapshot_preview1_fd_seek)
415 {
416 m3ApiReturnType (uint32_t)
417 m3ApiGetArg (__wasi_fd_t , fd)
418 m3ApiGetArg (__wasi_filedelta_t , offset)
419 m3ApiGetArg (uint32_t , wasi_whence)
420 m3ApiGetArgMem (__wasi_filesize_t * , result)
421
422 m3ApiCheckMem(result, sizeof(__wasi_filesize_t));
423
424 int whence;
425
426 switch (wasi_whence) {
427 case 0: whence = SEEK_SET; break;
428 case 1: whence = SEEK_CUR; break;
429 case 2: whence = SEEK_END; break;
430 default: m3ApiReturn(__WASI_ERRNO_INVAL);
431 }
432
433 int64_t ret;
434 #if defined(M3_COMPILER_MSVC) || defined(__MINGW32__)
435 ret = _lseeki64(fd, offset, whence);
436 #else
437 ret = lseek(fd, offset, whence);
438 #endif
439 if (ret < 0) { m3ApiReturn(errno_to_wasi(errno)); }
440 m3ApiWriteMem64(result, ret);
441 m3ApiReturn(__WASI_ERRNO_SUCCESS);
442 }
443
444
m3ApiRawFunction(m3_wasi_generic_path_open)445 m3ApiRawFunction(m3_wasi_generic_path_open)
446 {
447 m3ApiReturnType (uint32_t)
448 m3ApiGetArg (__wasi_fd_t , dirfd)
449 m3ApiGetArg (__wasi_lookupflags_t , dirflags)
450 m3ApiGetArgMem (const char * , path)
451 m3ApiGetArg (__wasi_size_t , path_len)
452 m3ApiGetArg (__wasi_oflags_t , oflags)
453 m3ApiGetArg (__wasi_rights_t , fs_rights_base)
454 m3ApiGetArg (__wasi_rights_t , fs_rights_inheriting)
455 m3ApiGetArg (__wasi_fdflags_t , fs_flags)
456 m3ApiGetArgMem (__wasi_fd_t * , fd)
457
458 m3ApiCheckMem(path, path_len);
459 m3ApiCheckMem(fd, sizeof(__wasi_fd_t));
460
461 if (path_len >= 512)
462 m3ApiReturn(__WASI_ERRNO_INVAL);
463
464 // copy path so we can ensure it is NULL terminated
465 #if defined(M3_COMPILER_MSVC)
466 char host_path[512];
467 #else
468 char host_path[path_len+1];
469 #endif
470 memcpy (host_path, path, path_len);
471 host_path[path_len] = '\0'; // NULL terminator
472
473 #if defined(APE)
474 // TODO: This all needs a proper implementation
475
476 int flags = ((oflags & __WASI_OFLAGS_CREAT) ? O_CREAT : 0) |
477 ((oflags & __WASI_OFLAGS_EXCL) ? O_EXCL : 0) |
478 ((oflags & __WASI_OFLAGS_TRUNC) ? O_TRUNC : 0) |
479 ((fs_flags & __WASI_FDFLAGS_APPEND) ? O_APPEND : 0);
480
481 if ((fs_rights_base & __WASI_RIGHTS_FD_READ) &&
482 (fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
483 flags |= O_RDWR;
484 } else if ((fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
485 flags |= O_WRONLY;
486 } else if ((fs_rights_base & __WASI_RIGHTS_FD_READ)) {
487 flags |= O_RDONLY; // no-op because O_RDONLY is 0
488 }
489 int mode = 0644;
490
491 int host_fd = open (host_path, flags, mode);
492
493 if (host_fd < 0)
494 {
495 m3ApiReturn(errno_to_wasi (errno));
496 }
497 else
498 {
499 m3ApiWriteMem32(fd, host_fd);
500 m3ApiReturn(__WASI_ERRNO_SUCCESS);
501 }
502 #elif defined(_WIN32)
503 // TODO: This all needs a proper implementation
504
505 int flags = ((oflags & __WASI_OFLAGS_CREAT) ? _O_CREAT : 0) |
506 ((oflags & __WASI_OFLAGS_EXCL) ? _O_EXCL : 0) |
507 ((oflags & __WASI_OFLAGS_TRUNC) ? _O_TRUNC : 0) |
508 ((fs_flags & __WASI_FDFLAGS_APPEND) ? _O_APPEND : 0) |
509 _O_BINARY;
510
511 if ((fs_rights_base & __WASI_RIGHTS_FD_READ) &&
512 (fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
513 flags |= _O_RDWR;
514 } else if ((fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
515 flags |= _O_WRONLY;
516 } else if ((fs_rights_base & __WASI_RIGHTS_FD_READ)) {
517 flags |= _O_RDONLY; // no-op because O_RDONLY is 0
518 }
519 int mode = 0644;
520
521 int host_fd = open (host_path, flags, mode);
522
523 if (host_fd < 0)
524 {
525 m3ApiReturn(errno_to_wasi (errno));
526 }
527 else
528 {
529 m3ApiWriteMem32(fd, host_fd);
530 m3ApiReturn(__WASI_ERRNO_SUCCESS);
531 }
532 #else
533 // translate o_flags and fs_flags into flags and mode
534 int flags = ((oflags & __WASI_OFLAGS_CREAT) ? O_CREAT : 0) |
535 //((oflags & __WASI_OFLAGS_DIRECTORY) ? O_DIRECTORY : 0) |
536 ((oflags & __WASI_OFLAGS_EXCL) ? O_EXCL : 0) |
537 ((oflags & __WASI_OFLAGS_TRUNC) ? O_TRUNC : 0) |
538 ((fs_flags & __WASI_FDFLAGS_APPEND) ? O_APPEND : 0) |
539 ((fs_flags & __WASI_FDFLAGS_DSYNC) ? O_DSYNC : 0) |
540 ((fs_flags & __WASI_FDFLAGS_NONBLOCK) ? O_NONBLOCK : 0) |
541 //((fs_flags & __WASI_FDFLAGS_RSYNC) ? O_RSYNC : 0) |
542 ((fs_flags & __WASI_FDFLAGS_SYNC) ? O_SYNC : 0);
543 if ((fs_rights_base & __WASI_RIGHTS_FD_READ) &&
544 (fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
545 flags |= O_RDWR;
546 } else if ((fs_rights_base & __WASI_RIGHTS_FD_WRITE)) {
547 flags |= O_WRONLY;
548 } else if ((fs_rights_base & __WASI_RIGHTS_FD_READ)) {
549 flags |= O_RDONLY; // no-op because O_RDONLY is 0
550 }
551 int mode = 0644;
552 int host_fd = openat (preopen[dirfd].fd, host_path, flags, mode);
553
554 if (host_fd < 0)
555 {
556 m3ApiReturn(errno_to_wasi (errno));
557 }
558 else
559 {
560 m3ApiWriteMem32(fd, host_fd);
561 m3ApiReturn(__WASI_ERRNO_SUCCESS);
562 }
563 #endif
564 }
565
m3ApiRawFunction(m3_wasi_generic_fd_read)566 m3ApiRawFunction(m3_wasi_generic_fd_read)
567 {
568 m3ApiReturnType (uint32_t)
569 m3ApiGetArg (__wasi_fd_t , fd)
570 m3ApiGetArgMem (wasi_iovec_t * , wasi_iovs)
571 m3ApiGetArg (__wasi_size_t , iovs_len)
572 m3ApiGetArgMem (__wasi_size_t * , nread)
573
574 m3ApiCheckMem(wasi_iovs, iovs_len * sizeof(wasi_iovec_t));
575 m3ApiCheckMem(nread, sizeof(__wasi_size_t));
576
577 #if defined(HAS_IOVEC)
578 struct iovec iovs[iovs_len];
579 copy_iov_to_host(_mem, iovs, wasi_iovs, iovs_len);
580
581 ssize_t ret = readv(fd, iovs, iovs_len);
582 if (ret < 0) { m3ApiReturn(errno_to_wasi(errno)); }
583 m3ApiWriteMem32(nread, ret);
584 m3ApiReturn(__WASI_ERRNO_SUCCESS);
585 #else
586 ssize_t res = 0;
587 for (__wasi_size_t i = 0; i < iovs_len; i++) {
588 void* addr = m3ApiOffsetToPtr(m3ApiReadMem32(&wasi_iovs[i].buf));
589 size_t len = m3ApiReadMem32(&wasi_iovs[i].buf_len);
590 if (len == 0) continue;
591
592 int ret = read (fd, addr, len);
593 if (ret < 0) m3ApiReturn(errno_to_wasi(errno));
594 res += ret;
595 if ((size_t)ret < len) break;
596 }
597 m3ApiWriteMem32(nread, res);
598 m3ApiReturn(__WASI_ERRNO_SUCCESS);
599 #endif
600 }
601
m3ApiRawFunction(m3_wasi_generic_fd_write)602 m3ApiRawFunction(m3_wasi_generic_fd_write)
603 {
604 m3ApiReturnType (uint32_t)
605 m3ApiGetArg (__wasi_fd_t , fd)
606 m3ApiGetArgMem (wasi_iovec_t * , wasi_iovs)
607 m3ApiGetArg (__wasi_size_t , iovs_len)
608 m3ApiGetArgMem (__wasi_size_t * , nwritten)
609
610 m3ApiCheckMem(wasi_iovs, iovs_len * sizeof(wasi_iovec_t));
611 m3ApiCheckMem(nwritten, sizeof(__wasi_size_t));
612
613 #if defined(HAS_IOVEC)
614 struct iovec iovs[iovs_len];
615 copy_iov_to_host(_mem, iovs, wasi_iovs, iovs_len);
616
617 ssize_t ret = writev(fd, iovs, iovs_len);
618 if (ret < 0) { m3ApiReturn(errno_to_wasi(errno)); }
619 m3ApiWriteMem32(nwritten, ret);
620 m3ApiReturn(__WASI_ERRNO_SUCCESS);
621 #else
622 ssize_t res = 0;
623 for (__wasi_size_t i = 0; i < iovs_len; i++) {
624 void* addr = m3ApiOffsetToPtr(m3ApiReadMem32(&wasi_iovs[i].buf));
625 size_t len = m3ApiReadMem32(&wasi_iovs[i].buf_len);
626 if (len == 0) continue;
627
628 int ret = write (fd, addr, len);
629 if (ret < 0) m3ApiReturn(errno_to_wasi(errno));
630 res += ret;
631 if ((size_t)ret < len) break;
632 }
633 m3ApiWriteMem32(nwritten, res);
634 m3ApiReturn(__WASI_ERRNO_SUCCESS);
635 #endif
636 }
637
m3ApiRawFunction(m3_wasi_generic_fd_close)638 m3ApiRawFunction(m3_wasi_generic_fd_close)
639 {
640 m3ApiReturnType (uint32_t)
641 m3ApiGetArg (__wasi_fd_t, fd)
642
643 int ret = close(fd);
644 m3ApiReturn(ret == 0 ? __WASI_ERRNO_SUCCESS : ret);
645 }
646
m3ApiRawFunction(m3_wasi_generic_fd_datasync)647 m3ApiRawFunction(m3_wasi_generic_fd_datasync)
648 {
649 m3ApiReturnType (uint32_t)
650 m3ApiGetArg (__wasi_fd_t, fd)
651
652 #if defined(_WIN32)
653 int ret = _commit(fd);
654 #elif defined(__APPLE__)
655 int ret = fsync(fd);
656 #elif defined(__ANDROID_API__) || defined(__OpenBSD__) || defined(__linux__) || defined(__EMSCRIPTEN__)
657 int ret = fdatasync(fd);
658 #else
659 int ret = __WASI_ERRNO_NOSYS;
660 #endif
661 m3ApiReturn(ret == 0 ? __WASI_ERRNO_SUCCESS : ret);
662 }
663
m3ApiRawFunction(m3_wasi_generic_random_get)664 m3ApiRawFunction(m3_wasi_generic_random_get)
665 {
666 m3ApiReturnType (uint32_t)
667 m3ApiGetArgMem (uint8_t * , buf)
668 m3ApiGetArg (__wasi_size_t , buf_len)
669
670 m3ApiCheckMem(buf, buf_len);
671
672 while (1) {
673 ssize_t retlen = 0;
674
675 #if defined(__wasi__) || defined(__APPLE__) || defined(__ANDROID_API__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
676 size_t reqlen = M3_MIN (buf_len, 256);
677 # if defined(__APPLE__) && (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
678 retlen = SecRandomCopyBytes(kSecRandomDefault, reqlen, buf) < 0 ? -1 : reqlen;
679 # else
680 retlen = getentropy(buf, reqlen) < 0 ? -1 : reqlen;
681 # endif
682 #elif defined(__FreeBSD__) || defined(__linux__) || defined(__DragonFly__)
683 retlen = getrandom(buf, buf_len, 0);
684 #elif defined(_WIN32)
685 if (RtlGenRandom(buf, buf_len) == TRUE) {
686 m3ApiReturn(__WASI_ERRNO_SUCCESS);
687 }
688 #else
689 m3ApiReturn(__WASI_ERRNO_NOSYS);
690 #endif
691 if (retlen < 0) {
692 if (errno == EINTR || errno == EAGAIN) {
693 continue;
694 }
695 m3ApiReturn(errno_to_wasi(errno));
696 } else if (retlen == buf_len) {
697 m3ApiReturn(__WASI_ERRNO_SUCCESS);
698 } else {
699 buf += retlen;
700 buf_len -= retlen;
701 }
702 }
703 }
704
m3ApiRawFunction(m3_wasi_generic_clock_res_get)705 m3ApiRawFunction(m3_wasi_generic_clock_res_get)
706 {
707 m3ApiReturnType (uint32_t)
708 m3ApiGetArg (__wasi_clockid_t , wasi_clk_id)
709 m3ApiGetArgMem (__wasi_timestamp_t * , resolution)
710
711 m3ApiCheckMem(resolution, sizeof(__wasi_timestamp_t));
712
713 int clk = convert_clockid(wasi_clk_id);
714 if (clk < 0) m3ApiReturn(__WASI_ERRNO_INVAL);
715
716 struct timespec tp;
717 if (clock_getres(clk, &tp) != 0) {
718 m3ApiWriteMem64(resolution, 1000000);
719 } else {
720 m3ApiWriteMem64(resolution, convert_timespec(&tp));
721 }
722
723 m3ApiReturn(__WASI_ERRNO_SUCCESS);
724 }
725
m3ApiRawFunction(m3_wasi_generic_clock_time_get)726 m3ApiRawFunction(m3_wasi_generic_clock_time_get)
727 {
728 m3ApiReturnType (uint32_t)
729 m3ApiGetArg (__wasi_clockid_t , wasi_clk_id)
730 m3ApiGetArg (__wasi_timestamp_t , precision)
731 m3ApiGetArgMem (__wasi_timestamp_t * , time)
732
733 m3ApiCheckMem(time, sizeof(__wasi_timestamp_t));
734
735 int clk = convert_clockid(wasi_clk_id);
736 if (clk < 0) m3ApiReturn(__WASI_ERRNO_INVAL);
737
738 struct timespec tp;
739 if (clock_gettime(clk, &tp) != 0) {
740 m3ApiReturn(errno_to_wasi(errno));
741 }
742
743 m3ApiWriteMem64(time, convert_timespec(&tp));
744 m3ApiReturn(__WASI_ERRNO_SUCCESS);
745 }
746
m3ApiRawFunction(m3_wasi_generic_proc_exit)747 m3ApiRawFunction(m3_wasi_generic_proc_exit)
748 {
749 m3ApiGetArg (uint32_t, code)
750
751 m3_wasi_context_t* context = (m3_wasi_context_t*)(_ctx->userdata);
752
753 if (context) {
754 context->exit_code = code;
755 }
756
757 m3ApiTrap(m3Err_trapExit);
758 }
759
760
761 static
SuppressLookupFailure(M3Result i_result)762 M3Result SuppressLookupFailure(M3Result i_result)
763 {
764 if (i_result == m3Err_functionLookupFailed)
765 return m3Err_none;
766 else
767 return i_result;
768 }
769
m3_GetWasiContext()770 m3_wasi_context_t* m3_GetWasiContext()
771 {
772 return wasi_context;
773 }
774
775
m3_LinkWASI(IM3Module module)776 M3Result m3_LinkWASI (IM3Module module)
777 {
778 M3Result result = m3Err_none;
779
780 #ifdef _WIN32
781 setmode(fileno(stdin), O_BINARY);
782 setmode(fileno(stdout), O_BINARY);
783 setmode(fileno(stderr), O_BINARY);
784
785 #else
786 // Preopen dirs
787 for (int i = 3; i < PREOPEN_CNT; i++) {
788 preopen[i].fd = open(preopen[i].real_path, O_RDONLY);
789 }
790 #endif
791
792 if (!wasi_context) {
793 wasi_context = (m3_wasi_context_t*)malloc(sizeof(m3_wasi_context_t));
794 wasi_context->exit_code = 0;
795 wasi_context->argc = 0;
796 wasi_context->argv = 0;
797 }
798
799 static const char* namespaces[2] = { "wasi_unstable", "wasi_snapshot_preview1" };
800
801 // fd_seek is incompatible
802 _ (SuppressLookupFailure (m3_LinkRawFunction (module, "wasi_unstable", "fd_seek", "i(iIi*)", &m3_wasi_unstable_fd_seek)));
803 _ (SuppressLookupFailure (m3_LinkRawFunction (module, "wasi_snapshot_preview1", "fd_seek", "i(iIi*)", &m3_wasi_snapshot_preview1_fd_seek)));
804
805 for (int i=0; i<2; i++)
806 {
807 const char* wasi = namespaces[i];
808
809 _ (SuppressLookupFailure (m3_LinkRawFunctionEx (module, wasi, "args_get", "i(**)", &m3_wasi_generic_args_get, wasi_context)));
810 _ (SuppressLookupFailure (m3_LinkRawFunctionEx (module, wasi, "args_sizes_get", "i(**)", &m3_wasi_generic_args_sizes_get, wasi_context)));
811 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "clock_res_get", "i(i*)", &m3_wasi_generic_clock_res_get)));
812 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "clock_time_get", "i(iI*)", &m3_wasi_generic_clock_time_get)));
813 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "environ_get", "i(**)", &m3_wasi_generic_environ_get)));
814 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "environ_sizes_get", "i(**)", &m3_wasi_generic_environ_sizes_get)));
815
816 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_advise", "i(iIIi)", )));
817 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_allocate", "i(iII)", )));
818 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_close", "i(i)", &m3_wasi_generic_fd_close)));
819 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_datasync", "i(i)", &m3_wasi_generic_fd_datasync)));
820 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_fdstat_get", "i(i*)", &m3_wasi_generic_fd_fdstat_get)));
821 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_fdstat_set_flags", "i(ii)", &m3_wasi_generic_fd_fdstat_set_flags)));
822 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_fdstat_set_rights", "i(iII)", )));
823 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_filestat_get", "i(i*)", )));
824 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_filestat_set_size", "i(iI)", )));
825 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_filestat_set_times","i(iIIi)", )));
826 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_pread", "i(i*iI*)",)));
827 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_prestat_get", "i(i*)", &m3_wasi_generic_fd_prestat_get)));
828 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_prestat_dir_name", "i(i*i)", &m3_wasi_generic_fd_prestat_dir_name)));
829 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_pwrite", "i(i*iI*)",)));
830 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_read", "i(i*i*)", &m3_wasi_generic_fd_read)));
831 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_readdir", "i(i*iI*)",)));
832 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_renumber", "i(ii)", )));
833 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_sync", "i(i)", )));
834 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_tell", "i(i*)", )));
835 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "fd_write", "i(i*i*)", &m3_wasi_generic_fd_write)));
836
837 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_create_directory", "i(i*i)", )));
838 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_filestat_get", "i(ii*i*)", &m3_wasi_generic_path_filestat_get)));
839 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_filestat_set_times", "i(ii*iIIi)", )));
840 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_link", "i(ii*ii*i)", )));
841 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_open", "i(ii*iiIIi*)", &m3_wasi_generic_path_open)));
842 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_readlink", "i(i*i*i*)", )));
843 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_remove_directory", "i(i*i)", )));
844 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_rename", "i(i*ii*i)", )));
845 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_symlink", "i(*ii*i)", )));
846 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_unlink_file", "i(i*i)", )));
847
848 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "poll_oneoff", "i(**i*)", &m3_wasi_generic_poll_oneoff)));
849 _ (SuppressLookupFailure (m3_LinkRawFunctionEx (module, wasi, "proc_exit", "v(i)", &m3_wasi_generic_proc_exit, wasi_context)));
850 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "proc_raise", "i(i)", )));
851 _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "random_get", "i(*i)", &m3_wasi_generic_random_get)));
852 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "sched_yield", "i()", )));
853
854 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "sock_recv", "i(i*ii**)", )));
855 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "sock_send", "i(i*ii*)", )));
856 //_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "sock_shutdown", "i(ii)", )));
857 }
858
859 _catch:
860 return result;
861 }
862
863 #endif // d_m3HasWASI
864