@tybys/wasm-util 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ const error_1 = require("./error");
9
9
  const util_1 = require("./util");
10
10
  const rights_1 = require("./rights");
11
11
  const memory_1 = require("../memory");
12
+ const jspi_1 = require("../jspi");
12
13
  function copyMemory(targets, src) {
13
14
  if (targets.length === 0 || src.length === 0)
14
15
  return 0;
@@ -67,7 +68,7 @@ function defineName(name, f) {
67
68
  Object.defineProperty(f, 'name', { value: name });
68
69
  return f;
69
70
  }
70
- function syscallWrap(name, f) {
71
+ function syscallWrap(self, name, f) {
71
72
  return defineName(name, function () {
72
73
  if (process.env.NODE_DEBUG_NATIVE === 'wasi') {
73
74
  const args = Array.prototype.slice.call(arguments);
@@ -77,7 +78,7 @@ function syscallWrap(name, f) {
77
78
  }
78
79
  let r;
79
80
  try {
80
- r = f.apply(this, arguments);
81
+ r = f.apply(self, arguments);
81
82
  }
82
83
  catch (err) {
83
84
  return handleError(err);
@@ -88,7 +89,7 @@ function syscallWrap(name, f) {
88
89
  return r;
89
90
  });
90
91
  }
91
- function resolvePath(fs, fileDescriptor, path, flags) {
92
+ function resolvePathSync(fs, fileDescriptor, path, flags) {
92
93
  let resolvedPath = (0, path_1.resolve)(fileDescriptor.realPath, path);
93
94
  if ((flags & 1) === 1) {
94
95
  try {
@@ -102,6 +103,20 @@ function resolvePath(fs, fileDescriptor, path, flags) {
102
103
  }
103
104
  return resolvedPath;
104
105
  }
106
+ async function resolvePathAsync(fs, fileDescriptor, path, flags) {
107
+ let resolvedPath = (0, path_1.resolve)(fileDescriptor.realPath, path);
108
+ if ((flags & 1) === 1) {
109
+ try {
110
+ resolvedPath = await fs.promises.readlink(resolvedPath);
111
+ }
112
+ catch (err) {
113
+ if (err.code !== 'EINVAL' && err.code !== 'ENOENT') {
114
+ throw err;
115
+ }
116
+ }
117
+ }
118
+ return resolvedPath;
119
+ }
105
120
  const encoder = new TextEncoder();
106
121
  const decoder = new TextDecoder();
107
122
  function readStdin() {
@@ -112,14 +127,8 @@ function readStdin() {
112
127
  return buffer;
113
128
  }
114
129
  class WASI {
115
- constructor(args, env, preopens, stdio, filesystem, print, printErr) {
116
- this._setMemory = function _setMemory(m) {
117
- if (!(m instanceof webassembly_1._WebAssembly.Memory)) {
118
- throw new TypeError('"instance.exports.memory" property must be a WebAssembly.Memory');
119
- }
120
- _memory.set(this, (0, memory_1.extendMemory)(m));
121
- };
122
- this.args_get = syscallWrap('args_get', function (argv, argv_buf) {
130
+ constructor(args, env, fds, asyncFs, fs, asyncify) {
131
+ this.args_get = syscallWrap(this, 'args_get', function (argv, argv_buf) {
123
132
  argv = Number(argv);
124
133
  argv_buf = Number(argv_buf);
125
134
  if (argv === 0 || argv_buf === 0) {
@@ -138,7 +147,7 @@ class WASI {
138
147
  }
139
148
  return types_1.WasiErrno.ESUCCESS;
140
149
  });
141
- this.args_sizes_get = syscallWrap('args_sizes_get', function (argc, argv_buf_size) {
150
+ this.args_sizes_get = syscallWrap(this, 'args_sizes_get', function (argc, argv_buf_size) {
142
151
  argc = Number(argc);
143
152
  argv_buf_size = Number(argv_buf_size);
144
153
  if (argc === 0 || argv_buf_size === 0) {
@@ -151,7 +160,7 @@ class WASI {
151
160
  view.setUint32(argv_buf_size, encoder.encode(args.join('\0') + '\0').length, true);
152
161
  return types_1.WasiErrno.ESUCCESS;
153
162
  });
154
- this.environ_get = syscallWrap('environ_get', function (environ, environ_buf) {
163
+ this.environ_get = syscallWrap(this, 'environ_get', function (environ, environ_buf) {
155
164
  environ = Number(environ);
156
165
  environ_buf = Number(environ_buf);
157
166
  if (environ === 0 || environ_buf === 0) {
@@ -170,7 +179,7 @@ class WASI {
170
179
  }
171
180
  return types_1.WasiErrno.ESUCCESS;
172
181
  });
173
- this.environ_sizes_get = syscallWrap('environ_sizes_get', function (len, buflen) {
182
+ this.environ_sizes_get = syscallWrap(this, 'environ_sizes_get', function (len, buflen) {
174
183
  len = Number(len);
175
184
  buflen = Number(buflen);
176
185
  if (len === 0 || buflen === 0) {
@@ -182,7 +191,7 @@ class WASI {
182
191
  view.setUint32(buflen, encoder.encode(wasi.env.join('\0') + '\0').length, true);
183
192
  return types_1.WasiErrno.ESUCCESS;
184
193
  });
185
- this.clock_res_get = syscallWrap('clock_res_get', function (id, resolution) {
194
+ this.clock_res_get = syscallWrap(this, 'clock_res_get', function (id, resolution) {
186
195
  resolution = Number(resolution);
187
196
  if (resolution === 0) {
188
197
  return types_1.WasiErrno.EINVAL;
@@ -200,7 +209,7 @@ class WASI {
200
209
  default: return types_1.WasiErrno.EINVAL;
201
210
  }
202
211
  });
203
- this.clock_time_get = syscallWrap('clock_time_get', function (id, _percision, time) {
212
+ this.clock_time_get = syscallWrap(this, 'clock_time_get', function (id, _percision, time) {
204
213
  time = Number(time);
205
214
  if (time === 0) {
206
215
  return types_1.WasiErrno.EINVAL;
@@ -223,35 +232,10 @@ class WASI {
223
232
  default: return types_1.WasiErrno.EINVAL;
224
233
  }
225
234
  });
226
- this.fd_advise = syscallWrap('fd_advise', function (_fd, _offset, _len, _advice) {
235
+ this.fd_advise = syscallWrap(this, 'fd_advise', function (_fd, _offset, _len, _advice) {
227
236
  return types_1.WasiErrno.ENOSYS;
228
237
  });
229
- this.fd_allocate = syscallWrap('fd_allocate', function (fd, offset, len) {
230
- const wasi = _wasi.get(this);
231
- const fs = getFs(this);
232
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_ALLOCATE, BigInt(0));
233
- const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
234
- if (stat.size < offset + len) {
235
- fs.ftruncateSync(fileDescriptor.fd, Number(offset + len));
236
- }
237
- return types_1.WasiErrno.ESUCCESS;
238
- });
239
- this.fd_close = syscallWrap('fd_close', function (fd) {
240
- const wasi = _wasi.get(this);
241
- const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
242
- const fs = getFs(this);
243
- fs.closeSync(fileDescriptor.fd);
244
- wasi.fds.remove(fd);
245
- return types_1.WasiErrno.ESUCCESS;
246
- });
247
- this.fd_datasync = syscallWrap('fd_datasync', function (fd) {
248
- const wasi = _wasi.get(this);
249
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_DATASYNC, BigInt(0));
250
- const fs = getFs(this);
251
- fs.fdatasyncSync(fileDescriptor.fd);
252
- return types_1.WasiErrno.ESUCCESS;
253
- });
254
- this.fd_fdstat_get = syscallWrap('fd_fdstat_get', function (fd, fdstat) {
238
+ this.fd_fdstat_get = syscallWrap(this, 'fd_fdstat_get', function (fd, fdstat) {
255
239
  fdstat = Number(fdstat);
256
240
  if (fdstat === 0) {
257
241
  return types_1.WasiErrno.EINVAL;
@@ -265,10 +249,10 @@ class WASI {
265
249
  view.setBigUint64(fdstat + 16, fileDescriptor.rightsInheriting, true);
266
250
  return types_1.WasiErrno.ESUCCESS;
267
251
  });
268
- this.fd_fdstat_set_flags = syscallWrap('fd_fdstat_set_flags', function (_fd, _flags) {
252
+ this.fd_fdstat_set_flags = syscallWrap(this, 'fd_fdstat_set_flags', function (_fd, _flags) {
269
253
  return types_1.WasiErrno.ENOSYS;
270
254
  });
271
- this.fd_fdstat_set_rights = syscallWrap('fd_fdstat_set_rights', function (fd, rightsBase, rightsInheriting) {
255
+ this.fd_fdstat_set_rights = syscallWrap(this, 'fd_fdstat_set_rights', function (fd, rightsBase, rightsInheriting) {
272
256
  const wasi = _wasi.get(this);
273
257
  const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
274
258
  if ((rightsBase | fileDescriptor.rightsBase) > fileDescriptor.rightsBase) {
@@ -282,7 +266,186 @@ class WASI {
282
266
  fileDescriptor.rightsInheriting = rightsInheriting;
283
267
  return types_1.WasiErrno.ESUCCESS;
284
268
  });
285
- this.fd_filestat_get = syscallWrap('fd_filestat_get', function (fd, buf) {
269
+ this.fd_prestat_get = syscallWrap(this, 'fd_prestat_get', function (fd, prestat) {
270
+ prestat = Number(prestat);
271
+ if (prestat === 0) {
272
+ return types_1.WasiErrno.EINVAL;
273
+ }
274
+ const wasi = _wasi.get(this);
275
+ let fileDescriptor;
276
+ try {
277
+ fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
278
+ }
279
+ catch (err) {
280
+ if (err instanceof error_1.WasiError)
281
+ return err.errno;
282
+ throw err;
283
+ }
284
+ if (fileDescriptor.preopen !== 1)
285
+ return types_1.WasiErrno.EINVAL;
286
+ const { view } = getMemory(this);
287
+ // preopen type is dir(0)
288
+ view.setUint32(prestat, 0, true);
289
+ view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length + 1, true);
290
+ return types_1.WasiErrno.ESUCCESS;
291
+ });
292
+ this.fd_prestat_dir_name = syscallWrap(this, 'fd_prestat_dir_name', function (fd, path, path_len) {
293
+ path = Number(path);
294
+ path_len = Number(path_len);
295
+ if (path === 0) {
296
+ return types_1.WasiErrno.EINVAL;
297
+ }
298
+ const wasi = _wasi.get(this);
299
+ const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
300
+ if (fileDescriptor.preopen !== 1)
301
+ return types_1.WasiErrno.EBADF;
302
+ const buffer = encoder.encode(fileDescriptor.path + '\0');
303
+ const size = buffer.length;
304
+ if (size > path_len)
305
+ return types_1.WasiErrno.ENOBUFS;
306
+ const { HEAPU8 } = getMemory(this);
307
+ HEAPU8.set(buffer, path);
308
+ return types_1.WasiErrno.ESUCCESS;
309
+ });
310
+ this.fd_seek = syscallWrap(this, 'fd_seek', function (fd, offset, whence, newOffset) {
311
+ newOffset = Number(newOffset);
312
+ if (newOffset === 0) {
313
+ return types_1.WasiErrno.EINVAL;
314
+ }
315
+ if (fd === 0 || fd === 1 || fd === 2)
316
+ return types_1.WasiErrno.ESUCCESS;
317
+ const wasi = _wasi.get(this);
318
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SEEK, BigInt(0));
319
+ const r = fileDescriptor.seek(offset, whence);
320
+ const { view } = getMemory(this);
321
+ view.setBigUint64(newOffset, r, true);
322
+ return types_1.WasiErrno.ESUCCESS;
323
+ });
324
+ this.fd_tell = syscallWrap(this, 'fd_tell', function (fd, offset) {
325
+ const wasi = _wasi.get(this);
326
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_TELL, BigInt(0));
327
+ const pos = BigInt(fileDescriptor.pos);
328
+ const { view } = getMemory(this);
329
+ view.setBigUint64(Number(offset), pos, true);
330
+ return types_1.WasiErrno.ESUCCESS;
331
+ });
332
+ this.poll_oneoff = syscallWrap(this, 'poll_oneoff', function (_in, _out, _sub, _nevents) {
333
+ return types_1.WasiErrno.ENOSYS;
334
+ });
335
+ this.proc_exit = syscallWrap(this, 'proc_exit', function (_rval) {
336
+ return types_1.WasiErrno.ESUCCESS;
337
+ });
338
+ this.proc_raise = syscallWrap(this, 'proc_raise', function (_sig) {
339
+ return types_1.WasiErrno.ENOSYS;
340
+ });
341
+ this.sched_yield = syscallWrap(this, 'sched_yield', function () {
342
+ return types_1.WasiErrno.ESUCCESS;
343
+ });
344
+ this.random_get = typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function'
345
+ ? syscallWrap(this, 'random_get', function (buf, buf_len) {
346
+ buf = Number(buf);
347
+ if (buf === 0) {
348
+ return types_1.WasiErrno.EINVAL;
349
+ }
350
+ buf_len = Number(buf_len);
351
+ const { HEAPU8 } = getMemory(this);
352
+ let pos;
353
+ const stride = 65536;
354
+ for (pos = 0; pos + stride < buf_len; pos += stride) {
355
+ crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + pos + stride));
356
+ }
357
+ crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + buf_len));
358
+ return types_1.WasiErrno.ESUCCESS;
359
+ })
360
+ : syscallWrap(this, 'random_get', function (buf, buf_len) {
361
+ buf = Number(buf);
362
+ if (buf === 0) {
363
+ return types_1.WasiErrno.EINVAL;
364
+ }
365
+ buf_len = Number(buf_len);
366
+ const { view } = getMemory(this);
367
+ for (let i = buf; i < buf + buf_len; ++i) {
368
+ view.setUint8(i, Math.floor(Math.random() * 256));
369
+ }
370
+ return types_1.WasiErrno.ESUCCESS;
371
+ });
372
+ this.sock_recv = syscallWrap(this, 'sock_recv', function () {
373
+ return types_1.WasiErrno.ENOTSUP;
374
+ });
375
+ this.sock_send = syscallWrap(this, 'sock_send', function () {
376
+ return types_1.WasiErrno.ENOTSUP;
377
+ });
378
+ this.sock_shutdown = syscallWrap(this, 'sock_shutdown', function () {
379
+ return types_1.WasiErrno.ENOTSUP;
380
+ });
381
+ _wasi.set(this, {
382
+ fds,
383
+ args,
384
+ env
385
+ });
386
+ if (fs)
387
+ _fs.set(this, fs);
388
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
389
+ const _this = this;
390
+ function defineImport(name, syncVersion, asyncVersion, parameterType, returnType) {
391
+ if (asyncFs) {
392
+ if (asyncify) {
393
+ _this[name] = asyncify.wrapImportFunction(syscallWrap(_this, name, asyncVersion));
394
+ }
395
+ else {
396
+ _this[name] = (0, jspi_1.wrapAsyncImport)(syscallWrap(_this, name, asyncVersion), parameterType, returnType);
397
+ }
398
+ }
399
+ else {
400
+ _this[name] = syscallWrap(_this, name, syncVersion);
401
+ }
402
+ }
403
+ defineImport('fd_allocate', function fd_allocate(fd, offset, len) {
404
+ const wasi = _wasi.get(this);
405
+ const fs = getFs(this);
406
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_ALLOCATE, BigInt(0));
407
+ const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
408
+ if (stat.size < offset + len) {
409
+ fs.ftruncateSync(fileDescriptor.fd, Number(offset + len));
410
+ }
411
+ return types_1.WasiErrno.ESUCCESS;
412
+ }, async function fd_allocate(fd, offset, len) {
413
+ const wasi = _wasi.get(this);
414
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_ALLOCATE, BigInt(0));
415
+ const h = fileDescriptor.fd;
416
+ const stat = await h.stat({ bigint: true });
417
+ if (stat.size < offset + len) {
418
+ await h.truncate(Number(offset + len));
419
+ }
420
+ return types_1.WasiErrno.ESUCCESS;
421
+ }, ['i32', 'i64', 'f64'], ['i32']);
422
+ defineImport('fd_close', function fd_close(fd) {
423
+ const wasi = _wasi.get(this);
424
+ const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
425
+ const fs = getFs(this);
426
+ fs.closeSync(fileDescriptor.fd);
427
+ wasi.fds.remove(fd);
428
+ return types_1.WasiErrno.ESUCCESS;
429
+ }, async function fd_close(fd) {
430
+ const wasi = _wasi.get(this);
431
+ const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
432
+ await fileDescriptor.fd.close();
433
+ wasi.fds.remove(fd);
434
+ return types_1.WasiErrno.ESUCCESS;
435
+ }, ['i32'], ['i32']);
436
+ defineImport('fd_datasync', function fd_datasync(fd) {
437
+ const wasi = _wasi.get(this);
438
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_DATASYNC, BigInt(0));
439
+ const fs = getFs(this);
440
+ fs.fdatasyncSync(fileDescriptor.fd);
441
+ return types_1.WasiErrno.ESUCCESS;
442
+ }, async function fd_datasync(fd) {
443
+ const wasi = _wasi.get(this);
444
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_DATASYNC, BigInt(0));
445
+ await fileDescriptor.fd.datasync();
446
+ return types_1.WasiErrno.ESUCCESS;
447
+ }, ['i32'], ['i32']);
448
+ defineImport('fd_filestat_get', function fd_filestat_get(fd, buf) {
286
449
  buf = Number(buf);
287
450
  if (buf === 0)
288
451
  return types_1.WasiErrno.EINVAL;
@@ -293,15 +456,32 @@ class WASI {
293
456
  const { view } = getMemory(this);
294
457
  (0, fd_1.toFileStat)(view, buf, stat);
295
458
  return types_1.WasiErrno.ESUCCESS;
296
- });
297
- this.fd_filestat_set_size = syscallWrap('fd_filestat_set_size', function (fd, size) {
459
+ }, async function fd_filestat_get(fd, buf) {
460
+ buf = Number(buf);
461
+ if (buf === 0)
462
+ return types_1.WasiErrno.EINVAL;
463
+ const wasi = _wasi.get(this);
464
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_GET, BigInt(0));
465
+ const h = fileDescriptor.fd;
466
+ const stat = await h.stat({ bigint: true });
467
+ const { view } = getMemory(this);
468
+ (0, fd_1.toFileStat)(view, buf, stat);
469
+ return types_1.WasiErrno.ESUCCESS;
470
+ }, ['i32', 'i32'], ['i32']);
471
+ defineImport('fd_filestat_set_size', function fd_filestat_set_size(fd, size) {
298
472
  const wasi = _wasi.get(this);
299
473
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_SET_SIZE, BigInt(0));
300
474
  const fs = getFs(this);
301
475
  fs.ftruncateSync(fileDescriptor.fd, Number(size));
302
476
  return types_1.WasiErrno.ESUCCESS;
303
- });
304
- this.fd_filestat_set_times = syscallWrap('fd_filestat_set_times', function (fd, atim, mtim, flags) {
477
+ }, async function fd_filestat_set_size(fd, size) {
478
+ const wasi = _wasi.get(this);
479
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_SET_SIZE, BigInt(0));
480
+ const h = fileDescriptor.fd;
481
+ await h.truncate(Number(size));
482
+ return types_1.WasiErrno.ESUCCESS;
483
+ }, ['i32', 'i64'], ['i32']);
484
+ function fdFilestatGetTimes(fd, atim, mtim, flags) {
305
485
  const wasi = _wasi.get(this);
306
486
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_SET_TIMES, BigInt(0));
307
487
  if ((flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
@@ -310,11 +490,20 @@ class WASI {
310
490
  if ((flags & types_1.WasiFstFlag.SET_MTIM_NOW) === types_1.WasiFstFlag.SET_MTIM_NOW) {
311
491
  mtim = BigInt(Date.now() * 1000000);
312
492
  }
493
+ return { fileDescriptor, atim, mtim };
494
+ }
495
+ defineImport('fd_filestat_set_times', function fd_filestat_set_times(fd, atim, mtim, flags) {
496
+ const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
313
497
  const fs = getFs(this);
314
- fs.futimesSync(fileDescriptor.fd, Number(atim), Number(mtim));
498
+ fs.futimesSync(fileDescriptor.fd, Number(atimRes), Number(mtimRes));
315
499
  return types_1.WasiErrno.ESUCCESS;
316
- });
317
- this.fd_pread = syscallWrap('fd_pread', function (fd, iovs, iovslen, offset, size) {
500
+ }, async function fd_filestat_set_times(fd, atim, mtim, flags) {
501
+ const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
502
+ const h = fileDescriptor.fd;
503
+ await h.utimes(Number(atimRes), Number(mtimRes));
504
+ return types_1.WasiErrno.ESUCCESS;
505
+ }, ['i32', 'i64', 'i64', 'i32'], ['i32']);
506
+ defineImport('fd_pread', function fd_pread(fd, iovs, iovslen, offset, size) {
318
507
  iovs = Number(iovs);
319
508
  size = Number(size);
320
509
  if (iovs === 0 || size === 0) {
@@ -339,49 +528,51 @@ class WASI {
339
528
  nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
340
529
  view.setUint32(size, nread, true);
341
530
  return types_1.WasiErrno.ESUCCESS;
342
- });
343
- this.fd_prestat_get = syscallWrap('fd_prestat_get', function (fd, prestat) {
344
- prestat = Number(prestat);
345
- if (prestat === 0) {
531
+ }, async function (fd, iovs, iovslen, offset, size) {
532
+ iovs = Number(iovs);
533
+ size = Number(size);
534
+ if (iovs === 0 || size === 0) {
346
535
  return types_1.WasiErrno.EINVAL;
347
536
  }
537
+ const { HEAPU8, view } = getMemory(this);
348
538
  const wasi = _wasi.get(this);
349
- let fileDescriptor;
350
- try {
351
- fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
352
- }
353
- catch (err) {
354
- if (err instanceof error_1.WasiError)
355
- return err.errno;
356
- throw err;
357
- }
358
- if (fileDescriptor.preopen !== 1)
359
- return types_1.WasiErrno.EINVAL;
360
- const { view } = getMemory(this);
361
- // preopen type is dir(0)
362
- view.setUint32(prestat, 0, true);
363
- view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length + 1, true);
539
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ | types_1.WasiRights.FD_SEEK, BigInt(0));
540
+ let totalSize = 0;
541
+ const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
542
+ const offset = iovs + (i * 8);
543
+ const buf = view.getInt32(offset, true);
544
+ const bufLen = view.getUint32(offset + 4, true);
545
+ totalSize += bufLen;
546
+ return HEAPU8.subarray(buf, buf + bufLen);
547
+ });
548
+ let nread = 0;
549
+ const buffer = new Uint8Array(totalSize);
550
+ buffer._isBuffer = true;
551
+ const { bytesRead } = await fileDescriptor.fd.read(buffer, 0, buffer.length, Number(offset));
552
+ nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
553
+ view.setUint32(size, nread, true);
364
554
  return types_1.WasiErrno.ESUCCESS;
365
- });
366
- this.fd_prestat_dir_name = syscallWrap('fd_prestat_dir_name', function (fd, path, path_len) {
367
- path = Number(path);
368
- path_len = Number(path_len);
369
- if (path === 0) {
555
+ }, ['i32', 'i32', 'i32', 'i64', 'i32'], ['i32']);
556
+ defineImport('fd_pwrite', function fd_pwrite(fd, iovs, iovslen, offset, size) {
557
+ iovs = Number(iovs);
558
+ size = Number(size);
559
+ if (iovs === 0 || size === 0) {
370
560
  return types_1.WasiErrno.EINVAL;
371
561
  }
562
+ const { HEAPU8, view } = getMemory(this);
372
563
  const wasi = _wasi.get(this);
373
- const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
374
- if (fileDescriptor.preopen !== 1)
375
- return types_1.WasiErrno.EBADF;
376
- const buffer = encoder.encode(fileDescriptor.path + '\0');
377
- const size = buffer.length;
378
- if (size > path_len)
379
- return types_1.WasiErrno.ENOBUFS;
380
- const { HEAPU8 } = getMemory(this);
381
- HEAPU8.set(buffer, path);
564
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE | types_1.WasiRights.FD_SEEK, BigInt(0));
565
+ const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
566
+ const offset = iovs + (i * 8);
567
+ const buf = view.getInt32(offset, true);
568
+ const bufLen = view.getUint32(offset + 4, true);
569
+ return HEAPU8.subarray(buf, buf + bufLen);
570
+ }));
571
+ const fs = getFs(this);
572
+ const nwritten = fs.writeSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(offset));
573
+ view.setUint32(size, nwritten, true);
382
574
  return types_1.WasiErrno.ESUCCESS;
383
- });
384
- this.fd_pwrite = syscallWrap('fd_pwrite', function (fd, iovs, iovslen, offset, size) {
575
+ }, async function fd_pwrite(fd, iovs, iovslen, offset, size) {
385
576
  iovs = Number(iovs);
386
577
  size = Number(size);
387
578
  if (iovs === 0 || size === 0) {
@@ -396,12 +587,11 @@ class WASI {
396
587
  const bufLen = view.getUint32(offset + 4, true);
397
588
  return HEAPU8.subarray(buf, buf + bufLen);
398
589
  }));
399
- const fs = getFs(this);
400
- const nwritten = fs.writeSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(offset));
401
- view.setUint32(size, nwritten, true);
590
+ const { bytesWritten } = await fileDescriptor.fd.write(buffer, 0, buffer.length, Number(offset));
591
+ view.setUint32(size, bytesWritten, true);
402
592
  return types_1.WasiErrno.ESUCCESS;
403
- });
404
- this.fd_read = syscallWrap('fd_read', function (fd, iovs, iovslen, size) {
593
+ }, ['i32', 'i32', 'i32', 'i64', 'i32'], ['i32']);
594
+ defineImport('fd_read', function fd_read(fd, iovs, iovslen, size) {
405
595
  iovs = Number(iovs);
406
596
  size = Number(size);
407
597
  if (iovs === 0 || size === 0) {
@@ -437,22 +627,43 @@ class WASI {
437
627
  }
438
628
  view.setUint32(size, nread, true);
439
629
  return types_1.WasiErrno.ESUCCESS;
440
- });
441
- this.fd_seek = syscallWrap('fd_seek', function (fd, offset, whence, newOffset) {
442
- newOffset = Number(newOffset);
443
- if (newOffset === 0) {
630
+ }, async function fd_read(fd, iovs, iovslen, size) {
631
+ iovs = Number(iovs);
632
+ size = Number(size);
633
+ if (iovs === 0 || size === 0) {
444
634
  return types_1.WasiErrno.EINVAL;
445
635
  }
446
- if (fd === 0 || fd === 1 || fd === 2)
447
- return types_1.WasiErrno.ESUCCESS;
636
+ const { HEAPU8, view } = getMemory(this);
448
637
  const wasi = _wasi.get(this);
449
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SEEK, BigInt(0));
450
- const r = fileDescriptor.seek(offset, whence);
451
- const { view } = getMemory(this);
452
- view.setBigUint64(newOffset, r, true);
638
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ, BigInt(0));
639
+ let totalSize = 0;
640
+ const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
641
+ const offset = iovs + (i * 8);
642
+ const buf = view.getInt32(offset, true);
643
+ const bufLen = view.getUint32(offset + 4, true);
644
+ totalSize += bufLen;
645
+ return HEAPU8.subarray(buf, buf + bufLen);
646
+ });
647
+ let buffer;
648
+ let nread = 0;
649
+ if (fd === 0) {
650
+ if (typeof window === 'undefined' || typeof window.prompt !== 'function') {
651
+ return types_1.WasiErrno.ENOTSUP;
652
+ }
653
+ buffer = readStdin();
654
+ nread = buffer ? copyMemory(ioVecs, buffer) : 0;
655
+ }
656
+ else {
657
+ buffer = new Uint8Array(totalSize);
658
+ buffer._isBuffer = true;
659
+ const { bytesRead } = await fileDescriptor.fd.read(buffer, 0, buffer.length, Number(fileDescriptor.pos));
660
+ nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
661
+ fileDescriptor.pos += BigInt(nread);
662
+ }
663
+ view.setUint32(size, nread, true);
453
664
  return types_1.WasiErrno.ESUCCESS;
454
- });
455
- this.fd_readdir = syscallWrap('fd_readdir', function (fd, buf, buf_len, cookie, bufused) {
665
+ }, ['i32', 'i32', 'i32', 'i32'], ['i32']);
666
+ defineImport('fd_readdir', function fd_readdir(fd, buf, buf_len, cookie, bufused) {
456
667
  buf = Number(buf);
457
668
  buf_len = Number(buf_len);
458
669
  bufused = Number(bufused);
@@ -502,28 +713,79 @@ class WASI {
502
713
  }
503
714
  view.setUint32(bufused, bufferUsed, true);
504
715
  return types_1.WasiErrno.ESUCCESS;
505
- });
506
- this.fd_renumber = syscallWrap('fd_renumber', function (from, to) {
716
+ }, async function fd_readdir(fd, buf, buf_len, cookie, bufused) {
717
+ buf = Number(buf);
718
+ buf_len = Number(buf_len);
719
+ bufused = Number(bufused);
720
+ if (buf === 0 || bufused === 0)
721
+ return types_1.WasiErrno.ESUCCESS;
722
+ const wasi = _wasi.get(this);
723
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READDIR, BigInt(0));
724
+ const fs = getFs(this);
725
+ const entries = await fs.promises.readdir(fileDescriptor.realPath, { withFileTypes: true });
726
+ const { HEAPU8, view } = getMemory(this);
727
+ let bufferUsed = 0;
728
+ for (let i = Number(cookie); i < entries.length; i++) {
729
+ const nameData = encoder.encode(entries[i].name);
730
+ const entryInfo = await fs.promises.stat((0, path_1.resolve)(fileDescriptor.realPath, entries[i].name), { bigint: true });
731
+ const entryData = new Uint8Array(24 + nameData.byteLength);
732
+ const entryView = new DataView(entryData.buffer);
733
+ entryView.setBigUint64(0, BigInt(i + 1), true);
734
+ entryView.setBigUint64(8, BigInt(entryInfo.ino ? entryInfo.ino : 0), true);
735
+ entryView.setUint32(16, nameData.byteLength, true);
736
+ let type;
737
+ if (entries[i].isFile()) {
738
+ type = types_1.WasiFileType.REGULAR_FILE;
739
+ }
740
+ else if (entries[i].isDirectory()) {
741
+ type = types_1.WasiFileType.DIRECTORY;
742
+ }
743
+ else if (entries[i].isSymbolicLink()) {
744
+ type = types_1.WasiFileType.SYMBOLIC_LINK;
745
+ }
746
+ else if (entries[i].isCharacterDevice()) {
747
+ type = types_1.WasiFileType.CHARACTER_DEVICE;
748
+ }
749
+ else if (entries[i].isBlockDevice()) {
750
+ type = types_1.WasiFileType.BLOCK_DEVICE;
751
+ }
752
+ else if (entries[i].isSocket()) {
753
+ type = types_1.WasiFileType.SOCKET_STREAM;
754
+ }
755
+ else {
756
+ type = types_1.WasiFileType.UNKNOWN;
757
+ }
758
+ entryView.setUint8(20, type);
759
+ entryData.set(nameData, 24);
760
+ const data = entryData.slice(0, Math.min(entryData.length, buf_len - bufferUsed));
761
+ HEAPU8.set(data, buf + bufferUsed);
762
+ bufferUsed += data.byteLength;
763
+ }
764
+ view.setUint32(bufused, bufferUsed, true);
765
+ return types_1.WasiErrno.ESUCCESS;
766
+ }, ['i32', 'i32', 'i32', 'i64', 'i32'], ['i32']);
767
+ defineImport('fd_renumber', function fd_renumber(from, to) {
507
768
  const wasi = _wasi.get(this);
508
769
  wasi.fds.renumber(to, from);
509
770
  return types_1.WasiErrno.ESUCCESS;
510
- });
511
- this.fd_sync = syscallWrap('fd_sync', function (fd) {
771
+ }, async function fd_renumber(from, to) {
772
+ const wasi = _wasi.get(this);
773
+ await wasi.fds.renumber(to, from);
774
+ return types_1.WasiErrno.ESUCCESS;
775
+ }, ['i32', 'i32'], ['i32']);
776
+ defineImport('fd_sync', function fd_sync(fd) {
512
777
  const wasi = _wasi.get(this);
513
778
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SYNC, BigInt(0));
514
779
  const fs = getFs(this);
515
780
  fs.fsyncSync(fileDescriptor.fd);
516
781
  return types_1.WasiErrno.ESUCCESS;
517
- });
518
- this.fd_tell = syscallWrap('fd_tell', function (fd, offset) {
782
+ }, async function fd_sync(fd) {
519
783
  const wasi = _wasi.get(this);
520
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_TELL, BigInt(0));
521
- const pos = BigInt(fileDescriptor.pos);
522
- const { view } = getMemory(this);
523
- view.setBigUint64(Number(offset), pos, true);
784
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SYNC, BigInt(0));
785
+ await fileDescriptor.fd.sync();
524
786
  return types_1.WasiErrno.ESUCCESS;
525
- });
526
- this.fd_write = syscallWrap('fd_write', function (fd, iovs, iovslen, size) {
787
+ }, ['i32'], ['i32']);
788
+ defineImport('fd_write', function fd_write(fd, iovs, iovslen, size) {
527
789
  iovs = Number(iovs);
528
790
  size = Number(size);
529
791
  if (iovs === 0 || size === 0) {
@@ -549,8 +811,47 @@ class WASI {
549
811
  }
550
812
  view.setUint32(size, nwritten, true);
551
813
  return types_1.WasiErrno.ESUCCESS;
552
- });
553
- this.path_create_directory = syscallWrap('path_create_directory', function (fd, path, path_len) {
814
+ }, async function fd_write(fd, iovs, iovslen, size) {
815
+ iovs = Number(iovs);
816
+ size = Number(size);
817
+ if (iovs === 0 || size === 0) {
818
+ return types_1.WasiErrno.EINVAL;
819
+ }
820
+ const { HEAPU8, view } = getMemory(this);
821
+ const wasi = _wasi.get(this);
822
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE, BigInt(0));
823
+ const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
824
+ const offset = iovs + (i * 8);
825
+ const buf = view.getInt32(offset, true);
826
+ const bufLen = view.getUint32(offset + 4, true);
827
+ return HEAPU8.subarray(buf, buf + bufLen);
828
+ }));
829
+ let nwritten;
830
+ if (fd === 1 || fd === 2) {
831
+ nwritten = fileDescriptor.write(buffer);
832
+ }
833
+ else {
834
+ nwritten = await (await (fileDescriptor.fd.write(buffer, 0, buffer.length, Number(fileDescriptor.pos)))).bytesWritten;
835
+ fileDescriptor.pos += BigInt(nwritten);
836
+ }
837
+ view.setUint32(size, nwritten, true);
838
+ return types_1.WasiErrno.ESUCCESS;
839
+ }, ['i32', 'i32', 'i32', 'i32'], ['i32']);
840
+ defineImport('path_create_directory', function path_create_directory(fd, path, path_len) {
841
+ path = Number(path);
842
+ path_len = Number(path_len);
843
+ if (path === 0) {
844
+ return types_1.WasiErrno.EINVAL;
845
+ }
846
+ const { HEAPU8 } = getMemory(this);
847
+ const wasi = _wasi.get(this);
848
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_CREATE_DIRECTORY, BigInt(0));
849
+ let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
850
+ pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
851
+ const fs = getFs(this);
852
+ fs.mkdirSync(pathString);
853
+ return types_1.WasiErrno.ESUCCESS;
854
+ }, async function path_create_directory(fd, path, path_len) {
554
855
  path = Number(path);
555
856
  path_len = Number(path_len);
556
857
  if (path === 0) {
@@ -562,10 +863,10 @@ class WASI {
562
863
  let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
563
864
  pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
564
865
  const fs = getFs(this);
565
- fs.mkdirSync(pathString);
866
+ await fs.promises.mkdir(pathString);
566
867
  return types_1.WasiErrno.ESUCCESS;
567
- });
568
- this.path_filestat_get = syscallWrap('path_filestat_get', function (fd, flags, path, path_len, filestat) {
868
+ }, ['i32', 'i32', 'i32'], ['i32']);
869
+ defineImport('path_filestat_get', function path_filestat_get(fd, flags, path, path_len, filestat) {
569
870
  path = Number(path);
570
871
  path_len = Number(path_len);
571
872
  filestat = Number(filestat);
@@ -587,8 +888,30 @@ class WASI {
587
888
  }
588
889
  (0, fd_1.toFileStat)(view, filestat, stat);
589
890
  return types_1.WasiErrno.ESUCCESS;
590
- });
591
- this.path_filestat_set_times = syscallWrap('path_filestat_set_times', function (fd, flags, path, path_len, atim, mtim, fst_flags) {
891
+ }, async function path_filestat_get(fd, flags, path, path_len, filestat) {
892
+ path = Number(path);
893
+ path_len = Number(path_len);
894
+ filestat = Number(filestat);
895
+ if (path === 0 || filestat === 0) {
896
+ return types_1.WasiErrno.EINVAL;
897
+ }
898
+ const { HEAPU8, view } = getMemory(this);
899
+ const wasi = _wasi.get(this);
900
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_GET, BigInt(0));
901
+ let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
902
+ const fs = getFs(this);
903
+ pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
904
+ let stat;
905
+ if ((flags & 1) === 1) {
906
+ stat = await fs.promises.stat(pathString, { bigint: true });
907
+ }
908
+ else {
909
+ stat = await fs.promises.lstat(pathString, { bigint: true });
910
+ }
911
+ (0, fd_1.toFileStat)(view, filestat, stat);
912
+ return types_1.WasiErrno.ESUCCESS;
913
+ }, ['i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
914
+ defineImport('path_filestat_set_times', function path_filestat_set_times(fd, flags, path, path_len, atim, mtim, fst_flags) {
592
915
  path = Number(path);
593
916
  path_len = Number(path_len);
594
917
  if (path === 0)
@@ -603,7 +926,7 @@ class WASI {
603
926
  const wasi = _wasi.get(this);
604
927
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
605
928
  const fs = getFs(this);
606
- const resolvedPath = resolvePath(fs, fileDescriptor, decoder.decode(HEAPU8.subarray(path, path + path_len)), flags);
929
+ const resolvedPath = resolvePathSync(fs, fileDescriptor, decoder.decode(HEAPU8.subarray(path, path + path_len)), flags);
607
930
  if ((fst_flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
608
931
  atim = BigInt(Date.now() * 1000000);
609
932
  }
@@ -612,8 +935,32 @@ class WASI {
612
935
  }
613
936
  fs.utimesSync(resolvedPath, Number(atim), Number(mtim));
614
937
  return types_1.WasiErrno.ESUCCESS;
615
- });
616
- this.path_link = syscallWrap('path_link', function (old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) {
938
+ }, async function path_filestat_set_times(fd, flags, path, path_len, atim, mtim, fst_flags) {
939
+ path = Number(path);
940
+ path_len = Number(path_len);
941
+ if (path === 0)
942
+ return types_1.WasiErrno.EINVAL;
943
+ if ((fst_flags) & ~(types_1.WasiFstFlag.SET_ATIM |
944
+ types_1.WasiFstFlag.SET_ATIM_NOW |
945
+ types_1.WasiFstFlag.SET_MTIM |
946
+ types_1.WasiFstFlag.SET_MTIM_NOW)) {
947
+ return types_1.WasiErrno.EINVAL;
948
+ }
949
+ const { HEAPU8 } = getMemory(this);
950
+ const wasi = _wasi.get(this);
951
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
952
+ const fs = getFs(this);
953
+ const resolvedPath = await resolvePathAsync(fs, fileDescriptor, decoder.decode(HEAPU8.subarray(path, path + path_len)), flags);
954
+ if ((fst_flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
955
+ atim = BigInt(Date.now() * 1000000);
956
+ }
957
+ if ((fst_flags & types_1.WasiFstFlag.SET_MTIM_NOW) === types_1.WasiFstFlag.SET_MTIM_NOW) {
958
+ mtim = BigInt(Date.now() * 1000000);
959
+ }
960
+ await fs.promises.utimes(resolvedPath, Number(atim), Number(mtim));
961
+ return types_1.WasiErrno.ESUCCESS;
962
+ }, ['i32', 'i32', 'i32', 'i32', 'i64', 'i64', 'i32'], ['i32']);
963
+ defineImport('path_link', function path_link(old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) {
617
964
  old_path = Number(old_path);
618
965
  old_path_len = Number(old_path_len);
619
966
  new_path = Number(new_path);
@@ -633,20 +980,36 @@ class WASI {
633
980
  }
634
981
  const { HEAPU8 } = getMemory(this);
635
982
  const fs = getFs(this);
636
- const resolvedOldPath = resolvePath(fs, oldWrap, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)), old_flags);
983
+ const resolvedOldPath = resolvePathSync(fs, oldWrap, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)), old_flags);
637
984
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
638
985
  fs.linkSync(resolvedOldPath, resolvedNewPath);
639
986
  return types_1.WasiErrno.ESUCCESS;
640
- });
641
- this.path_open = syscallWrap('path_open', function (dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
642
- path = Number(path);
643
- fd = Number(fd);
644
- if (path === 0 || fd === 0) {
987
+ }, async function path_link(old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) {
988
+ old_path = Number(old_path);
989
+ old_path_len = Number(old_path_len);
990
+ new_path = Number(new_path);
991
+ new_path_len = Number(new_path_len);
992
+ if (old_path === 0 || new_path === 0) {
645
993
  return types_1.WasiErrno.EINVAL;
646
994
  }
647
- path_len = Number(path_len);
648
- fs_rights_base = BigInt(fs_rights_base);
649
- fs_rights_base = BigInt(fs_rights_base);
995
+ const wasi = _wasi.get(this);
996
+ let oldWrap;
997
+ let newWrap;
998
+ if (old_fd === new_fd) {
999
+ oldWrap = newWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_LINK_SOURCE | types_1.WasiRights.PATH_LINK_TARGET, BigInt(0));
1000
+ }
1001
+ else {
1002
+ oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_LINK_SOURCE, BigInt(0));
1003
+ newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_LINK_TARGET, BigInt(0));
1004
+ }
1005
+ const { HEAPU8 } = getMemory(this);
1006
+ const fs = getFs(this);
1007
+ const resolvedOldPath = await resolvePathAsync(fs, oldWrap, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)), old_flags);
1008
+ const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
1009
+ await fs.promises.link(resolvedOldPath, resolvedNewPath);
1010
+ return types_1.WasiErrno.ESUCCESS;
1011
+ }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1012
+ function pathOpen(o_flags, fs_rights_base, fs_rights_inheriting, fs_flags) {
650
1013
  const read = (fs_rights_base & (types_1.WasiRights.FD_READ |
651
1014
  types_1.WasiRights.FD_READDIR)) !== BigInt(0);
652
1015
  const write = (fs_rights_base & (types_1.WasiRights.FD_DATASYNC |
@@ -691,32 +1054,78 @@ class WASI {
691
1054
  if (write && (flags & (types_1.FileControlFlag.O_APPEND | types_1.FileControlFlag.O_TRUNC)) === 0) {
692
1055
  needed_inheriting |= types_1.WasiRights.FD_SEEK;
693
1056
  }
1057
+ return { flags, needed_base, needed_inheriting };
1058
+ }
1059
+ defineImport('path_open', function path_open(dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
1060
+ path = Number(path);
1061
+ fd = Number(fd);
1062
+ if (path === 0 || fd === 0) {
1063
+ return types_1.WasiErrno.EINVAL;
1064
+ }
1065
+ path_len = Number(path_len);
1066
+ fs_rights_base = BigInt(fs_rights_base);
1067
+ fs_rights_inheriting = BigInt(fs_rights_inheriting);
1068
+ const { flags: flagsRes, needed_base: neededBase, needed_inheriting: neededInheriting } = pathOpen(o_flags, fs_rights_base, fs_rights_inheriting, fs_flags);
694
1069
  const wasi = _wasi.get(this);
695
- const fileDescriptor = wasi.fds.get(dirfd, needed_base, needed_inheriting);
1070
+ const fileDescriptor = wasi.fds.get(dirfd, neededBase, neededInheriting);
696
1071
  const memory = getMemory(this);
697
1072
  const HEAPU8 = memory.HEAPU8;
698
1073
  const pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
699
1074
  const fs = getFs(this);
700
- const resolved_path = resolvePath(fs, fileDescriptor, pathString, dirflags);
701
- const r = fs.openSync(resolved_path, flags, 0o666);
1075
+ const resolved_path = resolvePathSync(fs, fileDescriptor, pathString, dirflags);
1076
+ const r = fs.openSync(resolved_path, flagsRes, 0o666);
702
1077
  const filetype = wasi.fds.getFileTypeByFd(r);
703
1078
  if ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== types_1.WasiFileType.DIRECTORY) {
704
1079
  return types_1.WasiErrno.ENOTDIR;
705
1080
  }
706
- const { base: max_base, inheriting: max_inheriting } = (0, rights_1.getRights)(wasi.fds.stdio, r, flags, filetype);
1081
+ const { base: max_base, inheriting: max_inheriting } = (0, rights_1.getRights)(wasi.fds.stdio, r, flagsRes, filetype);
707
1082
  const wrap = wasi.fds.insert(r, resolved_path, resolved_path, filetype, fs_rights_base & max_base, fs_rights_inheriting & max_inheriting, 0);
708
1083
  const stat = fs.fstatSync(r, { bigint: true });
709
1084
  if (stat.isFile()) {
710
1085
  wrap.size = stat.size;
711
- if ((flags & types_1.FileControlFlag.O_APPEND) !== 0) {
1086
+ if ((flagsRes & types_1.FileControlFlag.O_APPEND) !== 0) {
712
1087
  wrap.pos = stat.size;
713
1088
  }
714
1089
  }
715
1090
  const view = memory.view;
716
1091
  view.setInt32(fd, wrap.id, true);
717
1092
  return types_1.WasiErrno.ESUCCESS;
718
- });
719
- this.path_readlink = syscallWrap('path_readlink', function (fd, path, path_len, buf, buf_len, bufused) {
1093
+ }, async function path_open(dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
1094
+ path = Number(path);
1095
+ fd = Number(fd);
1096
+ if (path === 0 || fd === 0) {
1097
+ return types_1.WasiErrno.EINVAL;
1098
+ }
1099
+ path_len = Number(path_len);
1100
+ fs_rights_base = BigInt(fs_rights_base);
1101
+ fs_rights_inheriting = BigInt(fs_rights_inheriting);
1102
+ const { flags: flagsRes, needed_base: neededBase, needed_inheriting: neededInheriting } = pathOpen(o_flags, fs_rights_base, fs_rights_inheriting, fs_flags);
1103
+ const wasi = _wasi.get(this);
1104
+ const fileDescriptor = wasi.fds.get(dirfd, neededBase, neededInheriting);
1105
+ const memory = getMemory(this);
1106
+ const HEAPU8 = memory.HEAPU8;
1107
+ const pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
1108
+ const fs = getFs(this);
1109
+ const resolved_path = await resolvePathAsync(fs, fileDescriptor, pathString, dirflags);
1110
+ const r = await fs.promises.open(resolved_path, flagsRes, 0o666);
1111
+ const filetype = await wasi.fds.getFileTypeByFd(r);
1112
+ if ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== types_1.WasiFileType.DIRECTORY) {
1113
+ return types_1.WasiErrno.ENOTDIR;
1114
+ }
1115
+ const { base: max_base, inheriting: max_inheriting } = (0, rights_1.getRights)(wasi.fds.stdio, r.fd, flagsRes, filetype);
1116
+ const wrap = wasi.fds.insert(r, resolved_path, resolved_path, filetype, fs_rights_base & max_base, fs_rights_inheriting & max_inheriting, 0);
1117
+ const stat = await r.stat({ bigint: true });
1118
+ if (stat.isFile()) {
1119
+ wrap.size = stat.size;
1120
+ if ((flagsRes & types_1.FileControlFlag.O_APPEND) !== 0) {
1121
+ wrap.pos = stat.size;
1122
+ }
1123
+ }
1124
+ const view = memory.view;
1125
+ view.setInt32(fd, wrap.id, true);
1126
+ return types_1.WasiErrno.ESUCCESS;
1127
+ }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i64', 'i64', 'i32', 'i32'], ['i32']);
1128
+ defineImport('path_readlink', function path_readlink(fd, path, path_len, buf, buf_len, bufused) {
720
1129
  path = Number(path);
721
1130
  path_len = Number(path_len);
722
1131
  buf = Number(buf);
@@ -740,8 +1149,32 @@ class WASI {
740
1149
  HEAPU8[buf + len] = 0;
741
1150
  view.setUint32(bufused, len + 1, true);
742
1151
  return types_1.WasiErrno.ESUCCESS;
743
- });
744
- this.path_remove_directory = syscallWrap('path_remove_directory', function (fd, path, path_len) {
1152
+ }, async function path_readlink(fd, path, path_len, buf, buf_len, bufused) {
1153
+ path = Number(path);
1154
+ path_len = Number(path_len);
1155
+ buf = Number(buf);
1156
+ buf_len = Number(buf_len);
1157
+ bufused = Number(bufused);
1158
+ if (path === 0 || buf === 0 || bufused === 0) {
1159
+ return types_1.WasiErrno.EINVAL;
1160
+ }
1161
+ const { HEAPU8, view } = getMemory(this);
1162
+ const wasi = _wasi.get(this);
1163
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_READLINK, BigInt(0));
1164
+ let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
1165
+ pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
1166
+ const fs = getFs(this);
1167
+ const link = await fs.promises.readlink(pathString);
1168
+ const linkData = encoder.encode(link);
1169
+ const len = Math.min(linkData.length, buf_len);
1170
+ if (len >= buf_len)
1171
+ return types_1.WasiErrno.ENOBUFS;
1172
+ HEAPU8.set(linkData.subarray(0, len), buf);
1173
+ HEAPU8[buf + len] = 0;
1174
+ view.setUint32(bufused, len + 1, true);
1175
+ return types_1.WasiErrno.ESUCCESS;
1176
+ }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1177
+ defineImport('path_remove_directory', function path_remove_directory(fd, path, path_len) {
745
1178
  path = Number(path);
746
1179
  path_len = Number(path_len);
747
1180
  if (path === 0) {
@@ -755,8 +1188,22 @@ class WASI {
755
1188
  const fs = getFs(this);
756
1189
  fs.rmdirSync(pathString);
757
1190
  return types_1.WasiErrno.ESUCCESS;
758
- });
759
- this.path_rename = syscallWrap('path_rename', function (old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) {
1191
+ }, async function path_remove_directory(fd, path, path_len) {
1192
+ path = Number(path);
1193
+ path_len = Number(path_len);
1194
+ if (path === 0) {
1195
+ return types_1.WasiErrno.EINVAL;
1196
+ }
1197
+ const { HEAPU8 } = getMemory(this);
1198
+ const wasi = _wasi.get(this);
1199
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_REMOVE_DIRECTORY, BigInt(0));
1200
+ let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
1201
+ pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
1202
+ const fs = getFs(this);
1203
+ await fs.promises.rmdir(pathString);
1204
+ return types_1.WasiErrno.ESUCCESS;
1205
+ }, ['i32', 'i32', 'i32'], ['i32']);
1206
+ defineImport('path_rename', function path_rename(old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) {
760
1207
  old_path = Number(old_path);
761
1208
  old_path_len = Number(old_path_len);
762
1209
  new_path = Number(new_path);
@@ -780,8 +1227,32 @@ class WASI {
780
1227
  const fs = getFs(this);
781
1228
  fs.renameSync(resolvedOldPath, resolvedNewPath);
782
1229
  return types_1.WasiErrno.ESUCCESS;
783
- });
784
- this.path_symlink = syscallWrap('path_symlink', function (old_path, old_path_len, fd, new_path, new_path_len) {
1230
+ }, async function path_rename(old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) {
1231
+ old_path = Number(old_path);
1232
+ old_path_len = Number(old_path_len);
1233
+ new_path = Number(new_path);
1234
+ new_path_len = Number(new_path_len);
1235
+ if (old_path === 0 || new_path === 0) {
1236
+ return types_1.WasiErrno.EINVAL;
1237
+ }
1238
+ const wasi = _wasi.get(this);
1239
+ let oldWrap;
1240
+ let newWrap;
1241
+ if (old_fd === new_fd) {
1242
+ oldWrap = newWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_RENAME_SOURCE | types_1.WasiRights.PATH_RENAME_TARGET, BigInt(0));
1243
+ }
1244
+ else {
1245
+ oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_RENAME_SOURCE, BigInt(0));
1246
+ newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_RENAME_TARGET, BigInt(0));
1247
+ }
1248
+ const { HEAPU8 } = getMemory(this);
1249
+ const resolvedOldPath = (0, path_1.resolve)(oldWrap.realPath, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)));
1250
+ const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
1251
+ const fs = getFs(this);
1252
+ await fs.promises.rename(resolvedOldPath, resolvedNewPath);
1253
+ return types_1.WasiErrno.ESUCCESS;
1254
+ }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1255
+ defineImport('path_symlink', function path_symlink(old_path, old_path_len, fd, new_path, new_path_len) {
785
1256
  old_path = Number(old_path);
786
1257
  old_path_len = Number(old_path_len);
787
1258
  new_path = Number(new_path);
@@ -798,8 +1269,25 @@ class WASI {
798
1269
  const fs = getFs(this);
799
1270
  fs.symlinkSync(oldPath, newPath);
800
1271
  return types_1.WasiErrno.ESUCCESS;
801
- });
802
- this.path_unlink_file = syscallWrap('path_unlink_file', function (fd, path, path_len) {
1272
+ }, async function path_symlink(old_path, old_path_len, fd, new_path, new_path_len) {
1273
+ old_path = Number(old_path);
1274
+ old_path_len = Number(old_path_len);
1275
+ new_path = Number(new_path);
1276
+ new_path_len = Number(new_path_len);
1277
+ if (old_path === 0 || new_path === 0) {
1278
+ return types_1.WasiErrno.EINVAL;
1279
+ }
1280
+ const { HEAPU8 } = getMemory(this);
1281
+ const wasi = _wasi.get(this);
1282
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_SYMLINK, BigInt(0));
1283
+ const oldPath = decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len));
1284
+ let newPath = decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len));
1285
+ newPath = (0, path_1.resolve)(fileDescriptor.realPath, newPath);
1286
+ const fs = getFs(this);
1287
+ await fs.promises.symlink(oldPath, newPath);
1288
+ return types_1.WasiErrno.ESUCCESS;
1289
+ }, ['i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1290
+ defineImport('path_unlink_file', function path_unlink_file(fd, path, path_len) {
803
1291
  path = Number(path);
804
1292
  path_len = Number(path_len);
805
1293
  if (path === 0) {
@@ -813,58 +1301,30 @@ class WASI {
813
1301
  const fs = getFs(this);
814
1302
  fs.unlinkSync(pathString);
815
1303
  return types_1.WasiErrno.ESUCCESS;
816
- });
817
- this.poll_oneoff = syscallWrap('poll_oneoff', function (_in, _out, _sub, _nevents) {
818
- return types_1.WasiErrno.ENOSYS;
819
- });
820
- this.proc_exit = syscallWrap('proc_exit', function (_rval) {
821
- return types_1.WasiErrno.ESUCCESS;
822
- });
823
- this.proc_raise = syscallWrap('proc_raise', function (_sig) {
824
- return types_1.WasiErrno.ENOSYS;
825
- });
826
- this.sched_yield = syscallWrap('sched_yield', function () {
1304
+ }, async function path_unlink_file(fd, path, path_len) {
1305
+ path = Number(path);
1306
+ path_len = Number(path_len);
1307
+ if (path === 0) {
1308
+ return types_1.WasiErrno.EINVAL;
1309
+ }
1310
+ const { HEAPU8 } = getMemory(this);
1311
+ const wasi = _wasi.get(this);
1312
+ const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_UNLINK_FILE, BigInt(0));
1313
+ let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
1314
+ pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
1315
+ const fs = getFs(this);
1316
+ await fs.promises.unlink(pathString);
827
1317
  return types_1.WasiErrno.ESUCCESS;
828
- });
829
- this.random_get = typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function'
830
- ? syscallWrap('random_get', function (buf, buf_len) {
831
- buf = Number(buf);
832
- if (buf === 0) {
833
- return types_1.WasiErrno.EINVAL;
834
- }
835
- buf_len = Number(buf_len);
836
- const { HEAPU8 } = getMemory(this);
837
- let pos;
838
- const stride = 65536;
839
- for (pos = 0; pos + stride < buf_len; pos += stride) {
840
- crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + pos + stride));
841
- }
842
- crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + buf_len));
843
- return types_1.WasiErrno.ESUCCESS;
844
- })
845
- : syscallWrap('random_get', function (buf, buf_len) {
846
- buf = Number(buf);
847
- if (buf === 0) {
848
- return types_1.WasiErrno.EINVAL;
849
- }
850
- buf_len = Number(buf_len);
851
- const { view } = getMemory(this);
852
- for (let i = buf; i < buf + buf_len; ++i) {
853
- view.setUint8(i, Math.floor(Math.random() * 256));
854
- }
855
- return types_1.WasiErrno.ESUCCESS;
856
- });
857
- this.sock_recv = syscallWrap('sock_recv', function () {
858
- return types_1.WasiErrno.ENOTSUP;
859
- });
860
- this.sock_send = syscallWrap('sock_send', function () {
861
- return types_1.WasiErrno.ENOTSUP;
862
- });
863
- this.sock_shutdown = syscallWrap('sock_shutdown', function () {
864
- return types_1.WasiErrno.ENOTSUP;
865
- });
866
- const fs = filesystem ? filesystem.fs : undefined;
867
- const fds = new fd_1.FileDescriptorTable({
1318
+ }, ['i32', 'i32', 'i32'], ['i32']);
1319
+ this._setMemory = function setMemory(m) {
1320
+ if (!(m instanceof webassembly_1._WebAssembly.Memory)) {
1321
+ throw new TypeError('"instance.exports.memory" property must be a WebAssembly.Memory');
1322
+ }
1323
+ _memory.set(_this, (0, memory_1.extendMemory)(m));
1324
+ };
1325
+ }
1326
+ static createSync(args, env, preopens, stdio, fs, print, printErr) {
1327
+ const fds = new fd_1.SyncTable({
868
1328
  size: 3,
869
1329
  in: stdio[0],
870
1330
  out: stdio[1],
@@ -873,13 +1333,7 @@ class WASI {
873
1333
  print,
874
1334
  printErr
875
1335
  });
876
- _wasi.set(this, {
877
- fds,
878
- args,
879
- env
880
- });
881
- if (fs)
882
- _fs.set(this, fs);
1336
+ const _this = new WASI(args, env, fds, false, fs);
883
1337
  if (preopens.length > 0) {
884
1338
  for (let i = 0; i < preopens.length; ++i) {
885
1339
  const realPath = fs.realpathSync(preopens[i].realPath, 'utf8');
@@ -887,6 +1341,27 @@ class WASI {
887
1341
  fds.insertPreopen(fd, preopens[i].mappedPath, realPath);
888
1342
  }
889
1343
  }
1344
+ return _this;
1345
+ }
1346
+ static async createAsync(args, env, preopens, stdio, fs, print, printErr, asyncify) {
1347
+ const fds = new fd_1.AsyncTable({
1348
+ size: 3,
1349
+ in: stdio[0],
1350
+ out: stdio[1],
1351
+ err: stdio[2],
1352
+ print,
1353
+ printErr
1354
+ });
1355
+ const _this = new WASI(args, env, fds, true, fs, asyncify);
1356
+ if (preopens.length > 0) {
1357
+ for (let i = 0; i < preopens.length; ++i) {
1358
+ const entry = preopens[i];
1359
+ const realPath = await fs.promises.realpath(entry.realPath);
1360
+ const fd = await fs.promises.open(realPath, 'r', 0o666);
1361
+ await fds.insertPreopen(fd, entry.mappedPath, realPath);
1362
+ }
1363
+ }
1364
+ return _this;
890
1365
  }
891
1366
  }
892
1367
  exports.WASI = WASI;