@bytecodealliance/preview2-shim 0.14.0 → 0.14.2

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.
@@ -70,13 +70,12 @@ class Descriptor {
70
70
  static _createPreopen(hostPreopen) {
71
71
  const descriptor = new Descriptor();
72
72
  descriptor.#hostPreopen = hostPreopen.endsWith("/")
73
- ? hostPreopen.slice(0, -1) || '/'
73
+ ? hostPreopen.slice(0, -1) || "/"
74
74
  : hostPreopen;
75
75
  // Windows requires UNC paths at minimum
76
76
  if (isWindows) {
77
- descriptor.#hostPreopen = descriptor.#hostPreopen.replace(/\\/g, '/');
78
- if (descriptor.#hostPreopen === '/')
79
- descriptor.#hostPreopen = '//';
77
+ descriptor.#hostPreopen = descriptor.#hostPreopen.replace(/\\/g, "/");
78
+ if (descriptor.#hostPreopen === "/") descriptor.#hostPreopen = "//";
80
79
  }
81
80
  return descriptor;
82
81
  }
@@ -85,7 +84,6 @@ class Descriptor {
85
84
  const descriptor = new Descriptor();
86
85
  descriptor.#fd = fd;
87
86
  descriptor.#mode = mode;
88
- if (fullPath.endsWith("/")) throw new Error("bad full path");
89
87
  descriptor.#fullPath = fullPath;
90
88
  return descriptor;
91
89
  }
@@ -118,7 +116,9 @@ class Descriptor {
118
116
  return this.writeViaStream(this.stat().size);
119
117
  }
120
118
 
121
- advise(_offset, _length, _advice) { }
119
+ advise(_offset, _length, _advice) {
120
+ if (this.getType() === "directory") throw "bad-descriptor";
121
+ }
122
122
 
123
123
  syncData() {
124
124
  if (this.#hostPreopen) throw "invalid";
@@ -130,7 +130,6 @@ class Descriptor {
130
130
  }
131
131
 
132
132
  getFlags() {
133
- if (this.#hostPreopen) throw "invalid";
134
133
  return this.#mode;
135
134
  }
136
135
 
@@ -164,7 +163,7 @@ class Descriptor {
164
163
  const mtime = this.#getNewTimestamp(
165
164
  dataModificationTimestamp,
166
165
  dataModificationTimestamp.tag === "no-change" &&
167
- stats.dataModificationTimestamp
166
+ stats.dataModificationTimestamp
168
167
  );
169
168
  try {
170
169
  futimesSync(this.#fd, atime, mtime);
@@ -186,8 +185,14 @@ class Descriptor {
186
185
 
187
186
  read(length, offset) {
188
187
  if (!this.#fullPath) throw "bad-descriptor";
189
- const buf = new Uint8Array(length);
190
- const bytesRead = readSync(this.#fd, buf, Number(offset), length, 0);
188
+ const buf = new Uint8Array(Number(length));
189
+ const bytesRead = readSync(
190
+ this.#fd,
191
+ buf,
192
+ 0,
193
+ Number(length),
194
+ Number(offset)
195
+ );
191
196
  const out = new Uint8Array(buf.buffer, 0, bytesRead);
192
197
  return [out, bytesRead === 0 ? "ended" : "open"];
193
198
  }
@@ -195,7 +200,7 @@ class Descriptor {
195
200
  write(buffer, offset) {
196
201
  if (!this.#fullPath) throw "bad-descriptor";
197
202
  return BigInt(
198
- writeSync(this.#fd, buffer, Number(offset), buffer.byteLength - offset, 0)
203
+ writeSync(this.#fd, buffer, 0, buffer.byteLength, Number(offset))
199
204
  );
200
205
  }
201
206
 
@@ -250,7 +255,9 @@ class Descriptor {
250
255
  const fullPath = this.#getFullPath(path, false);
251
256
  let stats;
252
257
  try {
253
- stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, { bigint: true });
258
+ stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
259
+ bigint: true,
260
+ });
254
261
  } catch (e) {
255
262
  throw convertFsError(e);
256
263
  }
@@ -280,7 +287,7 @@ class Descriptor {
280
287
  const mtime = this.#getNewTimestamp(
281
288
  dataModificationTimestamp,
282
289
  dataModificationTimestamp.tag === "no-change" &&
283
- stats.dataModificationTimestamp
290
+ stats.dataModificationTimestamp
284
291
  );
285
292
  try {
286
293
  (pathFlags.symlinkFollow ? utimesSync : lutimesSync)(
@@ -297,8 +304,7 @@ class Descriptor {
297
304
  const oldFullPath = this.#getFullPath(oldPath, oldPathFlags.symlinkFollow);
298
305
  const newFullPath = newDescriptor.#getFullPath(newPath, false);
299
306
  // Windows doesn't automatically fail on trailing slashes
300
- if (isWindows && newFullPath.endsWith('/'))
301
- throw 'no-entry';
307
+ if (isWindows && newFullPath.endsWith("/")) throw "no-entry";
302
308
  try {
303
309
  linkSync(oldFullPath, newFullPath);
304
310
  } catch (e) {
@@ -320,14 +326,26 @@ class Descriptor {
320
326
  else if (descriptorFlags.read) fsOpenFlags |= constants.O_RDONLY;
321
327
  if (descriptorFlags.fileIntegritySync) fsOpenFlags |= constants.O_SYNC;
322
328
  if (descriptorFlags.dataIntegritySync) fsOpenFlags |= constants.O_DSYNC;
329
+ if (!pathFlags.symlinkFollow) fsOpenFlags |= constants.O_NOFOLLOW;
330
+
323
331
  // Unsupported:
324
332
  // if (descriptorFlags.requestedWriteSync)
325
333
  // if (descriptorFlags.mutateDirectory)
326
-
327
334
  try {
328
335
  const fd = openSync(fullPath, fsOpenFlags);
329
- return descriptorCreate(fd, descriptorFlags, fullPath, preopenEntries);
336
+ const descriptor = descriptorCreate(
337
+ fd,
338
+ descriptorFlags,
339
+ fullPath,
340
+ preopenEntries
341
+ );
342
+ if (fullPath.endsWith("/")) {
343
+ // check if its a directory
344
+ if (!descriptor.getType() === "directory") throw "not-directory";
345
+ }
346
+ return descriptor;
330
347
  } catch (e) {
348
+ if (e.code === "ERR_INVALID_ARG_VALUE") throw "invalid";
331
349
  throw convertFsError(e);
332
350
  }
333
351
  }
@@ -346,8 +364,7 @@ class Descriptor {
346
364
  try {
347
365
  rmdirSync(fullPath);
348
366
  } catch (e) {
349
- if (isWindows && e.code === 'ENOENT')
350
- throw 'not-directory';
367
+ if (isWindows && e.code === "ENOENT") throw "not-directory";
351
368
  throw convertFsError(e);
352
369
  }
353
370
  }
@@ -358,19 +375,19 @@ class Descriptor {
358
375
  try {
359
376
  renameSync(oldFullPath, newFullPath);
360
377
  } catch (e) {
361
- if (isWindows && e.code === 'EPERM')
362
- throw 'access';
378
+ if (isWindows && e.code === "EPERM") throw "access";
363
379
  throw convertFsError(e);
364
380
  }
365
381
  }
366
382
 
367
383
  symlinkAt(target, path) {
368
384
  const fullPath = this.#getFullPath(path, false);
385
+ if (target.startsWith("/")) throw "not-permitted";
369
386
  try {
370
387
  symlinkSync(target, fullPath);
371
388
  } catch (e) {
372
- if (isWindows && (e.code === 'EPERM' || e.code === 'EEXIST'))
373
- throw 'no-entry'
389
+ if (isWindows && (e.code === "EPERM" || e.code === "EEXIST"))
390
+ throw "no-entry";
374
391
  throw convertFsError(e);
375
392
  }
376
393
  }
@@ -401,7 +418,9 @@ class Descriptor {
401
418
  metadataHashAt(pathFlags, path) {
402
419
  const fullPath = this.#getFullPath(path, false);
403
420
  try {
404
- const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, { bigint: true });
421
+ const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
422
+ bigint: true,
423
+ });
405
424
  return { upper: stats.mtimeNs, lower: stats.ino };
406
425
  } catch (e) {
407
426
  throw convertFsError(e);
@@ -412,27 +431,56 @@ class Descriptor {
412
431
  #getFullPath(subpath, _followSymlinks) {
413
432
  let descriptor = this;
414
433
  if (subpath.indexOf("\\") !== -1) subpath = subpath.replace(/\\/g, "/");
415
- if (subpath[0] === '/') {
416
- let bestPreopenMatch = "";
417
- for (const preopenEntry of preopenEntries) {
434
+ if (subpath.indexOf("//") !== -1) subpath = subpath.replace(/\/\/+/g, "/");
435
+ if (subpath[0] === "/") throw "not-permitted";
436
+
437
+ // segment resolution
438
+ const segments = [];
439
+ let segmentIndex = -1;
440
+ for (let i = 0; i < subpath.length; i++) {
441
+ // busy reading a segment - only terminate on '/'
442
+ if (segmentIndex !== -1) {
443
+ if (subpath[i] === "/") {
444
+ segments.push(subpath.slice(segmentIndex, i + 1));
445
+ segmentIndex = -1;
446
+ }
447
+ continue;
448
+ }
449
+ // new segment - check if it is relative
450
+ else if (subpath[i] === ".") {
451
+ // ../ segment
418
452
  if (
419
- subpath.startsWith(preopenEntry[1]) &&
420
- (!bestPreopenMatch ||
421
- bestPreopenMatch.length < preopenEntry[1].length)
453
+ subpath[i + 1] === "." &&
454
+ (subpath[i + 2] === "/" || i + 2 === subpath.length)
422
455
  ) {
423
- bestPreopenMatch = preopenEntry;
456
+ if (segments.pop() === undefined) throw "not-permitted";
457
+ i += 2;
458
+ continue;
459
+ }
460
+ // ./ segment
461
+ else if (subpath[i + 1] === "/" || i + 1 === subpath.length) {
462
+ i += 1;
463
+ continue;
424
464
  }
425
465
  }
426
- if (!bestPreopenMatch) throw "no-entry";
427
- descriptor = bestPreopenMatch[0];
428
- subpath = subpath.slice(bestPreopenMatch[1]);
429
- if (subpath[0] === "/") subpath = subpath.slice(1);
466
+ // it is the start of a new segment
467
+ while (subpath[i] === "/") i++;
468
+ segmentIndex = i;
430
469
  }
431
- if (subpath.startsWith("."))
432
- subpath = subpath.slice(subpath[1] === "/" ? 2 : 1);
470
+ // finish reading out the last segment
471
+ if (segmentIndex !== -1) segments.push(subpath.slice(segmentIndex));
472
+
473
+ subpath = segments.join("");
474
+
433
475
  if (descriptor.#hostPreopen)
434
476
  return (
435
- descriptor.#hostPreopen + (descriptor.#hostPreopen.endsWith('/') ? '' : (subpath.length > 0 ? "/" : "")) + subpath
477
+ descriptor.#hostPreopen +
478
+ (descriptor.#hostPreopen.endsWith("/")
479
+ ? ""
480
+ : subpath.length > 0
481
+ ? "/"
482
+ : "") +
483
+ subpath
436
484
  );
437
485
  return descriptor.#fullPath + (subpath.length > 0 ? "/" : "") + subpath;
438
486
  }
@@ -489,6 +537,9 @@ _addPreopen("/", isWindows ? "//" : "/");
489
537
  export const types = {
490
538
  Descriptor,
491
539
  DirectoryEntryStream,
540
+ filesystemErrorCode(err) {
541
+ return convertFsError(err.payload);
542
+ },
492
543
  };
493
544
 
494
545
  export function _setPreopens(preopens) {