@tybys/wasm-util 0.10.1 → 0.10.3

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,8 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WASI = void 0;
3
+ exports.WASI = exports.ensureMemoryFor = void 0;
4
4
  const webassembly_1 = require("../webassembly");
5
5
  const path_1 = require("./path");
6
+ // Linux fcntl flag bits ↔ Windows libuv flag bits. `pathOpen()` builds
7
+ // `flagsRes` using Linux constants (O_CREAT=0x40, O_EXCL=0x80,
8
+ // O_APPEND=0x400). Windows libuv expects different bits (O_CREAT=0x100,
9
+ // O_EXCL=0x400, O_APPEND=0x8). Without translation,
10
+ // `fs.openSync(path, 0x241 /* L:WRONLY|CREAT|TRUNC */)` is rejected
11
+ // with EINVAL because Linux's 0x40 happens to mean O_TEMPORARY on
12
+ // Windows — and O_TEMPORARY without O_CREAT is invalid.
13
+ const _isWin32Flags = typeof process !== 'undefined' && process.platform === 'win32';
14
+ function _toWinOpenFlags(f) {
15
+ let r = f & 3; // RDONLY/WRONLY/RDWR — same on both
16
+ if ((f & 0x40) !== 0)
17
+ r |= 0x100; // O_CREAT: Linux 0x40 -> Windows 0x100
18
+ if ((f & 0x80) !== 0)
19
+ r |= 0x400; // O_EXCL: Linux 0x80 -> Windows 0x400
20
+ if ((f & 0x200) !== 0)
21
+ r |= 0x200; // O_TRUNC: same value on both
22
+ if ((f & 0x400) !== 0)
23
+ r |= 0x8; // O_APPEND: Linux 0x400 -> Windows 0x8
24
+ return r;
25
+ }
6
26
  const types_1 = require("./types");
7
27
  const fd_1 = require("./fd");
8
28
  const error_1 = require("./error");
@@ -32,8 +52,19 @@ function copyMemory(targets, src) {
32
52
  const _memory = new WeakMap();
33
53
  const _wasi = new WeakMap();
34
54
  const _fs = new WeakMap();
35
- function getMemory(wasi) {
36
- return _memory.get(wasi);
55
+ function ensureMemoryFor(memory, end) {
56
+ let buffer = memory.buffer;
57
+ if (end > buffer.byteLength) {
58
+ memory.grow(0);
59
+ buffer = memory.buffer;
60
+ }
61
+ return buffer;
62
+ }
63
+ exports.ensureMemoryFor = ensureMemoryFor;
64
+ function getMemory(wasi, end = 0) {
65
+ const memory = _memory.get(wasi);
66
+ ensureMemoryFor(memory, end);
67
+ return memory;
37
68
  }
38
69
  function getFs(wasi) {
39
70
  const fs = _fs.get(wasi);
@@ -162,9 +193,10 @@ class WASI {
162
193
  if (argv === 0 || argv_buf === 0) {
163
194
  return types_1.WasiErrno.EINVAL;
164
195
  }
165
- const { HEAPU8, view } = getMemory(this);
166
196
  const wasi = _wasi.get(this);
167
197
  const args = wasi.args;
198
+ const argsSize = encoder.encode(args.join('\0') + '\0').length;
199
+ const { HEAPU8, view } = getMemory(this, Math.max(argv + args.length * 4, argv_buf + argsSize));
168
200
  for (let i = 0; i < args.length; ++i) {
169
201
  const arg = args[i];
170
202
  view.setInt32(argv, argv_buf, true);
@@ -181,7 +213,7 @@ class WASI {
181
213
  if (argc === 0 || argv_buf_size === 0) {
182
214
  return types_1.WasiErrno.EINVAL;
183
215
  }
184
- const { view } = getMemory(this);
216
+ const { view } = getMemory(this, Math.max(argc + 4, argv_buf_size + 4));
185
217
  const wasi = _wasi.get(this);
186
218
  const args = wasi.args;
187
219
  view.setUint32(argc, args.length, true);
@@ -194,9 +226,10 @@ class WASI {
194
226
  if (environ === 0 || environ_buf === 0) {
195
227
  return types_1.WasiErrno.EINVAL;
196
228
  }
197
- const { HEAPU8, view } = getMemory(this);
198
229
  const wasi = _wasi.get(this);
199
230
  const env = wasi.env;
231
+ const envSize = encoder.encode(env.join('\0') + '\0').length;
232
+ const { HEAPU8, view } = getMemory(this, Math.max(environ + env.length * 4, environ_buf + envSize));
200
233
  for (let i = 0; i < env.length; ++i) {
201
234
  const pair = env[i];
202
235
  view.setInt32(environ, environ_buf, true);
@@ -213,7 +246,7 @@ class WASI {
213
246
  if (len === 0 || buflen === 0) {
214
247
  return types_1.WasiErrno.EINVAL;
215
248
  }
216
- const { view } = getMemory(this);
249
+ const { view } = getMemory(this, Math.max(len + 4, buflen + 4));
217
250
  const wasi = _wasi.get(this);
218
251
  view.setUint32(len, wasi.env.length, true);
219
252
  view.setUint32(buflen, encoder.encode(wasi.env.join('\0') + '\0').length, true);
@@ -224,7 +257,7 @@ class WASI {
224
257
  if (resolution === 0) {
225
258
  return types_1.WasiErrno.EINVAL;
226
259
  }
227
- const { view } = getMemory(this);
260
+ const { view } = getMemory(this, resolution + 8);
228
261
  switch (id) {
229
262
  case types_1.WasiClockid.REALTIME:
230
263
  view.setBigUint64(resolution, BigInt(1000000), true);
@@ -242,7 +275,7 @@ class WASI {
242
275
  if (time === 0) {
243
276
  return types_1.WasiErrno.EINVAL;
244
277
  }
245
- const { view } = getMemory(this);
278
+ const { view } = getMemory(this, time + 8);
246
279
  switch (id) {
247
280
  case types_1.WasiClockid.REALTIME:
248
281
  view.setBigUint64(time, BigInt(Date.now()) * BigInt(1000000), true);
@@ -270,7 +303,7 @@ class WASI {
270
303
  }
271
304
  const wasi = _wasi.get(this);
272
305
  const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
273
- const { view } = getMemory(this);
306
+ const { view } = getMemory(this, fdstat + 24);
274
307
  view.setUint16(fdstat, fileDescriptor.type, true);
275
308
  view.setUint16(fdstat + 2, 0, true);
276
309
  view.setBigUint64(fdstat + 8, fileDescriptor.rightsBase, true);
@@ -311,7 +344,7 @@ class WASI {
311
344
  }
312
345
  if (fileDescriptor.preopen !== 1)
313
346
  return types_1.WasiErrno.EINVAL;
314
- const { view } = getMemory(this);
347
+ const { view } = getMemory(this, prestat + 8);
315
348
  // preopen type is dir(0)
316
349
  view.setUint32(prestat, 0, true);
317
350
  view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length, true);
@@ -331,7 +364,7 @@ class WASI {
331
364
  const size = buffer.length;
332
365
  if (size > path_len)
333
366
  return types_1.WasiErrno.ENOBUFS;
334
- const { HEAPU8 } = getMemory(this);
367
+ const { HEAPU8 } = getMemory(this, path + size);
335
368
  HEAPU8.set(buffer, path);
336
369
  return types_1.WasiErrno.ESUCCESS;
337
370
  });
@@ -345,7 +378,7 @@ class WASI {
345
378
  const wasi = _wasi.get(this);
346
379
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_SEEK, BigInt(0));
347
380
  const r = fileDescriptor.seek(offset, whence);
348
- const { view } = getMemory(this);
381
+ const { view } = getMemory(this, newOffset + 8);
349
382
  view.setBigUint64(newOffset, r, true);
350
383
  return types_1.WasiErrno.ESUCCESS;
351
384
  });
@@ -353,7 +386,7 @@ class WASI {
353
386
  const wasi = _wasi.get(this);
354
387
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_TELL, BigInt(0));
355
388
  const pos = BigInt(fileDescriptor.pos);
356
- const { view } = getMemory(this);
389
+ const { view } = getMemory(this, Number(offset) + 8);
357
390
  view.setBigUint64(Number(offset), pos, true);
358
391
  return types_1.WasiErrno.ESUCCESS;
359
392
  });
@@ -366,7 +399,7 @@ class WASI {
366
399
  if (in_ptr === 0 || out_ptr === 0 || nsubscriptions === 0 || nevents === 0) {
367
400
  return types_1.WasiErrno.EINVAL;
368
401
  }
369
- const { view } = getMemory(this);
402
+ const { view } = getMemory(this, Math.max(in_ptr + nsubscriptions * 48, out_ptr + nsubscriptions * 32, nevents + 4));
370
403
  view.setUint32(nevents, 0, true);
371
404
  let i = 0;
372
405
  let timer_userdata = BigInt(0);
@@ -485,7 +518,7 @@ class WASI {
485
518
  return types_1.WasiErrno.EINVAL;
486
519
  }
487
520
  buf_len = Number(buf_len);
488
- const { HEAPU8, view } = getMemory(this);
521
+ const { HEAPU8, view } = getMemory(this, buf + buf_len);
489
522
  if ((typeof SharedArrayBuffer === 'function' && HEAPU8.buffer instanceof SharedArrayBuffer) ||
490
523
  (Object.prototype.toString.call(HEAPU8.buffer) === '[object SharedArrayBuffer]')) {
491
524
  for (let i = buf; i < buf + buf_len; ++i) {
@@ -507,7 +540,7 @@ class WASI {
507
540
  return types_1.WasiErrno.EINVAL;
508
541
  }
509
542
  buf_len = Number(buf_len);
510
- const { view } = getMemory(this);
543
+ const { view } = getMemory(this, buf + buf_len);
511
544
  for (let i = buf; i < buf + buf_len; ++i) {
512
545
  view.setUint8(i, Math.floor(Math.random() * 256));
513
546
  }
@@ -600,7 +633,7 @@ class WASI {
600
633
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_GET, BigInt(0));
601
634
  const fs = getFs(this);
602
635
  const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
603
- const { view } = getMemory(this);
636
+ const { view } = getMemory(this, buf + 64);
604
637
  (0, fd_1.toFileStat)(view, buf, stat);
605
638
  return types_1.WasiErrno.ESUCCESS;
606
639
  }, async function fd_filestat_get(fd, buf) {
@@ -611,7 +644,7 @@ class WASI {
611
644
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_FILESTAT_GET, BigInt(0));
612
645
  const h = fileDescriptor.fd;
613
646
  const stat = await h.stat({ bigint: true });
614
- const { view } = getMemory(this);
647
+ const { view } = getMemory(this, buf + 64);
615
648
  (0, fd_1.toFileStat)(view, buf, stat);
616
649
  return types_1.WasiErrno.ESUCCESS;
617
650
  }, ['i32', 'i32'], ['i32']);
@@ -662,7 +695,7 @@ class WASI {
662
695
  if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
663
696
  return types_1.WasiErrno.EINVAL;
664
697
  }
665
- const { HEAPU8, view } = getMemory(this);
698
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
666
699
  const wasi = _wasi.get(this);
667
700
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ | types_1.WasiRights.FD_SEEK, BigInt(0));
668
701
  if (!iovslen) {
@@ -698,7 +731,7 @@ class WASI {
698
731
  if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
699
732
  return types_1.WasiErrno.EINVAL;
700
733
  }
701
- const { HEAPU8, view } = getMemory(this);
734
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
702
735
  const wasi = _wasi.get(this);
703
736
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ | types_1.WasiRights.FD_SEEK, BigInt(0));
704
737
  if (!iovslen) {
@@ -727,7 +760,7 @@ class WASI {
727
760
  if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
728
761
  return types_1.WasiErrno.EINVAL;
729
762
  }
730
- const { HEAPU8, view } = getMemory(this);
763
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
731
764
  const wasi = _wasi.get(this);
732
765
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE | types_1.WasiRights.FD_SEEK, BigInt(0));
733
766
  if (!iovslen) {
@@ -750,7 +783,7 @@ class WASI {
750
783
  if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
751
784
  return types_1.WasiErrno.EINVAL;
752
785
  }
753
- const { HEAPU8, view } = getMemory(this);
786
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
754
787
  const wasi = _wasi.get(this);
755
788
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE | types_1.WasiRights.FD_SEEK, BigInt(0));
756
789
  if (!iovslen) {
@@ -773,7 +806,7 @@ class WASI {
773
806
  if ((iovs === 0 && iovslen) || size === 0) {
774
807
  return types_1.WasiErrno.EINVAL;
775
808
  }
776
- const { HEAPU8, view } = getMemory(this);
809
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
777
810
  const wasi = _wasi.get(this);
778
811
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ, BigInt(0));
779
812
  if (!iovslen) {
@@ -820,7 +853,7 @@ class WASI {
820
853
  if ((iovs === 0 && iovslen) || size === 0) {
821
854
  return types_1.WasiErrno.EINVAL;
822
855
  }
823
- const { HEAPU8, view } = getMemory(this);
856
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
824
857
  const wasi = _wasi.get(this);
825
858
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ, BigInt(0));
826
859
  if (!iovslen) {
@@ -864,7 +897,7 @@ class WASI {
864
897
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READDIR, BigInt(0));
865
898
  const fs = getFs(this);
866
899
  const entries = fs.readdirSync(fileDescriptor.realPath, { withFileTypes: true });
867
- const { HEAPU8, view } = getMemory(this);
900
+ const { HEAPU8, view } = getMemory(this, Math.max(buf + buf_len, bufused + 4));
868
901
  let bufferUsed = 0;
869
902
  for (let i = Number(cookie); i < entries.length; i++) {
870
903
  const nameData = encoder.encode(entries[i].name);
@@ -914,7 +947,7 @@ class WASI {
914
947
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READDIR, BigInt(0));
915
948
  const fs = getFs(this);
916
949
  const entries = await fs.promises.readdir(fileDescriptor.realPath, { withFileTypes: true });
917
- const { HEAPU8, view } = getMemory(this);
950
+ const { HEAPU8, view } = getMemory(this, Math.max(buf + buf_len, bufused + 4));
918
951
  let bufferUsed = 0;
919
952
  for (let i = Number(cookie); i < entries.length; i++) {
920
953
  const nameData = encoder.encode(entries[i].name);
@@ -982,7 +1015,7 @@ class WASI {
982
1015
  if ((iovs === 0 && iovslen) || size === 0) {
983
1016
  return types_1.WasiErrno.EINVAL;
984
1017
  }
985
- const { HEAPU8, view } = getMemory(this);
1018
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
986
1019
  const wasi = _wasi.get(this);
987
1020
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE, BigInt(0));
988
1021
  if (!iovslen) {
@@ -1012,7 +1045,7 @@ class WASI {
1012
1045
  if ((iovs === 0 && iovslen) || size === 0) {
1013
1046
  return types_1.WasiErrno.EINVAL;
1014
1047
  }
1015
- const { HEAPU8, view } = getMemory(this);
1048
+ const { HEAPU8, view } = getMemory(this, Math.max(iovs + Number(iovslen) * 8, size + 4));
1016
1049
  const wasi = _wasi.get(this);
1017
1050
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE, BigInt(0));
1018
1051
  if (!iovslen) {
@@ -1042,7 +1075,7 @@ class WASI {
1042
1075
  if (path === 0) {
1043
1076
  return types_1.WasiErrno.EINVAL;
1044
1077
  }
1045
- const { HEAPU8 } = getMemory(this);
1078
+ const { HEAPU8 } = getMemory(this, path + path_len);
1046
1079
  const wasi = _wasi.get(this);
1047
1080
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_CREATE_DIRECTORY, BigInt(0));
1048
1081
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1056,7 +1089,7 @@ class WASI {
1056
1089
  if (path === 0) {
1057
1090
  return types_1.WasiErrno.EINVAL;
1058
1091
  }
1059
- const { HEAPU8 } = getMemory(this);
1092
+ const { HEAPU8 } = getMemory(this, path + path_len);
1060
1093
  const wasi = _wasi.get(this);
1061
1094
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_CREATE_DIRECTORY, BigInt(0));
1062
1095
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1072,7 +1105,7 @@ class WASI {
1072
1105
  if (path === 0 || filestat === 0) {
1073
1106
  return types_1.WasiErrno.EINVAL;
1074
1107
  }
1075
- const { HEAPU8, view } = getMemory(this);
1108
+ const { HEAPU8, view } = getMemory(this, Math.max(path + path_len, filestat + 64));
1076
1109
  const wasi = _wasi.get(this);
1077
1110
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_GET, BigInt(0));
1078
1111
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1094,7 +1127,7 @@ class WASI {
1094
1127
  if (path === 0 || filestat === 0) {
1095
1128
  return types_1.WasiErrno.EINVAL;
1096
1129
  }
1097
- const { HEAPU8, view } = getMemory(this);
1130
+ const { HEAPU8, view } = getMemory(this, Math.max(path + path_len, filestat + 64));
1098
1131
  const wasi = _wasi.get(this);
1099
1132
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_GET, BigInt(0));
1100
1133
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1115,7 +1148,7 @@ class WASI {
1115
1148
  path_len = Number(path_len);
1116
1149
  if (path === 0)
1117
1150
  return types_1.WasiErrno.EINVAL;
1118
- const { HEAPU8 } = getMemory(this);
1151
+ const { HEAPU8 } = getMemory(this, path + path_len);
1119
1152
  const wasi = _wasi.get(this);
1120
1153
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1121
1154
  if (validateFstFlagsOrReturn(fst_flags)) {
@@ -1136,7 +1169,7 @@ class WASI {
1136
1169
  path_len = Number(path_len);
1137
1170
  if (path === 0)
1138
1171
  return types_1.WasiErrno.EINVAL;
1139
- const { HEAPU8 } = getMemory(this);
1172
+ const { HEAPU8 } = getMemory(this, path + path_len);
1140
1173
  const wasi = _wasi.get(this);
1141
1174
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1142
1175
  if (validateFstFlagsOrReturn(fst_flags)) {
@@ -1171,7 +1204,7 @@ class WASI {
1171
1204
  oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_LINK_SOURCE, BigInt(0));
1172
1205
  newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_LINK_TARGET, BigInt(0));
1173
1206
  }
1174
- const { HEAPU8 } = getMemory(this);
1207
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1175
1208
  const fs = getFs(this);
1176
1209
  const resolvedOldPath = resolvePathSync(fs, oldWrap, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len)), old_flags);
1177
1210
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, new_path, new_path + new_path_len)));
@@ -1195,7 +1228,7 @@ class WASI {
1195
1228
  oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_LINK_SOURCE, BigInt(0));
1196
1229
  newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_LINK_TARGET, BigInt(0));
1197
1230
  }
1198
- const { HEAPU8 } = getMemory(this);
1231
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1199
1232
  const fs = getFs(this);
1200
1233
  const resolvedOldPath = await resolvePathAsync(fs, oldWrap, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len)), old_flags);
1201
1234
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, new_path, new_path + new_path_len)));
@@ -1261,12 +1294,12 @@ class WASI {
1261
1294
  const { flags: flagsRes, needed_base: neededBase, needed_inheriting: neededInheriting } = pathOpen(o_flags, fs_rights_base, fs_rights_inheriting, fs_flags);
1262
1295
  const wasi = _wasi.get(this);
1263
1296
  const fileDescriptor = wasi.fds.get(dirfd, neededBase, neededInheriting);
1264
- const memory = getMemory(this);
1297
+ const memory = getMemory(this, Math.max(path + path_len, fd + 4));
1265
1298
  const HEAPU8 = memory.HEAPU8;
1266
1299
  const pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
1267
1300
  const fs = getFs(this);
1268
1301
  const resolved_path = resolvePathSync(fs, fileDescriptor, pathString, dirflags);
1269
- const r = fs.openSync(resolved_path, flagsRes, 0o666);
1302
+ const r = fs.openSync(resolved_path, _isWin32Flags ? _toWinOpenFlags(flagsRes) : flagsRes, 0o666);
1270
1303
  const filetype = wasi.fds.getFileTypeByFd(r);
1271
1304
  if ((filetype !== types_1.WasiFileType.DIRECTORY) &&
1272
1305
  ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 ||
@@ -1297,12 +1330,12 @@ class WASI {
1297
1330
  const { flags: flagsRes, needed_base: neededBase, needed_inheriting: neededInheriting } = pathOpen(o_flags, fs_rights_base, fs_rights_inheriting, fs_flags);
1298
1331
  const wasi = _wasi.get(this);
1299
1332
  const fileDescriptor = wasi.fds.get(dirfd, neededBase, neededInheriting);
1300
- const memory = getMemory(this);
1333
+ const memory = getMemory(this, Math.max(path + path_len, fd + 4));
1301
1334
  const HEAPU8 = memory.HEAPU8;
1302
1335
  const pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
1303
1336
  const fs = getFs(this);
1304
1337
  const resolved_path = await resolvePathAsync(fs, fileDescriptor, pathString, dirflags);
1305
- const r = await fs.promises.open(resolved_path, flagsRes, 0o666);
1338
+ const r = await fs.promises.open(resolved_path, _isWin32Flags ? _toWinOpenFlags(flagsRes) : flagsRes, 0o666);
1306
1339
  const filetype = await wasi.fds.getFileTypeByFd(r);
1307
1340
  if ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== types_1.WasiFileType.DIRECTORY) {
1308
1341
  return types_1.WasiErrno.ENOTDIR;
@@ -1329,7 +1362,7 @@ class WASI {
1329
1362
  if (path === 0 || buf === 0 || bufused === 0) {
1330
1363
  return types_1.WasiErrno.EINVAL;
1331
1364
  }
1332
- const { HEAPU8, view } = getMemory(this);
1365
+ const { HEAPU8, view } = getMemory(this, Math.max(path + path_len, buf + buf_len, bufused + 4));
1333
1366
  const wasi = _wasi.get(this);
1334
1367
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_READLINK, BigInt(0));
1335
1368
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1353,7 +1386,7 @@ class WASI {
1353
1386
  if (path === 0 || buf === 0 || bufused === 0) {
1354
1387
  return types_1.WasiErrno.EINVAL;
1355
1388
  }
1356
- const { HEAPU8, view } = getMemory(this);
1389
+ const { HEAPU8, view } = getMemory(this, Math.max(path + path_len, buf + buf_len, bufused + 4));
1357
1390
  const wasi = _wasi.get(this);
1358
1391
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_READLINK, BigInt(0));
1359
1392
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1375,7 +1408,7 @@ class WASI {
1375
1408
  if (path === 0) {
1376
1409
  return types_1.WasiErrno.EINVAL;
1377
1410
  }
1378
- const { HEAPU8 } = getMemory(this);
1411
+ const { HEAPU8 } = getMemory(this, path + path_len);
1379
1412
  const wasi = _wasi.get(this);
1380
1413
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_REMOVE_DIRECTORY, BigInt(0));
1381
1414
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1389,7 +1422,7 @@ class WASI {
1389
1422
  if (path === 0) {
1390
1423
  return types_1.WasiErrno.EINVAL;
1391
1424
  }
1392
- const { HEAPU8 } = getMemory(this);
1425
+ const { HEAPU8 } = getMemory(this, path + path_len);
1393
1426
  const wasi = _wasi.get(this);
1394
1427
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_REMOVE_DIRECTORY, BigInt(0));
1395
1428
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1416,7 +1449,7 @@ class WASI {
1416
1449
  oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_RENAME_SOURCE, BigInt(0));
1417
1450
  newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_RENAME_TARGET, BigInt(0));
1418
1451
  }
1419
- const { HEAPU8 } = getMemory(this);
1452
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1420
1453
  const resolvedOldPath = (0, path_1.resolve)(oldWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len)));
1421
1454
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, new_path, new_path + new_path_len)));
1422
1455
  const fs = getFs(this);
@@ -1440,7 +1473,7 @@ class WASI {
1440
1473
  oldWrap = wasi.fds.get(old_fd, types_1.WasiRights.PATH_RENAME_SOURCE, BigInt(0));
1441
1474
  newWrap = wasi.fds.get(new_fd, types_1.WasiRights.PATH_RENAME_TARGET, BigInt(0));
1442
1475
  }
1443
- const { HEAPU8 } = getMemory(this);
1476
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1444
1477
  const resolvedOldPath = (0, path_1.resolve)(oldWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len)));
1445
1478
  const resolvedNewPath = (0, path_1.resolve)(newWrap.realPath, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, new_path, new_path + new_path_len)));
1446
1479
  const fs = getFs(this);
@@ -1455,7 +1488,7 @@ class WASI {
1455
1488
  if (old_path === 0 || new_path === 0) {
1456
1489
  return types_1.WasiErrno.EINVAL;
1457
1490
  }
1458
- const { HEAPU8 } = getMemory(this);
1491
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1459
1492
  const wasi = _wasi.get(this);
1460
1493
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_SYMLINK, BigInt(0));
1461
1494
  const oldPath = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len));
@@ -1475,7 +1508,7 @@ class WASI {
1475
1508
  if (old_path === 0 || new_path === 0) {
1476
1509
  return types_1.WasiErrno.EINVAL;
1477
1510
  }
1478
- const { HEAPU8 } = getMemory(this);
1511
+ const { HEAPU8 } = getMemory(this, Math.max(old_path + old_path_len, new_path + new_path_len));
1479
1512
  const wasi = _wasi.get(this);
1480
1513
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_SYMLINK, BigInt(0));
1481
1514
  const oldPath = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len));
@@ -1491,7 +1524,7 @@ class WASI {
1491
1524
  if (path === 0) {
1492
1525
  return types_1.WasiErrno.EINVAL;
1493
1526
  }
1494
- const { HEAPU8 } = getMemory(this);
1527
+ const { HEAPU8 } = getMemory(this, path + path_len);
1495
1528
  const wasi = _wasi.get(this);
1496
1529
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_UNLINK_FILE, BigInt(0));
1497
1530
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1505,7 +1538,7 @@ class WASI {
1505
1538
  if (path === 0) {
1506
1539
  return types_1.WasiErrno.EINVAL;
1507
1540
  }
1508
- const { HEAPU8 } = getMemory(this);
1541
+ const { HEAPU8 } = getMemory(this, path + path_len);
1509
1542
  const wasi = _wasi.get(this);
1510
1543
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_UNLINK_FILE, BigInt(0));
1511
1544
  let pathString = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len));
@@ -1,6 +1,141 @@
1
1
  import { validateString } from "./util.mjs";
2
2
  const CHAR_DOT = 46; /* . */
3
3
  const CHAR_FORWARD_SLASH = 47; /* / */
4
+ const CHAR_BACKWARD_SLASH = 92; /* \ */
5
+ const CHAR_COLON = 58; /* : */
6
+ const CHAR_UPPERCASE_A = 65; /* A */
7
+ const CHAR_UPPERCASE_Z = 90; /* Z */
8
+ const CHAR_LOWERCASE_A = 97; /* a */
9
+ const CHAR_LOWERCASE_Z = 122; /* z */
10
+ function isPathSeparatorWin(code) {
11
+ return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
12
+ }
13
+ function isWindowsDeviceRoot(code) {
14
+ return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
15
+ (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);
16
+ }
17
+ const _isWin32 = typeof process !== 'undefined' && process.platform === 'win32';
18
+ /**
19
+ * Windows variant of `resolve()`. Mirrors Node's `path.win32.resolve`
20
+ * semantics enough for the WASI shim's needs (drive-letter absolutes
21
+ * + UNC paths + per-drive cwd lookups via `process.env`/`process.cwd`).
22
+ *
23
+ * Why this is needed: on Windows, `FileDescriptor.realPath` is the
24
+ * host realpath returned by `fs.realpathSync(realPath, 'utf8')` — the
25
+ * backslash form `D:\…`. The POSIX-only `resolveImpl` below only
26
+ * treats `/` as a separator, reads `D` as non-`/`, decides realPath
27
+ * is "relative", and produces a garbage joined path. Downstream
28
+ * `fs.openSync(garbage)` then returns `EINVAL` and the WASI caller
29
+ * sees a permanent failure. This function gives us the correct
30
+ * Windows-style resolution without taking a Node-only `path` import
31
+ * (which would break browser bundles of this package).
32
+ *
33
+ * Cribbed from Node's `lib/path.js` `win32.resolve()` (MIT-licensed),
34
+ * trimmed to what WASI realpath resolution actually exercises.
35
+ */
36
+ function resolveWin32(args) {
37
+ let resolvedDevice = '';
38
+ let resolvedTail = '';
39
+ let resolvedAbsolute = false;
40
+ for (let i = args.length - 1; i >= -1; i--) {
41
+ let path;
42
+ if (i >= 0) {
43
+ path = args[i];
44
+ validateString(path, 'path');
45
+ if (path.length === 0)
46
+ continue;
47
+ }
48
+ else if (resolvedDevice.length === 0) {
49
+ path = (typeof process !== 'undefined' && typeof process.cwd === 'function')
50
+ ? process.cwd()
51
+ : '';
52
+ }
53
+ else {
54
+ // Look up per-drive cwd via the `=X:` env var convention; fall back
55
+ // to the global cwd if absent.
56
+ const envKey = `=${resolvedDevice}`;
57
+ const env = (typeof process !== 'undefined') ? process.env : undefined;
58
+ path = (env && typeof env[envKey] === 'string')
59
+ ? env[envKey]
60
+ : (typeof process !== 'undefined' && typeof process.cwd === 'function')
61
+ ? process.cwd()
62
+ : '';
63
+ if (path === undefined ||
64
+ (path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() &&
65
+ path.charCodeAt(2) === CHAR_BACKWARD_SLASH)) {
66
+ path = `${resolvedDevice}\\`;
67
+ }
68
+ }
69
+ const len = path.length;
70
+ let rootEnd = 0;
71
+ let device = '';
72
+ let isAbsolute = false;
73
+ const code = path.charCodeAt(0);
74
+ if (len === 1) {
75
+ if (isPathSeparatorWin(code)) {
76
+ rootEnd = 1;
77
+ isAbsolute = true;
78
+ }
79
+ }
80
+ else if (isPathSeparatorWin(code)) {
81
+ isAbsolute = true;
82
+ if (isPathSeparatorWin(path.charCodeAt(1))) {
83
+ // UNC path: `\\server\share\…`
84
+ let j = 2;
85
+ let last = j;
86
+ while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
87
+ j++;
88
+ if (j < len && j !== last) {
89
+ const firstPart = path.slice(last, j);
90
+ last = j;
91
+ while (j < len && isPathSeparatorWin(path.charCodeAt(j)))
92
+ j++;
93
+ if (j < len && j !== last) {
94
+ last = j;
95
+ while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
96
+ j++;
97
+ if (j === len || j !== last) {
98
+ device = `\\\\${firstPart}\\${path.slice(last, j)}`;
99
+ rootEnd = j;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ rootEnd = 1;
106
+ }
107
+ }
108
+ else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
109
+ device = path.slice(0, 2);
110
+ rootEnd = 2;
111
+ if (len > 2 && isPathSeparatorWin(path.charCodeAt(2))) {
112
+ isAbsolute = true;
113
+ rootEnd = 3;
114
+ }
115
+ }
116
+ if (device.length > 0) {
117
+ if (resolvedDevice.length > 0) {
118
+ if (device.toLowerCase() !== resolvedDevice.toLowerCase())
119
+ continue;
120
+ }
121
+ else {
122
+ resolvedDevice = device;
123
+ }
124
+ }
125
+ if (resolvedAbsolute) {
126
+ if (resolvedDevice.length > 0)
127
+ break;
128
+ }
129
+ else {
130
+ resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
131
+ resolvedAbsolute = isAbsolute;
132
+ if (isAbsolute && resolvedDevice.length > 0)
133
+ break;
134
+ }
135
+ }
136
+ resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparatorWin);
137
+ return resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail || '.';
138
+ }
4
139
  function isPosixPathSeparator(code) {
5
140
  return code === CHAR_FORWARD_SLASH;
6
141
  }
@@ -78,6 +213,13 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
78
213
  return res;
79
214
  }
80
215
  export function resolve(...args) {
216
+ // On Windows, host paths are `D:\…` style. The POSIX-only resolver
217
+ // below treats `D` as a non-`/` character and produces garbage; route
218
+ // to the Windows-aware variant. POSIX hosts (Linux/macOS/browser)
219
+ // run the original code path unchanged — `_isWin32` is constant-folded
220
+ // away on those targets.
221
+ if (_isWin32)
222
+ return resolveWin32(args);
81
223
  let resolvedPath = '';
82
224
  let resolvedAbsolute = false;
83
225
  for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {