@bytecodealliance/preview2-shim 0.14.1 → 0.15.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.
- package/README.md +2 -2
- package/lib/browser/filesystem.js +6 -5
- package/lib/browser/random.js +1 -1
- package/lib/browser/sockets.js +0 -14
- package/lib/io/calls.js +80 -16
- package/lib/io/worker-http.js +164 -67
- package/lib/io/worker-io.js +207 -68
- package/lib/io/worker-socket-tcp.js +285 -0
- package/lib/io/worker-socket-udp.js +576 -0
- package/lib/io/worker-sockets.js +371 -0
- package/lib/io/worker-thread.js +793 -399
- package/lib/nodejs/cli.js +29 -13
- package/lib/nodejs/clocks.js +9 -6
- package/lib/nodejs/filesystem.js +170 -57
- package/lib/nodejs/http.js +662 -531
- package/lib/nodejs/index.js +0 -3
- package/lib/nodejs/sockets.js +571 -11
- package/lib/synckit/index.js +25 -41
- package/package.json +2 -2
- package/types/interfaces/wasi-http-types.d.ts +53 -41
- package/types/interfaces/wasi-sockets-tcp.d.ts +5 -0
- package/lib/common/assert.js +0 -7
- package/lib/nodejs/sockets/socket-common.js +0 -116
- package/lib/nodejs/sockets/socketopts-bindings.js +0 -94
- package/lib/nodejs/sockets/tcp-socket-impl.js +0 -794
- package/lib/nodejs/sockets/udp-socket-impl.js +0 -628
- package/lib/nodejs/sockets/wasi-sockets.js +0 -320
- package/lib/synckit/index.d.ts +0 -71
package/lib/nodejs/cli.js
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
import { argv, env, cwd } from "node:process";
|
|
2
2
|
import {
|
|
3
|
+
ioCall,
|
|
3
4
|
streams,
|
|
4
5
|
inputStreamCreate,
|
|
5
6
|
outputStreamCreate,
|
|
6
7
|
} from "../io/worker-io.js";
|
|
7
|
-
import { STDIN, STDOUT
|
|
8
|
+
import { INPUT_STREAM_CREATE, STDERR, STDIN, STDOUT } from "../io/calls.js";
|
|
8
9
|
const { InputStream, OutputStream } = streams;
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const
|
|
17
|
-
export const
|
|
18
|
-
export const
|
|
11
|
+
export const _appendEnv = (env) => {
|
|
12
|
+
void (_env = [
|
|
13
|
+
..._env.filter(([curKey]) => !(curKey in env)),
|
|
14
|
+
...Object.entries(env),
|
|
15
|
+
]);
|
|
16
|
+
}
|
|
17
|
+
export const _setEnv = (env) => void (_env = Object.entries(env));
|
|
18
|
+
export const _setArgs = (args) => void (_args = args);
|
|
19
|
+
export const _setCwd = (cwd) => void (_cwd = cwd);
|
|
20
|
+
export const _setStdin = (stdin) => void (stdinStream = stdin);
|
|
21
|
+
export const _setStdout = (stdout) => void (stdoutStream = stdout);
|
|
22
|
+
export const _setStderr = (stderr) => void (stderrStream = stderr);
|
|
23
|
+
export const _setTerminalStdin = (terminalStdin) =>
|
|
24
|
+
void (terminalStdinInstance = terminalStdin);
|
|
25
|
+
export const _setTerminalStdout = (terminalStdout) =>
|
|
26
|
+
void (terminalStdoutInstance = terminalStdout);
|
|
27
|
+
export const _setTerminalStderr = (terminalStderr) =>
|
|
28
|
+
void (terminalStderrInstance = terminalStderr);
|
|
19
29
|
|
|
20
30
|
let _env = Object.entries(env),
|
|
21
31
|
_args = argv.slice(1),
|
|
@@ -39,13 +49,19 @@ export const exit = {
|
|
|
39
49
|
},
|
|
40
50
|
};
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
let
|
|
44
|
-
let
|
|
52
|
+
// Stdin is created as a FILE descriptor
|
|
53
|
+
let stdinStream;
|
|
54
|
+
let stdoutStream = outputStreamCreate(STDOUT, 1);
|
|
55
|
+
let stderrStream = outputStreamCreate(STDERR, 2);
|
|
45
56
|
|
|
46
57
|
export const stdin = {
|
|
47
58
|
InputStream,
|
|
48
59
|
getStdin() {
|
|
60
|
+
if (!stdinStream)
|
|
61
|
+
stdinStream = inputStreamCreate(
|
|
62
|
+
STDIN,
|
|
63
|
+
ioCall(INPUT_STREAM_CREATE | STDIN, null, null),
|
|
64
|
+
);
|
|
49
65
|
return stdinStream;
|
|
50
66
|
},
|
|
51
67
|
};
|
package/lib/nodejs/clocks.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import { ioCall, createPoll
|
|
2
|
-
import
|
|
1
|
+
import { ioCall, createPoll } from "../io/worker-io.js";
|
|
2
|
+
import {
|
|
3
|
+
CLOCKS_NOW,
|
|
4
|
+
CLOCKS_INSTANT_SUBSCRIBE,
|
|
5
|
+
CLOCKS_DURATION_SUBSCRIBE,
|
|
6
|
+
} from "../io/calls.js";
|
|
3
7
|
|
|
4
8
|
export const monotonicClock = {
|
|
5
9
|
resolution() {
|
|
6
10
|
return 1n;
|
|
7
11
|
},
|
|
8
12
|
now() {
|
|
9
|
-
return ioCall(
|
|
13
|
+
return ioCall(CLOCKS_NOW, null, null);
|
|
10
14
|
},
|
|
11
15
|
subscribeInstant(instant) {
|
|
12
|
-
return createPoll(
|
|
16
|
+
return createPoll(CLOCKS_INSTANT_SUBSCRIBE, null, instant);
|
|
13
17
|
},
|
|
14
18
|
subscribeDuration(duration) {
|
|
15
19
|
duration = BigInt(duration);
|
|
16
|
-
|
|
17
|
-
return createPoll(calls.CLOCKS_DURATION_SUBSCRIBE, null, duration);
|
|
20
|
+
return createPoll(CLOCKS_DURATION_SUBSCRIBE, null, duration);
|
|
18
21
|
},
|
|
19
22
|
};
|
|
20
23
|
|
package/lib/nodejs/filesystem.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
earlyDispose,
|
|
3
3
|
inputStreamCreate,
|
|
4
|
+
ioCall,
|
|
4
5
|
outputStreamCreate,
|
|
6
|
+
registerDispose,
|
|
5
7
|
} from "../io/worker-io.js";
|
|
6
8
|
import { INPUT_STREAM_CREATE, OUTPUT_STREAM_CREATE } from "../io/calls.js";
|
|
7
9
|
import { FILE } from "../io/calls.js";
|
|
8
|
-
// import { environment } from "./cli.js";
|
|
9
10
|
import {
|
|
10
11
|
closeSync,
|
|
11
12
|
constants,
|
|
@@ -35,6 +36,7 @@ import { platform } from "node:process";
|
|
|
35
36
|
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
36
37
|
|
|
37
38
|
const isWindows = platform === "win32";
|
|
39
|
+
const isMac = platform === "darwin";
|
|
38
40
|
|
|
39
41
|
const nsMagnitude = 1_000_000_000_000n;
|
|
40
42
|
function nsToDateTime(ns) {
|
|
@@ -54,29 +56,29 @@ function lookupType(obj) {
|
|
|
54
56
|
return "unknown";
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
// Note: This should implement per-segment semantics of openAt, but we cannot
|
|
58
|
-
// due to the lack of support for openat() in Node.js.
|
|
59
|
+
// Note: This should implement per-segment semantics of openAt, but we cannot
|
|
60
|
+
// currently due to the lack of support for openat() in Node.js.
|
|
59
61
|
// Tracking issue: https://github.com/libuv/libuv/issues/4167
|
|
62
|
+
|
|
60
63
|
/**
|
|
61
64
|
* @implements {DescriptorProps}
|
|
62
65
|
*/
|
|
63
|
-
let descriptorCnt = 3;
|
|
64
66
|
class Descriptor {
|
|
65
67
|
#hostPreopen;
|
|
66
68
|
#fd;
|
|
69
|
+
#finalizer;
|
|
67
70
|
#mode;
|
|
68
71
|
#fullPath;
|
|
69
72
|
|
|
70
73
|
static _createPreopen(hostPreopen) {
|
|
71
74
|
const descriptor = new Descriptor();
|
|
72
75
|
descriptor.#hostPreopen = hostPreopen.endsWith("/")
|
|
73
|
-
? hostPreopen.slice(0, -1) ||
|
|
76
|
+
? hostPreopen.slice(0, -1) || "/"
|
|
74
77
|
: hostPreopen;
|
|
75
78
|
// Windows requires UNC paths at minimum
|
|
76
79
|
if (isWindows) {
|
|
77
|
-
descriptor.#hostPreopen = descriptor.#hostPreopen.replace(/\\/g,
|
|
78
|
-
if (descriptor.#hostPreopen ===
|
|
79
|
-
descriptor.#hostPreopen = '//';
|
|
80
|
+
descriptor.#hostPreopen = descriptor.#hostPreopen.replace(/\\/g, "/");
|
|
81
|
+
if (descriptor.#hostPreopen === "/") descriptor.#hostPreopen = "//";
|
|
80
82
|
}
|
|
81
83
|
return descriptor;
|
|
82
84
|
}
|
|
@@ -84,15 +86,17 @@ class Descriptor {
|
|
|
84
86
|
static _create(fd, mode, fullPath) {
|
|
85
87
|
const descriptor = new Descriptor();
|
|
86
88
|
descriptor.#fd = fd;
|
|
89
|
+
descriptor.#finalizer = registerDispose(descriptor, null, fd, closeSync);
|
|
87
90
|
descriptor.#mode = mode;
|
|
88
|
-
if (fullPath.endsWith("/")) throw new Error("bad full path");
|
|
89
91
|
descriptor.#fullPath = fullPath;
|
|
90
92
|
return descriptor;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
[symbolDispose]() {
|
|
96
|
+
if (this.#finalizer) {
|
|
97
|
+
earlyDispose(this.#finalizer);
|
|
98
|
+
this.#finalizer = null;
|
|
99
|
+
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
readViaStream(offset) {
|
|
@@ -118,19 +122,21 @@ class Descriptor {
|
|
|
118
122
|
return this.writeViaStream(this.stat().size);
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
advise(_offset, _length, _advice) {
|
|
125
|
+
advise(_offset, _length, _advice) {
|
|
126
|
+
if (this.getType() === "directory") throw "bad-descriptor";
|
|
127
|
+
}
|
|
122
128
|
|
|
123
129
|
syncData() {
|
|
124
130
|
if (this.#hostPreopen) throw "invalid";
|
|
125
131
|
try {
|
|
126
132
|
fdatasyncSync(this.#fd);
|
|
127
133
|
} catch (e) {
|
|
134
|
+
if (e.code === "EPERM") return;
|
|
128
135
|
throw convertFsError(e);
|
|
129
136
|
}
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
getFlags() {
|
|
133
|
-
if (this.#hostPreopen) throw "invalid";
|
|
134
140
|
return this.#mode;
|
|
135
141
|
}
|
|
136
142
|
|
|
@@ -164,7 +170,7 @@ class Descriptor {
|
|
|
164
170
|
const mtime = this.#getNewTimestamp(
|
|
165
171
|
dataModificationTimestamp,
|
|
166
172
|
dataModificationTimestamp.tag === "no-change" &&
|
|
167
|
-
|
|
173
|
+
stats.dataModificationTimestamp
|
|
168
174
|
);
|
|
169
175
|
try {
|
|
170
176
|
futimesSync(this.#fd, atime, mtime);
|
|
@@ -186,8 +192,14 @@ class Descriptor {
|
|
|
186
192
|
|
|
187
193
|
read(length, offset) {
|
|
188
194
|
if (!this.#fullPath) throw "bad-descriptor";
|
|
189
|
-
const buf = new Uint8Array(length);
|
|
190
|
-
const bytesRead = readSync(
|
|
195
|
+
const buf = new Uint8Array(Number(length));
|
|
196
|
+
const bytesRead = readSync(
|
|
197
|
+
this.#fd,
|
|
198
|
+
buf,
|
|
199
|
+
0,
|
|
200
|
+
Number(length),
|
|
201
|
+
Number(offset)
|
|
202
|
+
);
|
|
191
203
|
const out = new Uint8Array(buf.buffer, 0, bytesRead);
|
|
192
204
|
return [out, bytesRead === 0 ? "ended" : "open"];
|
|
193
205
|
}
|
|
@@ -195,7 +207,7 @@ class Descriptor {
|
|
|
195
207
|
write(buffer, offset) {
|
|
196
208
|
if (!this.#fullPath) throw "bad-descriptor";
|
|
197
209
|
return BigInt(
|
|
198
|
-
writeSync(this.#fd, buffer,
|
|
210
|
+
writeSync(this.#fd, buffer, 0, buffer.byteLength, Number(offset))
|
|
199
211
|
);
|
|
200
212
|
}
|
|
201
213
|
|
|
@@ -214,6 +226,7 @@ class Descriptor {
|
|
|
214
226
|
try {
|
|
215
227
|
fsyncSync(this.#fd);
|
|
216
228
|
} catch (e) {
|
|
229
|
+
if (e.code === "EPERM") return;
|
|
217
230
|
throw convertFsError(e);
|
|
218
231
|
}
|
|
219
232
|
}
|
|
@@ -250,7 +263,9 @@ class Descriptor {
|
|
|
250
263
|
const fullPath = this.#getFullPath(path, false);
|
|
251
264
|
let stats;
|
|
252
265
|
try {
|
|
253
|
-
stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
266
|
+
stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
267
|
+
bigint: true,
|
|
268
|
+
});
|
|
254
269
|
} catch (e) {
|
|
255
270
|
throw convertFsError(e);
|
|
256
271
|
}
|
|
@@ -280,7 +295,7 @@ class Descriptor {
|
|
|
280
295
|
const mtime = this.#getNewTimestamp(
|
|
281
296
|
dataModificationTimestamp,
|
|
282
297
|
dataModificationTimestamp.tag === "no-change" &&
|
|
283
|
-
|
|
298
|
+
stats.dataModificationTimestamp
|
|
284
299
|
);
|
|
285
300
|
try {
|
|
286
301
|
(pathFlags.symlinkFollow ? utimesSync : lutimesSync)(
|
|
@@ -297,8 +312,7 @@ class Descriptor {
|
|
|
297
312
|
const oldFullPath = this.#getFullPath(oldPath, oldPathFlags.symlinkFollow);
|
|
298
313
|
const newFullPath = newDescriptor.#getFullPath(newPath, false);
|
|
299
314
|
// Windows doesn't automatically fail on trailing slashes
|
|
300
|
-
if (isWindows && newFullPath.endsWith(
|
|
301
|
-
throw 'no-entry';
|
|
315
|
+
if (isWindows && newFullPath.endsWith("/")) throw "no-entry";
|
|
302
316
|
try {
|
|
303
317
|
linkSync(oldFullPath, newFullPath);
|
|
304
318
|
} catch (e) {
|
|
@@ -320,14 +334,51 @@ class Descriptor {
|
|
|
320
334
|
else if (descriptorFlags.read) fsOpenFlags |= constants.O_RDONLY;
|
|
321
335
|
if (descriptorFlags.fileIntegritySync) fsOpenFlags |= constants.O_SYNC;
|
|
322
336
|
if (descriptorFlags.dataIntegritySync) fsOpenFlags |= constants.O_DSYNC;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
337
|
+
if (!pathFlags.symlinkFollow) fsOpenFlags |= constants.O_NOFOLLOW;
|
|
338
|
+
if (descriptorFlags.requestedWriteSync || descriptorFlags.mutateDirectory)
|
|
339
|
+
throw "unsupported";
|
|
340
|
+
// Currently throw to match Wasmtime
|
|
341
|
+
if (descriptorFlags.fileIntegritySync || descriptorFlags.dataIntegritySync)
|
|
342
|
+
throw "unsupported";
|
|
343
|
+
if (isWindows) {
|
|
344
|
+
if (!pathFlags.symlinkFollow && !openFlags.create) {
|
|
345
|
+
let isSymlink = false;
|
|
346
|
+
try {
|
|
347
|
+
isSymlink = lstatSync(fullPath).isSymbolicLink();
|
|
348
|
+
} catch (e) {
|
|
349
|
+
//
|
|
350
|
+
}
|
|
351
|
+
if (isSymlink) throw openFlags.directory ? "not-directory" : "loop";
|
|
352
|
+
}
|
|
353
|
+
if (pathFlags.symlinkFollow && openFlags.directory) {
|
|
354
|
+
let isFile = false;
|
|
355
|
+
try {
|
|
356
|
+
isFile = !statSync(fullPath).isDirectory();
|
|
357
|
+
} catch (e) {
|
|
358
|
+
//
|
|
359
|
+
}
|
|
360
|
+
if (isFile) throw "not-directory";
|
|
361
|
+
}
|
|
362
|
+
}
|
|
327
363
|
try {
|
|
328
364
|
const fd = openSync(fullPath, fsOpenFlags);
|
|
329
|
-
|
|
365
|
+
const descriptor = descriptorCreate(
|
|
366
|
+
fd,
|
|
367
|
+
descriptorFlags,
|
|
368
|
+
fullPath,
|
|
369
|
+
preopenEntries
|
|
370
|
+
);
|
|
371
|
+
if (fullPath.endsWith("/") && isWindows) {
|
|
372
|
+
// check if its a directory
|
|
373
|
+
if (descriptor.getType() !== "directory") {
|
|
374
|
+
descriptor[symbolDispose]();
|
|
375
|
+
throw "not-directory";
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return descriptor;
|
|
330
379
|
} catch (e) {
|
|
380
|
+
if (e.code === "ERR_INVALID_ARG_VALUE")
|
|
381
|
+
throw isWindows ? "no-entry" : "invalid";
|
|
331
382
|
throw convertFsError(e);
|
|
332
383
|
}
|
|
333
384
|
}
|
|
@@ -346,8 +397,7 @@ class Descriptor {
|
|
|
346
397
|
try {
|
|
347
398
|
rmdirSync(fullPath);
|
|
348
399
|
} catch (e) {
|
|
349
|
-
if (isWindows && e.code ===
|
|
350
|
-
throw 'not-directory';
|
|
400
|
+
if (isWindows && e.code === "ENOENT") throw "not-directory";
|
|
351
401
|
throw convertFsError(e);
|
|
352
402
|
}
|
|
353
403
|
}
|
|
@@ -358,19 +408,29 @@ class Descriptor {
|
|
|
358
408
|
try {
|
|
359
409
|
renameSync(oldFullPath, newFullPath);
|
|
360
410
|
} catch (e) {
|
|
361
|
-
if (isWindows && e.code ===
|
|
362
|
-
throw 'access';
|
|
411
|
+
if (isWindows && e.code === "EPERM") throw "access";
|
|
363
412
|
throw convertFsError(e);
|
|
364
413
|
}
|
|
365
414
|
}
|
|
366
415
|
|
|
367
416
|
symlinkAt(target, path) {
|
|
368
417
|
const fullPath = this.#getFullPath(path, false);
|
|
418
|
+
if (target.startsWith("/")) throw "not-permitted";
|
|
369
419
|
try {
|
|
370
420
|
symlinkSync(target, fullPath);
|
|
371
421
|
} catch (e) {
|
|
372
|
-
if (
|
|
373
|
-
|
|
422
|
+
if (fullPath.endsWith("/") && e.code === "EEXIST") {
|
|
423
|
+
let isDir = false;
|
|
424
|
+
try {
|
|
425
|
+
isDir = statSync(fullPath).isDirectory();
|
|
426
|
+
} catch (_) {
|
|
427
|
+
//
|
|
428
|
+
}
|
|
429
|
+
if (!isDir) throw isWindows ? "no-entry" : "not-directory";
|
|
430
|
+
}
|
|
431
|
+
if (isWindows) {
|
|
432
|
+
if (e.code === "EPERM" || e.code === "EEXIST") throw "no-entry";
|
|
433
|
+
}
|
|
374
434
|
throw convertFsError(e);
|
|
375
435
|
}
|
|
376
436
|
}
|
|
@@ -378,8 +438,18 @@ class Descriptor {
|
|
|
378
438
|
unlinkFileAt(path) {
|
|
379
439
|
const fullPath = this.#getFullPath(path, false);
|
|
380
440
|
try {
|
|
441
|
+
if (fullPath.endsWith("/")) {
|
|
442
|
+
let isDir = false;
|
|
443
|
+
try {
|
|
444
|
+
isDir = statSync(fullPath).isDirectory();
|
|
445
|
+
} catch (e) {
|
|
446
|
+
//
|
|
447
|
+
}
|
|
448
|
+
throw isDir ? (isWindows ? "access" : (isMac ? "not-permitted" : "is-directory")) : "not-directory";
|
|
449
|
+
}
|
|
381
450
|
unlinkSync(fullPath);
|
|
382
451
|
} catch (e) {
|
|
452
|
+
if (isWindows && e.code === "EPERM") throw "access";
|
|
383
453
|
throw convertFsError(e);
|
|
384
454
|
}
|
|
385
455
|
}
|
|
@@ -401,7 +471,9 @@ class Descriptor {
|
|
|
401
471
|
metadataHashAt(pathFlags, path) {
|
|
402
472
|
const fullPath = this.#getFullPath(path, false);
|
|
403
473
|
try {
|
|
404
|
-
const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
474
|
+
const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
475
|
+
bigint: true,
|
|
476
|
+
});
|
|
405
477
|
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
406
478
|
} catch (e) {
|
|
407
479
|
throw convertFsError(e);
|
|
@@ -412,34 +484,59 @@ class Descriptor {
|
|
|
412
484
|
#getFullPath(subpath, _followSymlinks) {
|
|
413
485
|
let descriptor = this;
|
|
414
486
|
if (subpath.indexOf("\\") !== -1) subpath = subpath.replace(/\\/g, "/");
|
|
415
|
-
if (subpath
|
|
416
|
-
|
|
417
|
-
|
|
487
|
+
if (subpath.indexOf("//") !== -1) subpath = subpath.replace(/\/\/+/g, "/");
|
|
488
|
+
if (subpath[0] === "/") throw "not-permitted";
|
|
489
|
+
|
|
490
|
+
// segment resolution
|
|
491
|
+
const segments = [];
|
|
492
|
+
let segmentIndex = -1;
|
|
493
|
+
for (let i = 0; i < subpath.length; i++) {
|
|
494
|
+
// busy reading a segment - only terminate on '/'
|
|
495
|
+
if (segmentIndex !== -1) {
|
|
496
|
+
if (subpath[i] === "/") {
|
|
497
|
+
segments.push(subpath.slice(segmentIndex, i + 1));
|
|
498
|
+
segmentIndex = -1;
|
|
499
|
+
}
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
// new segment - check if it is relative
|
|
503
|
+
else if (subpath[i] === ".") {
|
|
504
|
+
// ../ segment
|
|
418
505
|
if (
|
|
419
|
-
subpath
|
|
420
|
-
(
|
|
421
|
-
bestPreopenMatch.length < preopenEntry[1].length)
|
|
506
|
+
subpath[i + 1] === "." &&
|
|
507
|
+
(subpath[i + 2] === "/" || i + 2 === subpath.length)
|
|
422
508
|
) {
|
|
423
|
-
|
|
509
|
+
if (segments.pop() === undefined) throw "not-permitted";
|
|
510
|
+
i += 2;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
// ./ segment
|
|
514
|
+
else if (subpath[i + 1] === "/" || i + 1 === subpath.length) {
|
|
515
|
+
i += 1;
|
|
516
|
+
continue;
|
|
424
517
|
}
|
|
425
518
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
if (subpath[0] === "/") subpath = subpath.slice(1);
|
|
519
|
+
// it is the start of a new segment
|
|
520
|
+
while (subpath[i] === "/") i++;
|
|
521
|
+
segmentIndex = i;
|
|
430
522
|
}
|
|
431
|
-
|
|
432
|
-
|
|
523
|
+
// finish reading out the last segment
|
|
524
|
+
if (segmentIndex !== -1) segments.push(subpath.slice(segmentIndex));
|
|
525
|
+
|
|
526
|
+
subpath = segments.join("");
|
|
527
|
+
|
|
433
528
|
if (descriptor.#hostPreopen)
|
|
434
529
|
return (
|
|
435
|
-
descriptor.#hostPreopen +
|
|
530
|
+
descriptor.#hostPreopen +
|
|
531
|
+
(descriptor.#hostPreopen.endsWith("/")
|
|
532
|
+
? ""
|
|
533
|
+
: subpath.length > 0
|
|
534
|
+
? "/"
|
|
535
|
+
: "") +
|
|
536
|
+
subpath
|
|
436
537
|
);
|
|
437
538
|
return descriptor.#fullPath + (subpath.length > 0 ? "/" : "") + subpath;
|
|
438
539
|
}
|
|
439
|
-
|
|
440
|
-
[symbolDispose]() {
|
|
441
|
-
if (this.#fd) closeSync(this.#fd);
|
|
442
|
-
}
|
|
443
540
|
}
|
|
444
541
|
const descriptorCreatePreopen = Descriptor._createPreopen;
|
|
445
542
|
delete Descriptor._createPreopen;
|
|
@@ -448,6 +545,7 @@ delete Descriptor._create;
|
|
|
448
545
|
|
|
449
546
|
class DirectoryEntryStream {
|
|
450
547
|
#dir;
|
|
548
|
+
#finalizer;
|
|
451
549
|
readDirectoryEntry() {
|
|
452
550
|
let entry;
|
|
453
551
|
try {
|
|
@@ -462,15 +560,23 @@ class DirectoryEntryStream {
|
|
|
462
560
|
const type = lookupType(entry);
|
|
463
561
|
return { name, type };
|
|
464
562
|
}
|
|
465
|
-
[symbolDispose]() {
|
|
466
|
-
this.#dir.closeSync();
|
|
467
|
-
}
|
|
468
|
-
|
|
469
563
|
static _create(dir) {
|
|
470
564
|
const dirStream = new DirectoryEntryStream();
|
|
565
|
+
dirStream.#finalizer = registerDispose(
|
|
566
|
+
dirStream,
|
|
567
|
+
null,
|
|
568
|
+
null,
|
|
569
|
+
dir.closeSync.bind(dir)
|
|
570
|
+
);
|
|
471
571
|
dirStream.#dir = dir;
|
|
472
572
|
return dirStream;
|
|
473
573
|
}
|
|
574
|
+
[symbolDispose]() {
|
|
575
|
+
if (this.#finalizer) {
|
|
576
|
+
earlyDispose(this.#finalizer);
|
|
577
|
+
this.#finalizer = null;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
474
580
|
}
|
|
475
581
|
const directoryEntryStreamCreate = DirectoryEntryStream._create;
|
|
476
582
|
delete DirectoryEntryStream._create;
|
|
@@ -489,6 +595,9 @@ _addPreopen("/", isWindows ? "//" : "/");
|
|
|
489
595
|
export const types = {
|
|
490
596
|
Descriptor,
|
|
491
597
|
DirectoryEntryStream,
|
|
598
|
+
filesystemErrorCode(err) {
|
|
599
|
+
return convertFsError(err.payload);
|
|
600
|
+
},
|
|
492
601
|
};
|
|
493
602
|
|
|
494
603
|
export function _setPreopens(preopens) {
|
|
@@ -564,6 +673,10 @@ function convertFsError(e) {
|
|
|
564
673
|
return "unsupported";
|
|
565
674
|
case "ENOTTY":
|
|
566
675
|
return "no-tty";
|
|
676
|
+
// windows gives this error for badly structured `//` reads
|
|
677
|
+
// this seems like a slightly better error than unknown given
|
|
678
|
+
// that it's a common footgun
|
|
679
|
+
case -4094:
|
|
567
680
|
case "ENXIO":
|
|
568
681
|
return "no-such-device";
|
|
569
682
|
case "EOVERFLOW":
|