@tybys/wasm-util 0.3.0 → 0.5.0

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.
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WASI = void 0;
4
- // import { vol } from 'memfs-browser'
5
4
  const webassembly_1 = require("../webassembly");
6
5
  const path_1 = require("./path");
7
6
  const types_1 = require("./types");
@@ -10,6 +9,7 @@ const error_1 = require("./error");
10
9
  const util_1 = require("./util");
11
10
  const rights_1 = require("./rights");
12
11
  const memory_1 = require("../memory");
12
+ const jspi_1 = require("../jspi");
13
13
  function copyMemory(targets, src) {
14
14
  if (targets.length === 0 || src.length === 0)
15
15
  return 0;
@@ -68,7 +68,7 @@ function defineName(name, f) {
68
68
  Object.defineProperty(f, 'name', { value: name });
69
69
  return f;
70
70
  }
71
- function syscallWrap(name, f) {
71
+ function syscallWrap(self, name, f) {
72
72
  return defineName(name, function () {
73
73
  if (process.env.NODE_DEBUG_NATIVE === 'wasi') {
74
74
  const args = Array.prototype.slice.call(arguments);
@@ -78,7 +78,7 @@ function syscallWrap(name, f) {
78
78
  }
79
79
  let r;
80
80
  try {
81
- r = f.apply(this, arguments);
81
+ r = f.apply(self, arguments);
82
82
  }
83
83
  catch (err) {
84
84
  return handleError(err);
@@ -89,7 +89,7 @@ function syscallWrap(name, f) {
89
89
  return r;
90
90
  });
91
91
  }
92
- function resolvePath(fs, fileDescriptor, path, flags) {
92
+ function resolvePathSync(fs, fileDescriptor, path, flags) {
93
93
  let resolvedPath = (0, path_1.resolve)(fileDescriptor.realPath, path);
94
94
  if ((flags & 1) === 1) {
95
95
  try {
@@ -103,6 +103,20 @@ function resolvePath(fs, fileDescriptor, path, flags) {
103
103
  }
104
104
  return resolvedPath;
105
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
+ }
106
120
  const encoder = new TextEncoder();
107
121
  const decoder = new TextDecoder();
108
122
  function readStdin() {
@@ -113,14 +127,8 @@ function readStdin() {
113
127
  return buffer;
114
128
  }
115
129
  class WASI {
116
- constructor(args, env, preopens, stdio, filesystem, print, printErr) {
117
- this._setMemory = function _setMemory(m) {
118
- if (!(m instanceof webassembly_1._WebAssembly.Memory)) {
119
- throw new TypeError('"instance.exports.memory" property must be a WebAssembly.Memory');
120
- }
121
- _memory.set(this, (0, memory_1.extendMemory)(m));
122
- };
123
- 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) {
124
132
  argv = Number(argv);
125
133
  argv_buf = Number(argv_buf);
126
134
  if (argv === 0 || argv_buf === 0) {
@@ -139,7 +147,7 @@ class WASI {
139
147
  }
140
148
  return types_1.WasiErrno.ESUCCESS;
141
149
  });
142
- 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) {
143
151
  argc = Number(argc);
144
152
  argv_buf_size = Number(argv_buf_size);
145
153
  if (argc === 0 || argv_buf_size === 0) {
@@ -152,7 +160,7 @@ class WASI {
152
160
  view.setUint32(argv_buf_size, encoder.encode(args.join('\0') + '\0').length, true);
153
161
  return types_1.WasiErrno.ESUCCESS;
154
162
  });
155
- this.environ_get = syscallWrap('environ_get', function (environ, environ_buf) {
163
+ this.environ_get = syscallWrap(this, 'environ_get', function (environ, environ_buf) {
156
164
  environ = Number(environ);
157
165
  environ_buf = Number(environ_buf);
158
166
  if (environ === 0 || environ_buf === 0) {
@@ -171,7 +179,7 @@ class WASI {
171
179
  }
172
180
  return types_1.WasiErrno.ESUCCESS;
173
181
  });
174
- this.environ_sizes_get = syscallWrap('environ_sizes_get', function (len, buflen) {
182
+ this.environ_sizes_get = syscallWrap(this, 'environ_sizes_get', function (len, buflen) {
175
183
  len = Number(len);
176
184
  buflen = Number(buflen);
177
185
  if (len === 0 || buflen === 0) {
@@ -183,7 +191,7 @@ class WASI {
183
191
  view.setUint32(buflen, encoder.encode(wasi.env.join('\0') + '\0').length, true);
184
192
  return types_1.WasiErrno.ESUCCESS;
185
193
  });
186
- this.clock_res_get = syscallWrap('clock_res_get', function (id, resolution) {
194
+ this.clock_res_get = syscallWrap(this, 'clock_res_get', function (id, resolution) {
187
195
  resolution = Number(resolution);
188
196
  if (resolution === 0) {
189
197
  return types_1.WasiErrno.EINVAL;
@@ -201,7 +209,7 @@ class WASI {
201
209
  default: return types_1.WasiErrno.EINVAL;
202
210
  }
203
211
  });
204
- 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) {
205
213
  time = Number(time);
206
214
  if (time === 0) {
207
215
  return types_1.WasiErrno.EINVAL;
@@ -224,35 +232,10 @@ class WASI {
224
232
  default: return types_1.WasiErrno.EINVAL;
225
233
  }
226
234
  });
227
- this.fd_advise = syscallWrap('fd_advise', function (_fd, _offset, _len, _advice) {
235
+ this.fd_advise = syscallWrap(this, 'fd_advise', function (_fd, _offset, _len, _advice) {
228
236
  return types_1.WasiErrno.ENOSYS;
229
237
  });
230
- this.fd_allocate = syscallWrap('fd_allocate', function (fd, offset, len) {
231
- const wasi = _wasi.get(this);
232
- const fs = getFs(this);
233
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_ALLOCATE, BigInt(0));
234
- const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
235
- if (stat.size < offset + len) {
236
- fs.truncateSync(fileDescriptor.fd, Number(offset + len));
237
- }
238
- return types_1.WasiErrno.ESUCCESS;
239
- });
240
- this.fd_close = syscallWrap('fd_close', function (fd) {
241
- const wasi = _wasi.get(this);
242
- const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
243
- const fs = getFs(this);
244
- fs.closeSync(fileDescriptor.fd);
245
- wasi.fds.remove(fd);
246
- return types_1.WasiErrno.ESUCCESS;
247
- });
248
- this.fd_datasync = syscallWrap('fd_datasync', function (fd) {
249
- const wasi = _wasi.get(this);
250
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_DATASYNC, BigInt(0));
251
- const fs = getFs(this);
252
- fs.fdatasyncSync(fileDescriptor.fd);
253
- return types_1.WasiErrno.ESUCCESS;
254
- });
255
- this.fd_fdstat_get = syscallWrap('fd_fdstat_get', function (fd, fdstat) {
238
+ this.fd_fdstat_get = syscallWrap(this, 'fd_fdstat_get', function (fd, fdstat) {
256
239
  fdstat = Number(fdstat);
257
240
  if (fdstat === 0) {
258
241
  return types_1.WasiErrno.EINVAL;
@@ -266,10 +249,10 @@ class WASI {
266
249
  view.setBigUint64(fdstat + 16, fileDescriptor.rightsInheriting, true);
267
250
  return types_1.WasiErrno.ESUCCESS;
268
251
  });
269
- 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) {
270
253
  return types_1.WasiErrno.ENOSYS;
271
254
  });
272
- 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) {
273
256
  const wasi = _wasi.get(this);
274
257
  const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
275
258
  if ((rightsBase | fileDescriptor.rightsBase) > fileDescriptor.rightsBase) {
@@ -283,7 +266,186 @@ class WASI {
283
266
  fileDescriptor.rightsInheriting = rightsInheriting;
284
267
  return types_1.WasiErrno.ESUCCESS;
285
268
  });
286
- 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) {
287
449
  buf = Number(buf);
288
450
  if (buf === 0)
289
451
  return types_1.WasiErrno.EINVAL;
@@ -294,15 +456,32 @@ class WASI {
294
456
  const { view } = getMemory(this);
295
457
  (0, fd_1.toFileStat)(view, buf, stat);
296
458
  return types_1.WasiErrno.ESUCCESS;
297
- });
298
- 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) {
299
472
  const wasi = _wasi.get(this);
300
473
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_SET_SIZE, BigInt(0));
301
474
  const fs = getFs(this);
302
475
  fs.ftruncateSync(fileDescriptor.fd, Number(size));
303
476
  return types_1.WasiErrno.ESUCCESS;
304
- });
305
- 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) {
306
485
  const wasi = _wasi.get(this);
307
486
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_SET_TIMES, BigInt(0));
308
487
  if ((flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
@@ -311,11 +490,20 @@ class WASI {
311
490
  if ((flags & types_1.WasiFstFlag.SET_MTIM_NOW) === types_1.WasiFstFlag.SET_MTIM_NOW) {
312
491
  mtim = BigInt(Date.now() * 1000000);
313
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);
314
497
  const fs = getFs(this);
315
- fs.futimesSync(fileDescriptor.fd, Number(atim), Number(mtim));
498
+ fs.futimesSync(fileDescriptor.fd, Number(atimRes), Number(mtimRes));
316
499
  return types_1.WasiErrno.ESUCCESS;
317
- });
318
- 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) {
319
507
  iovs = Number(iovs);
320
508
  size = Number(size);
321
509
  if (iovs === 0 || size === 0) {
@@ -340,49 +528,51 @@ class WASI {
340
528
  nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
341
529
  view.setUint32(size, nread, true);
342
530
  return types_1.WasiErrno.ESUCCESS;
343
- });
344
- this.fd_prestat_get = syscallWrap('fd_prestat_get', function (fd, prestat) {
345
- prestat = Number(prestat);
346
- 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) {
347
535
  return types_1.WasiErrno.EINVAL;
348
536
  }
537
+ const { HEAPU8, view } = getMemory(this);
349
538
  const wasi = _wasi.get(this);
350
- let fileDescriptor;
351
- try {
352
- fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
353
- }
354
- catch (err) {
355
- if (err instanceof error_1.WasiError)
356
- return err.errno;
357
- throw err;
358
- }
359
- if (fileDescriptor.preopen !== 1)
360
- return types_1.WasiErrno.EINVAL;
361
- const { view } = getMemory(this);
362
- // preopen type is dir(0)
363
- view.setUint32(prestat, 0, true);
364
- 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);
365
554
  return types_1.WasiErrno.ESUCCESS;
366
- });
367
- this.fd_prestat_dir_name = syscallWrap('fd_prestat_dir_name', function (fd, path, path_len) {
368
- path = Number(path);
369
- path_len = Number(path_len);
370
- 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) {
371
560
  return types_1.WasiErrno.EINVAL;
372
561
  }
562
+ const { HEAPU8, view } = getMemory(this);
373
563
  const wasi = _wasi.get(this);
374
- const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
375
- if (fileDescriptor.preopen !== 1)
376
- return types_1.WasiErrno.EBADF;
377
- const buffer = encoder.encode(fileDescriptor.path + '\0');
378
- const size = buffer.length;
379
- if (size > path_len)
380
- return types_1.WasiErrno.ENOBUFS;
381
- const { HEAPU8 } = getMemory(this);
382
- 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);
383
574
  return types_1.WasiErrno.ESUCCESS;
384
- });
385
- this.fd_pwrite = syscallWrap('fd_pwrite', function (fd, iovs, iovslen, offset, size) {
575
+ }, async function fd_pwrite(fd, iovs, iovslen, offset, size) {
386
576
  iovs = Number(iovs);
387
577
  size = Number(size);
388
578
  if (iovs === 0 || size === 0) {
@@ -397,12 +587,11 @@ class WASI {
397
587
  const bufLen = view.getUint32(offset + 4, true);
398
588
  return HEAPU8.subarray(buf, buf + bufLen);
399
589
  }));
400
- const fs = getFs(this);
401
- const nwritten = fs.writeSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(offset));
402
- view.setUint32(size, nwritten, true);
590
+ const { bytesWritten } = await fileDescriptor.fd.write(buffer, 0, buffer.length, Number(offset));
591
+ view.setUint32(size, bytesWritten, true);
403
592
  return types_1.WasiErrno.ESUCCESS;
404
- });
405
- 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) {
406
595
  iovs = Number(iovs);
407
596
  size = Number(size);
408
597
  if (iovs === 0 || size === 0) {
@@ -438,22 +627,43 @@ class WASI {
438
627
  }
439
628
  view.setUint32(size, nread, true);
440
629
  return types_1.WasiErrno.ESUCCESS;
441
- });
442
- this.fd_seek = syscallWrap('fd_seek', function (fd, offset, whence, newOffset) {
443
- newOffset = Number(newOffset);
444
- 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) {
445
634
  return types_1.WasiErrno.EINVAL;
446
635
  }
447
- if (fd === 0 || fd === 1 || fd === 2)
448
- return types_1.WasiErrno.ESUCCESS;
636
+ const { HEAPU8, view } = getMemory(this);
449
637
  const wasi = _wasi.get(this);
450
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SEEK, BigInt(0));
451
- const r = fileDescriptor.seek(offset, whence);
452
- const { view } = getMemory(this);
453
- 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);
454
664
  return types_1.WasiErrno.ESUCCESS;
455
- });
456
- 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) {
457
667
  buf = Number(buf);
458
668
  buf_len = Number(buf_len);
459
669
  bufused = Number(bufused);
@@ -503,28 +713,79 @@ class WASI {
503
713
  }
504
714
  view.setUint32(bufused, bufferUsed, true);
505
715
  return types_1.WasiErrno.ESUCCESS;
506
- });
507
- 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) {
508
768
  const wasi = _wasi.get(this);
509
769
  wasi.fds.renumber(to, from);
510
770
  return types_1.WasiErrno.ESUCCESS;
511
- });
512
- 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) {
513
777
  const wasi = _wasi.get(this);
514
778
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SYNC, BigInt(0));
515
779
  const fs = getFs(this);
516
780
  fs.fsyncSync(fileDescriptor.fd);
517
781
  return types_1.WasiErrno.ESUCCESS;
518
- });
519
- this.fd_tell = syscallWrap('fd_tell', function (fd, offset) {
782
+ }, async function fd_sync(fd) {
520
783
  const wasi = _wasi.get(this);
521
- const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_TELL, BigInt(0));
522
- const pos = BigInt(fileDescriptor.pos);
523
- const { view } = getMemory(this);
524
- 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();
525
786
  return types_1.WasiErrno.ESUCCESS;
526
- });
527
- 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) {
528
789
  iovs = Number(iovs);
529
790
  size = Number(size);
530
791
  if (iovs === 0 || size === 0) {
@@ -550,8 +811,47 @@ class WASI {
550
811
  }
551
812
  view.setUint32(size, nwritten, true);
552
813
  return types_1.WasiErrno.ESUCCESS;
553
- });
554
- 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) {
555
855
  path = Number(path);
556
856
  path_len = Number(path_len);
557
857
  if (path === 0) {
@@ -563,10 +863,10 @@ class WASI {
563
863
  let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
564
864
  pathString = (0, path_1.resolve)(fileDescriptor.realPath, pathString);
565
865
  const fs = getFs(this);
566
- fs.mkdirSync(pathString);
866
+ await fs.promises.mkdir(pathString);
567
867
  return types_1.WasiErrno.ESUCCESS;
568
- });
569
- 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) {
570
870
  path = Number(path);
571
871
  path_len = Number(path_len);
572
872
  filestat = Number(filestat);
@@ -588,8 +888,30 @@ class WASI {
588
888
  }
589
889
  (0, fd_1.toFileStat)(view, filestat, stat);
590
890
  return types_1.WasiErrno.ESUCCESS;
591
- });
592
- 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) {
593
915
  path = Number(path);
594
916
  path_len = Number(path_len);
595
917
  if (path === 0)
@@ -604,7 +926,7 @@ class WASI {
604
926
  const wasi = _wasi.get(this);
605
927
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
606
928
  const fs = getFs(this);
607
- 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);
608
930
  if ((fst_flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
609
931
  atim = BigInt(Date.now() * 1000000);
610
932
  }
@@ -613,8 +935,32 @@ class WASI {
613
935
  }
614
936
  fs.utimesSync(resolvedPath, Number(atim), Number(mtim));
615
937
  return types_1.WasiErrno.ESUCCESS;
616
- });
617
- 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) {
618
964
  old_path = Number(old_path);
619
965
  old_path_len = Number(old_path_len);
620
966
  new_path = Number(new_path);
@@ -634,20 +980,36 @@ class WASI {
634
980
  }
635
981
  const { HEAPU8 } = getMemory(this);
636
982
  const fs = getFs(this);
637
- 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);
638
984
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
639
985
  fs.linkSync(resolvedOldPath, resolvedNewPath);
640
986
  return types_1.WasiErrno.ESUCCESS;
641
- });
642
- this.path_open = syscallWrap('path_open', function (dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
643
- path = Number(path);
644
- fd = Number(fd);
645
- 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) {
646
993
  return types_1.WasiErrno.EINVAL;
647
994
  }
648
- path_len = Number(path_len);
649
- fs_rights_base = BigInt(fs_rights_base);
650
- 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) {
651
1013
  const read = (fs_rights_base & (types_1.WasiRights.FD_READ |
652
1014
  types_1.WasiRights.FD_READDIR)) !== BigInt(0);
653
1015
  const write = (fs_rights_base & (types_1.WasiRights.FD_DATASYNC |
@@ -692,32 +1054,78 @@ class WASI {
692
1054
  if (write && (flags & (types_1.FileControlFlag.O_APPEND | types_1.FileControlFlag.O_TRUNC)) === 0) {
693
1055
  needed_inheriting |= types_1.WasiRights.FD_SEEK;
694
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);
695
1069
  const wasi = _wasi.get(this);
696
- const fileDescriptor = wasi.fds.get(dirfd, needed_base, needed_inheriting);
1070
+ const fileDescriptor = wasi.fds.get(dirfd, neededBase, neededInheriting);
697
1071
  const memory = getMemory(this);
698
1072
  const HEAPU8 = memory.HEAPU8;
699
1073
  const pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
700
1074
  const fs = getFs(this);
701
- const resolved_path = resolvePath(fs, fileDescriptor, pathString, dirflags);
702
- 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);
703
1077
  const filetype = wasi.fds.getFileTypeByFd(r);
704
1078
  if ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== types_1.WasiFileType.DIRECTORY) {
705
1079
  return types_1.WasiErrno.ENOTDIR;
706
1080
  }
707
- 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);
708
1082
  const wrap = wasi.fds.insert(r, resolved_path, resolved_path, filetype, fs_rights_base & max_base, fs_rights_inheriting & max_inheriting, 0);
709
1083
  const stat = fs.fstatSync(r, { bigint: true });
710
1084
  if (stat.isFile()) {
711
1085
  wrap.size = stat.size;
712
- if ((flags & types_1.FileControlFlag.O_APPEND) !== 0) {
1086
+ if ((flagsRes & types_1.FileControlFlag.O_APPEND) !== 0) {
713
1087
  wrap.pos = stat.size;
714
1088
  }
715
1089
  }
716
1090
  const view = memory.view;
717
1091
  view.setInt32(fd, wrap.id, true);
718
1092
  return types_1.WasiErrno.ESUCCESS;
719
- });
720
- 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) {
721
1129
  path = Number(path);
722
1130
  path_len = Number(path_len);
723
1131
  buf = Number(buf);
@@ -741,8 +1149,32 @@ class WASI {
741
1149
  HEAPU8[buf + len] = 0;
742
1150
  view.setUint32(bufused, len + 1, true);
743
1151
  return types_1.WasiErrno.ESUCCESS;
744
- });
745
- 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) {
746
1178
  path = Number(path);
747
1179
  path_len = Number(path_len);
748
1180
  if (path === 0) {
@@ -756,8 +1188,22 @@ class WASI {
756
1188
  const fs = getFs(this);
757
1189
  fs.rmdirSync(pathString);
758
1190
  return types_1.WasiErrno.ESUCCESS;
759
- });
760
- 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) {
761
1207
  old_path = Number(old_path);
762
1208
  old_path_len = Number(old_path_len);
763
1209
  new_path = Number(new_path);
@@ -781,8 +1227,32 @@ class WASI {
781
1227
  const fs = getFs(this);
782
1228
  fs.renameSync(resolvedOldPath, resolvedNewPath);
783
1229
  return types_1.WasiErrno.ESUCCESS;
784
- });
785
- 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) {
786
1256
  old_path = Number(old_path);
787
1257
  old_path_len = Number(old_path_len);
788
1258
  new_path = Number(new_path);
@@ -799,8 +1269,25 @@ class WASI {
799
1269
  const fs = getFs(this);
800
1270
  fs.symlinkSync(oldPath, newPath);
801
1271
  return types_1.WasiErrno.ESUCCESS;
802
- });
803
- 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) {
804
1291
  path = Number(path);
805
1292
  path_len = Number(path_len);
806
1293
  if (path === 0) {
@@ -814,58 +1301,30 @@ class WASI {
814
1301
  const fs = getFs(this);
815
1302
  fs.unlinkSync(pathString);
816
1303
  return types_1.WasiErrno.ESUCCESS;
817
- });
818
- this.poll_oneoff = syscallWrap('poll_oneoff', function (_in, _out, _sub, _nevents) {
819
- return types_1.WasiErrno.ENOSYS;
820
- });
821
- this.proc_exit = syscallWrap('proc_exit', function (_rval) {
822
- return types_1.WasiErrno.ESUCCESS;
823
- });
824
- this.proc_raise = syscallWrap('proc_raise', function (_sig) {
825
- return types_1.WasiErrno.ENOSYS;
826
- });
827
- 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);
828
1317
  return types_1.WasiErrno.ESUCCESS;
829
- });
830
- this.random_get = typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function'
831
- ? syscallWrap('random_get', function (buf, buf_len) {
832
- buf = Number(buf);
833
- if (buf === 0) {
834
- return types_1.WasiErrno.EINVAL;
835
- }
836
- buf_len = Number(buf_len);
837
- const { HEAPU8 } = getMemory(this);
838
- let pos;
839
- const stride = 65536;
840
- for (pos = 0; pos + stride < buf_len; pos += stride) {
841
- crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + pos + stride));
842
- }
843
- crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + buf_len));
844
- return types_1.WasiErrno.ESUCCESS;
845
- })
846
- : syscallWrap('random_get', function (buf, buf_len) {
847
- buf = Number(buf);
848
- if (buf === 0) {
849
- return types_1.WasiErrno.EINVAL;
850
- }
851
- buf_len = Number(buf_len);
852
- const { view } = getMemory(this);
853
- for (let i = buf; i < buf + buf_len; ++i) {
854
- view.setUint8(i, Math.floor(Math.random() * 256));
855
- }
856
- return types_1.WasiErrno.ESUCCESS;
857
- });
858
- this.sock_recv = syscallWrap('sock_recv', function () {
859
- return types_1.WasiErrno.ENOTSUP;
860
- });
861
- this.sock_send = syscallWrap('sock_send', function () {
862
- return types_1.WasiErrno.ENOTSUP;
863
- });
864
- this.sock_shutdown = syscallWrap('sock_shutdown', function () {
865
- return types_1.WasiErrno.ENOTSUP;
866
- });
867
- const fs = filesystem ? filesystem.fs : undefined;
868
- 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({
869
1328
  size: 3,
870
1329
  in: stdio[0],
871
1330
  out: stdio[1],
@@ -874,13 +1333,7 @@ class WASI {
874
1333
  print,
875
1334
  printErr
876
1335
  });
877
- _wasi.set(this, {
878
- fds,
879
- args,
880
- env
881
- });
882
- if (fs)
883
- _fs.set(this, fs);
1336
+ const _this = new WASI(args, env, fds, false, fs);
884
1337
  if (preopens.length > 0) {
885
1338
  for (let i = 0; i < preopens.length; ++i) {
886
1339
  const realPath = fs.realpathSync(preopens[i].realPath, 'utf8');
@@ -888,6 +1341,27 @@ class WASI {
888
1341
  fds.insertPreopen(fd, preopens[i].mappedPath, realPath);
889
1342
  }
890
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;
891
1365
  }
892
1366
  }
893
1367
  exports.WASI = WASI;