@bytecodealliance/preview2-shim 0.18.1 → 0.20.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 +15 -15
- package/dist/browser/cli.d.ts +16 -0
- package/dist/browser/cli.js +109 -0
- package/dist/browser/clocks.d.ts +3 -0
- package/dist/browser/clocks.js +36 -0
- package/dist/browser/config.d.ts +2 -0
- package/{lib → dist}/browser/config.js +2 -4
- package/dist/browser/environment.d.ts +5 -0
- package/dist/browser/environment.js +24 -0
- package/dist/browser/filesystem.d.ts +132 -0
- package/dist/browser/filesystem.js +488 -0
- package/dist/browser/http.d.ts +4 -0
- package/dist/browser/http.js +643 -0
- package/dist/browser/index.d.ts +7 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/io.d.ts +58 -0
- package/dist/browser/io.js +205 -0
- package/dist/browser/random.d.ts +4 -0
- package/dist/browser/random.js +49 -0
- package/dist/browser/sockets.d.ts +8 -0
- package/dist/browser/sockets.js +66 -0
- package/dist/common/instantiation.d.ts +97 -0
- package/dist/common/instantiation.js +228 -0
- package/dist/io/calls.d.ts +91 -0
- package/{lib → dist}/io/calls.js +4 -19
- package/dist/io/worker-http.d.ts +17 -0
- package/dist/io/worker-http.js +192 -0
- package/dist/io/worker-io.d.ts +84 -0
- package/dist/io/worker-io.js +381 -0
- package/dist/io/worker-socket-tcp.d.ts +34 -0
- package/dist/io/worker-socket-tcp.js +251 -0
- package/dist/io/worker-socket-udp.d.ts +54 -0
- package/dist/io/worker-socket-udp.js +493 -0
- package/dist/io/worker-sockets.d.ts +32 -0
- package/dist/io/worker-sockets.js +265 -0
- package/dist/io/worker-thread.d.ts +73 -0
- package/dist/io/worker-thread.js +794 -0
- package/dist/nodejs/cli.d.ts +30 -0
- package/dist/nodejs/cli.js +86 -0
- package/dist/nodejs/clocks.d.ts +3 -0
- package/dist/nodejs/clocks.js +61 -0
- package/dist/nodejs/filesystem.d.ts +113 -0
- package/dist/nodejs/filesystem.js +761 -0
- package/dist/nodejs/http.d.ts +82 -0
- package/dist/nodejs/http.js +674 -0
- package/dist/nodejs/index.d.ts +7 -0
- package/dist/nodejs/index.js +7 -0
- package/dist/nodejs/io.d.ts +1 -0
- package/dist/nodejs/io.js +1 -0
- package/dist/nodejs/random.d.ts +4 -0
- package/dist/nodejs/random.js +42 -0
- package/dist/nodejs/sockets.d.ts +21 -0
- package/dist/nodejs/sockets.js +482 -0
- package/dist/synckit/index.d.ts +2 -0
- package/dist/synckit/index.js +117 -0
- package/package.json +28 -15
- package/types/instantiation.d.ts +7 -7
- package/lib/browser/cli.js +0 -135
- package/lib/browser/clocks.js +0 -39
- package/lib/browser/environment.js +0 -29
- package/lib/browser/filesystem.js +0 -503
- package/lib/browser/http.js +0 -707
- package/lib/browser/index.js +0 -9
- package/lib/browser/io.js +0 -262
- package/lib/browser/random.js +0 -56
- package/lib/browser/sockets.js +0 -88
- package/lib/common/instantiation.js +0 -253
- package/lib/io/worker-http.js +0 -206
- package/lib/io/worker-io.js +0 -468
- package/lib/io/worker-socket-tcp.js +0 -331
- package/lib/io/worker-socket-udp.js +0 -587
- package/lib/io/worker-sockets.js +0 -364
- package/lib/io/worker-thread.js +0 -1051
- package/lib/nodejs/cli.js +0 -109
- package/lib/nodejs/clocks.js +0 -67
- package/lib/nodejs/filesystem.js +0 -829
- package/lib/nodejs/http.js +0 -764
- package/lib/nodejs/index.js +0 -9
- package/lib/nodejs/io.js +0 -1
- package/lib/nodejs/random.js +0 -49
- package/lib/nodejs/sockets.js +0 -565
- package/lib/synckit/index.js +0 -127
package/lib/nodejs/filesystem.js
DELETED
|
@@ -1,829 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
earlyDispose,
|
|
3
|
-
inputStreamCreate,
|
|
4
|
-
ioCall,
|
|
5
|
-
outputStreamCreate,
|
|
6
|
-
registerDispose,
|
|
7
|
-
} from "../io/worker-io.js";
|
|
8
|
-
import { INPUT_STREAM_CREATE, OUTPUT_STREAM_CREATE } from "../io/calls.js";
|
|
9
|
-
import { FILE } from "../io/calls.js";
|
|
10
|
-
import nodeFs, {
|
|
11
|
-
closeSync,
|
|
12
|
-
constants,
|
|
13
|
-
fdatasyncSync,
|
|
14
|
-
fstatSync,
|
|
15
|
-
fsyncSync,
|
|
16
|
-
ftruncateSync,
|
|
17
|
-
futimesSync,
|
|
18
|
-
linkSync,
|
|
19
|
-
lstatSync,
|
|
20
|
-
mkdirSync,
|
|
21
|
-
opendirSync,
|
|
22
|
-
openSync,
|
|
23
|
-
readlinkSync,
|
|
24
|
-
readSync,
|
|
25
|
-
renameSync,
|
|
26
|
-
rmdirSync,
|
|
27
|
-
statSync,
|
|
28
|
-
symlinkSync,
|
|
29
|
-
unlinkSync,
|
|
30
|
-
utimesSync,
|
|
31
|
-
writeSync,
|
|
32
|
-
} from "node:fs";
|
|
33
|
-
import { platform } from "node:process";
|
|
34
|
-
|
|
35
|
-
const lutimesSync = nodeFs.lutimesSync;
|
|
36
|
-
|
|
37
|
-
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
38
|
-
|
|
39
|
-
const isWindows = platform === "win32";
|
|
40
|
-
const isMac = platform === "darwin";
|
|
41
|
-
|
|
42
|
-
const nsMagnitude = 1_000_000_000n;
|
|
43
|
-
function nsToDateTime(ns) {
|
|
44
|
-
const seconds = ns / nsMagnitude;
|
|
45
|
-
const nanoseconds = Number(ns % nsMagnitude);
|
|
46
|
-
return { seconds, nanoseconds };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function lookupType(obj) {
|
|
50
|
-
if (obj.isFile()) {
|
|
51
|
-
return "regular-file";
|
|
52
|
-
} else if (obj.isSocket()) {
|
|
53
|
-
return "socket";
|
|
54
|
-
} else if (obj.isSymbolicLink()) {
|
|
55
|
-
return "symbolic-link";
|
|
56
|
-
} else if (obj.isFIFO()) {
|
|
57
|
-
return "fifo";
|
|
58
|
-
} else if (obj.isDirectory()) {
|
|
59
|
-
return "directory";
|
|
60
|
-
} else if (obj.isCharacterDevice()) {
|
|
61
|
-
return "character-device";
|
|
62
|
-
} else if (obj.isBlockDevice()) {
|
|
63
|
-
return "block-device";
|
|
64
|
-
}
|
|
65
|
-
return "unknown";
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Note: This should implement per-segment semantics of openAt, but we cannot
|
|
69
|
-
// currently due to the lack of support for openat() in Node.js.
|
|
70
|
-
// Tracking issue: https://github.com/libuv/libuv/issues/4167
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @implements {DescriptorProps}
|
|
74
|
-
*/
|
|
75
|
-
class Descriptor {
|
|
76
|
-
#hostPreopen;
|
|
77
|
-
#fd;
|
|
78
|
-
#finalizer;
|
|
79
|
-
#mode;
|
|
80
|
-
#fullPath;
|
|
81
|
-
|
|
82
|
-
static _createPreopen(hostPreopen) {
|
|
83
|
-
const descriptor = new Descriptor();
|
|
84
|
-
descriptor.#hostPreopen = hostPreopen.endsWith("/")
|
|
85
|
-
? hostPreopen.slice(0, -1) || "/"
|
|
86
|
-
: hostPreopen;
|
|
87
|
-
// Windows requires UNC paths at minimum
|
|
88
|
-
if (isWindows) {
|
|
89
|
-
descriptor.#hostPreopen = descriptor.#hostPreopen.replace(/\\/g, "/");
|
|
90
|
-
if (descriptor.#hostPreopen === "/") {
|
|
91
|
-
descriptor.#hostPreopen = "//";
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return descriptor;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
static _create(fd, mode, fullPath) {
|
|
98
|
-
const descriptor = new Descriptor();
|
|
99
|
-
descriptor.#fd = fd;
|
|
100
|
-
descriptor.#finalizer = registerDispose(descriptor, null, fd, closeSync);
|
|
101
|
-
descriptor.#mode = mode;
|
|
102
|
-
descriptor.#fullPath = fullPath;
|
|
103
|
-
return descriptor;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
[symbolDispose]() {
|
|
107
|
-
if (this.#finalizer) {
|
|
108
|
-
earlyDispose(this.#finalizer);
|
|
109
|
-
this.#finalizer = null;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
readViaStream(offset) {
|
|
114
|
-
if (this.#hostPreopen) {
|
|
115
|
-
throw "is-directory";
|
|
116
|
-
}
|
|
117
|
-
return inputStreamCreate(
|
|
118
|
-
FILE,
|
|
119
|
-
ioCall(INPUT_STREAM_CREATE | FILE, null, {
|
|
120
|
-
fd: this.#fd,
|
|
121
|
-
offset,
|
|
122
|
-
}),
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
writeViaStream(offset) {
|
|
127
|
-
if (this.#hostPreopen) {
|
|
128
|
-
throw "is-directory";
|
|
129
|
-
}
|
|
130
|
-
return outputStreamCreate(
|
|
131
|
-
FILE,
|
|
132
|
-
ioCall(OUTPUT_STREAM_CREATE | FILE, null, { fd: this.#fd, offset }),
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
appendViaStream() {
|
|
137
|
-
return this.writeViaStream(this.stat().size);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
advise(_offset, _length, _advice) {
|
|
141
|
-
if (this.getType() === "directory") {
|
|
142
|
-
throw "bad-descriptor";
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
syncData() {
|
|
147
|
-
if (this.#hostPreopen) {
|
|
148
|
-
throw "invalid";
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
fdatasyncSync(this.#fd);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
if (e.code === "EPERM") {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
throw convertFsError(e);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
getFlags() {
|
|
161
|
-
return this.#mode;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
getType() {
|
|
165
|
-
if (this.#hostPreopen) {
|
|
166
|
-
return "directory";
|
|
167
|
-
}
|
|
168
|
-
const stats = fstatSync(this.#fd);
|
|
169
|
-
return lookupType(stats);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
setSize(size) {
|
|
173
|
-
if (this.#hostPreopen) {
|
|
174
|
-
throw "is-directory";
|
|
175
|
-
}
|
|
176
|
-
try {
|
|
177
|
-
ftruncateSync(this.#fd, Number(size));
|
|
178
|
-
} catch (e) {
|
|
179
|
-
if (isWindows && e.code === "EPERM") {
|
|
180
|
-
throw "access";
|
|
181
|
-
}
|
|
182
|
-
throw convertFsError(e);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
setTimes(dataAccessTimestamp, dataModificationTimestamp) {
|
|
187
|
-
if (this.#hostPreopen) {
|
|
188
|
-
throw "invalid";
|
|
189
|
-
}
|
|
190
|
-
let stats;
|
|
191
|
-
if (dataAccessTimestamp.tag === "no-change" || dataModificationTimestamp.tag === "no-change") {
|
|
192
|
-
stats = this.stat();
|
|
193
|
-
}
|
|
194
|
-
const atime = this.#getNewTimestamp(
|
|
195
|
-
dataAccessTimestamp,
|
|
196
|
-
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp,
|
|
197
|
-
);
|
|
198
|
-
const mtime = this.#getNewTimestamp(
|
|
199
|
-
dataModificationTimestamp,
|
|
200
|
-
dataModificationTimestamp.tag === "no-change" && stats.dataModificationTimestamp,
|
|
201
|
-
);
|
|
202
|
-
try {
|
|
203
|
-
futimesSync(this.#fd, atime, mtime);
|
|
204
|
-
} catch (e) {
|
|
205
|
-
throw convertFsError(e);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
#getNewTimestamp(newTimestamp, maybeNow) {
|
|
210
|
-
switch (newTimestamp.tag) {
|
|
211
|
-
case "no-change":
|
|
212
|
-
return timestampToMs(maybeNow);
|
|
213
|
-
case "now":
|
|
214
|
-
return Math.floor(Date.now() / 1e3);
|
|
215
|
-
case "timestamp":
|
|
216
|
-
return timestampToMs(newTimestamp.val);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
read(length, offset) {
|
|
221
|
-
if (!this.#fullPath) {
|
|
222
|
-
throw "bad-descriptor";
|
|
223
|
-
}
|
|
224
|
-
const buf = new Uint8Array(Number(length));
|
|
225
|
-
const bytesRead = readSync(this.#fd, buf, 0, Number(length), Number(offset));
|
|
226
|
-
const out = new Uint8Array(buf.buffer, 0, bytesRead);
|
|
227
|
-
return [out, bytesRead === 0 ? "ended" : "open"];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
write(buffer, offset) {
|
|
231
|
-
if (!this.#fullPath) {
|
|
232
|
-
throw "bad-descriptor";
|
|
233
|
-
}
|
|
234
|
-
return BigInt(writeSync(this.#fd, buffer, 0, buffer.byteLength, Number(offset)));
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
readDirectory() {
|
|
238
|
-
if (!this.#fullPath) {
|
|
239
|
-
throw "bad-descriptor";
|
|
240
|
-
}
|
|
241
|
-
try {
|
|
242
|
-
const dir = opendirSync(this.#fullPath);
|
|
243
|
-
return directoryEntryStreamCreate(dir);
|
|
244
|
-
} catch (e) {
|
|
245
|
-
throw convertFsError(e);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
sync() {
|
|
250
|
-
if (this.#hostPreopen) {
|
|
251
|
-
throw "invalid";
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
fsyncSync(this.#fd);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
if (e.code === "EPERM") {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
throw convertFsError(e);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
createDirectoryAt(path) {
|
|
264
|
-
const fullPath = this.#getFullPath(path);
|
|
265
|
-
try {
|
|
266
|
-
mkdirSync(fullPath);
|
|
267
|
-
} catch (e) {
|
|
268
|
-
throw convertFsError(e);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
stat() {
|
|
273
|
-
if (this.#hostPreopen) {
|
|
274
|
-
throw "invalid";
|
|
275
|
-
}
|
|
276
|
-
let stats;
|
|
277
|
-
try {
|
|
278
|
-
stats = fstatSync(this.#fd, { bigint: true });
|
|
279
|
-
} catch (e) {
|
|
280
|
-
throw convertFsError(e);
|
|
281
|
-
}
|
|
282
|
-
const type = lookupType(stats);
|
|
283
|
-
return {
|
|
284
|
-
type,
|
|
285
|
-
linkCount: stats.nlink,
|
|
286
|
-
size: stats.size,
|
|
287
|
-
dataAccessTimestamp: nsToDateTime(stats.atimeNs),
|
|
288
|
-
dataModificationTimestamp: nsToDateTime(stats.mtimeNs),
|
|
289
|
-
statusChangeTimestamp: nsToDateTime(stats.ctimeNs),
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
statAt(pathFlags, path) {
|
|
294
|
-
const fullPath = this.#getFullPath(path, false);
|
|
295
|
-
let stats;
|
|
296
|
-
try {
|
|
297
|
-
stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
298
|
-
bigint: true,
|
|
299
|
-
});
|
|
300
|
-
} catch (e) {
|
|
301
|
-
throw convertFsError(e);
|
|
302
|
-
}
|
|
303
|
-
const type = lookupType(stats);
|
|
304
|
-
return {
|
|
305
|
-
type,
|
|
306
|
-
linkCount: stats.nlink,
|
|
307
|
-
size: stats.size,
|
|
308
|
-
dataAccessTimestamp: nsToDateTime(stats.atimeNs),
|
|
309
|
-
dataModificationTimestamp: nsToDateTime(stats.mtimeNs),
|
|
310
|
-
statusChangeTimestamp: nsToDateTime(stats.ctimeNs),
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
setTimesAt(pathFlags, path, dataAccessTimestamp, dataModificationTimestamp) {
|
|
315
|
-
const fullPath = this.#getFullPath(path, false);
|
|
316
|
-
let stats;
|
|
317
|
-
if (dataAccessTimestamp.tag === "no-change" || dataModificationTimestamp.tag === "no-change") {
|
|
318
|
-
stats = this.stat();
|
|
319
|
-
}
|
|
320
|
-
const atime = this.#getNewTimestamp(
|
|
321
|
-
dataAccessTimestamp,
|
|
322
|
-
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp,
|
|
323
|
-
);
|
|
324
|
-
const mtime = this.#getNewTimestamp(
|
|
325
|
-
dataModificationTimestamp,
|
|
326
|
-
dataModificationTimestamp.tag === "no-change" && stats.dataModificationTimestamp,
|
|
327
|
-
);
|
|
328
|
-
if (!pathFlags.symlinkFollow && !lutimesSync) {
|
|
329
|
-
throw new Error("Changing the timestamps of symlinks isn't supported");
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
let metadataSetFn = pathFlags.symlinkFollow ? lutimesSync : utimesSync;
|
|
333
|
-
try {
|
|
334
|
-
metadataSetFn(fullPath, atime / 1000, mtime / 1000);
|
|
335
|
-
} catch (e) {
|
|
336
|
-
throw convertFsError(e);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
linkAt(oldPathFlags, oldPath, newDescriptor, newPath) {
|
|
341
|
-
const oldFullPath = this.#getFullPath(oldPath, oldPathFlags.symlinkFollow);
|
|
342
|
-
const newFullPath = newDescriptor.#getFullPath(newPath, false);
|
|
343
|
-
// Windows doesn't automatically fail on trailing slashes
|
|
344
|
-
if (isWindows && newFullPath.endsWith("/")) {
|
|
345
|
-
throw "no-entry";
|
|
346
|
-
}
|
|
347
|
-
try {
|
|
348
|
-
linkSync(oldFullPath, newFullPath);
|
|
349
|
-
} catch (e) {
|
|
350
|
-
throw convertFsError(e);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
openAt(pathFlags, path, openFlags, descriptorFlags) {
|
|
355
|
-
if (preopenEntries.length === 0) {
|
|
356
|
-
throw "access";
|
|
357
|
-
}
|
|
358
|
-
const fullPath = this.#getFullPath(path, pathFlags.symlinkFollow);
|
|
359
|
-
let fsOpenFlags = 0x0;
|
|
360
|
-
if (openFlags.create) {
|
|
361
|
-
fsOpenFlags |= constants.O_CREAT;
|
|
362
|
-
}
|
|
363
|
-
if (openFlags.directory) {
|
|
364
|
-
fsOpenFlags |= constants.O_DIRECTORY;
|
|
365
|
-
}
|
|
366
|
-
if (openFlags.exclusive) {
|
|
367
|
-
fsOpenFlags |= constants.O_EXCL;
|
|
368
|
-
}
|
|
369
|
-
if (openFlags.truncate) {
|
|
370
|
-
fsOpenFlags |= constants.O_TRUNC;
|
|
371
|
-
}
|
|
372
|
-
if (descriptorFlags.read && descriptorFlags.write) {
|
|
373
|
-
fsOpenFlags |= constants.O_RDWR;
|
|
374
|
-
} else if (descriptorFlags.write) {
|
|
375
|
-
fsOpenFlags |= constants.O_WRONLY;
|
|
376
|
-
} else if (descriptorFlags.read) {
|
|
377
|
-
fsOpenFlags |= constants.O_RDONLY;
|
|
378
|
-
}
|
|
379
|
-
if (descriptorFlags.fileIntegritySync) {
|
|
380
|
-
fsOpenFlags |= constants.O_SYNC;
|
|
381
|
-
}
|
|
382
|
-
if (descriptorFlags.dataIntegritySync) {
|
|
383
|
-
fsOpenFlags |= constants.O_DSYNC;
|
|
384
|
-
}
|
|
385
|
-
if (!pathFlags.symlinkFollow) {
|
|
386
|
-
fsOpenFlags |= constants.O_NOFOLLOW;
|
|
387
|
-
}
|
|
388
|
-
if (descriptorFlags.requestedWriteSync || descriptorFlags.mutateDirectory) {
|
|
389
|
-
throw "unsupported";
|
|
390
|
-
}
|
|
391
|
-
// Currently throw to match Wasmtime
|
|
392
|
-
if (descriptorFlags.fileIntegritySync || descriptorFlags.dataIntegritySync) {
|
|
393
|
-
throw "unsupported";
|
|
394
|
-
}
|
|
395
|
-
if (isWindows) {
|
|
396
|
-
if (!pathFlags.symlinkFollow && !openFlags.create) {
|
|
397
|
-
let isSymlink = false;
|
|
398
|
-
try {
|
|
399
|
-
isSymlink = lstatSync(fullPath).isSymbolicLink();
|
|
400
|
-
} catch {
|
|
401
|
-
//
|
|
402
|
-
}
|
|
403
|
-
if (isSymlink) {
|
|
404
|
-
throw openFlags.directory ? "not-directory" : "loop";
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
if (pathFlags.symlinkFollow && openFlags.directory) {
|
|
408
|
-
let isFile = false;
|
|
409
|
-
try {
|
|
410
|
-
isFile = !statSync(fullPath).isDirectory();
|
|
411
|
-
} catch {
|
|
412
|
-
//
|
|
413
|
-
}
|
|
414
|
-
if (isFile) {
|
|
415
|
-
throw "not-directory";
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
try {
|
|
420
|
-
const fd = openSync(fullPath.endsWith("/") ? fullPath.slice(0, -1) : fullPath, fsOpenFlags);
|
|
421
|
-
const descriptor = descriptorCreate(fd, descriptorFlags, fullPath, preopenEntries);
|
|
422
|
-
if (fullPath.endsWith("/") && descriptor.getType() !== "directory") {
|
|
423
|
-
descriptor[symbolDispose]();
|
|
424
|
-
throw "not-directory";
|
|
425
|
-
}
|
|
426
|
-
return descriptor;
|
|
427
|
-
} catch (e) {
|
|
428
|
-
if (e.code === "ERR_INVALID_ARG_VALUE") {
|
|
429
|
-
throw isWindows ? "no-entry" : "invalid";
|
|
430
|
-
}
|
|
431
|
-
throw convertFsError(e);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
readlinkAt(path) {
|
|
436
|
-
const fullPath = this.#getFullPath(path, false);
|
|
437
|
-
try {
|
|
438
|
-
return readlinkSync(fullPath);
|
|
439
|
-
} catch (e) {
|
|
440
|
-
throw convertFsError(e);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
removeDirectoryAt(path) {
|
|
445
|
-
const fullPath = this.#getFullPath(path, false);
|
|
446
|
-
try {
|
|
447
|
-
rmdirSync(fullPath);
|
|
448
|
-
} catch (e) {
|
|
449
|
-
if (isWindows && e.code === "ENOENT") {
|
|
450
|
-
throw "not-directory";
|
|
451
|
-
}
|
|
452
|
-
throw convertFsError(e);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
renameAt(oldPath, newDescriptor, newPath) {
|
|
457
|
-
const oldFullPath = this.#getFullPath(oldPath, false);
|
|
458
|
-
const newFullPath = newDescriptor.#getFullPath(newPath, false);
|
|
459
|
-
try {
|
|
460
|
-
renameSync(oldFullPath, newFullPath);
|
|
461
|
-
} catch (e) {
|
|
462
|
-
if (isWindows && e.code === "EPERM") {
|
|
463
|
-
throw "access";
|
|
464
|
-
}
|
|
465
|
-
throw convertFsError(e);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
symlinkAt(target, path) {
|
|
470
|
-
const fullPath = this.#getFullPath(path, false);
|
|
471
|
-
if (target.startsWith("/")) {
|
|
472
|
-
throw "not-permitted";
|
|
473
|
-
}
|
|
474
|
-
try {
|
|
475
|
-
symlinkSync(target, fullPath);
|
|
476
|
-
} catch (e) {
|
|
477
|
-
if (fullPath.endsWith("/") && e.code === "EEXIST") {
|
|
478
|
-
let isDir = false;
|
|
479
|
-
try {
|
|
480
|
-
isDir = statSync(fullPath).isDirectory();
|
|
481
|
-
} catch {
|
|
482
|
-
//
|
|
483
|
-
}
|
|
484
|
-
if (!isDir) {
|
|
485
|
-
throw isWindows ? "no-entry" : "not-directory";
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
if (isWindows) {
|
|
489
|
-
if (e.code === "EPERM" || e.code === "EEXIST") {
|
|
490
|
-
throw "no-entry";
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
throw convertFsError(e);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
unlinkFileAt(path) {
|
|
498
|
-
const fullPath = this.#getFullPath(path, false);
|
|
499
|
-
try {
|
|
500
|
-
if (fullPath.endsWith("/")) {
|
|
501
|
-
let isDir = false;
|
|
502
|
-
try {
|
|
503
|
-
isDir = statSync(fullPath).isDirectory();
|
|
504
|
-
} catch {
|
|
505
|
-
//
|
|
506
|
-
}
|
|
507
|
-
throw isDir
|
|
508
|
-
? isWindows
|
|
509
|
-
? "access"
|
|
510
|
-
: isMac
|
|
511
|
-
? "not-permitted"
|
|
512
|
-
: "is-directory"
|
|
513
|
-
: "not-directory";
|
|
514
|
-
}
|
|
515
|
-
unlinkSync(fullPath);
|
|
516
|
-
} catch (e) {
|
|
517
|
-
if (isWindows && e.code === "EPERM") {
|
|
518
|
-
throw "access";
|
|
519
|
-
}
|
|
520
|
-
throw convertFsError(e);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
isSameObject(other) {
|
|
525
|
-
return other === this;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
metadataHash() {
|
|
529
|
-
if (this.#hostPreopen) {
|
|
530
|
-
return { upper: 0n, lower: BigInt(this._id) };
|
|
531
|
-
}
|
|
532
|
-
try {
|
|
533
|
-
const stats = fstatSync(this.#fd, { bigint: true });
|
|
534
|
-
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
535
|
-
} catch (e) {
|
|
536
|
-
throw convertFsError(e);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
metadataHashAt(pathFlags, path) {
|
|
541
|
-
const fullPath = this.#getFullPath(path, false);
|
|
542
|
-
try {
|
|
543
|
-
const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(fullPath, {
|
|
544
|
-
bigint: true,
|
|
545
|
-
});
|
|
546
|
-
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
547
|
-
} catch (e) {
|
|
548
|
-
throw convertFsError(e);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// TODO: support followSymlinks
|
|
553
|
-
#getFullPath(subpath, _followSymlinks) {
|
|
554
|
-
let descriptor = this;
|
|
555
|
-
if (subpath.indexOf("\\") !== -1) {
|
|
556
|
-
subpath = subpath.replace(/\\/g, "/");
|
|
557
|
-
}
|
|
558
|
-
if (subpath.indexOf("//") !== -1) {
|
|
559
|
-
subpath = subpath.replace(/\/\/+/g, "/");
|
|
560
|
-
}
|
|
561
|
-
if (subpath[0] === "/") {
|
|
562
|
-
throw "not-permitted";
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// segment resolution
|
|
566
|
-
const segments = [];
|
|
567
|
-
let segmentIndex = -1;
|
|
568
|
-
for (let i = 0; i < subpath.length; i++) {
|
|
569
|
-
// busy reading a segment - only terminate on '/'
|
|
570
|
-
if (segmentIndex !== -1) {
|
|
571
|
-
if (subpath[i] === "/") {
|
|
572
|
-
segments.push(subpath.slice(segmentIndex, i + 1));
|
|
573
|
-
segmentIndex = -1;
|
|
574
|
-
}
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
// new segment - check if it is relative
|
|
578
|
-
else if (subpath[i] === ".") {
|
|
579
|
-
// ../ segment
|
|
580
|
-
if (subpath[i + 1] === "." && (subpath[i + 2] === "/" || i + 2 === subpath.length)) {
|
|
581
|
-
if (segments.pop() === undefined) {
|
|
582
|
-
throw "not-permitted";
|
|
583
|
-
}
|
|
584
|
-
i += 2;
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
// ./ segment
|
|
588
|
-
else if (subpath[i + 1] === "/" || i + 1 === subpath.length) {
|
|
589
|
-
i += 1;
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
// it is the start of a new segment
|
|
594
|
-
while (subpath[i] === "/") {
|
|
595
|
-
i++;
|
|
596
|
-
}
|
|
597
|
-
segmentIndex = i;
|
|
598
|
-
}
|
|
599
|
-
// finish reading out the last segment
|
|
600
|
-
if (segmentIndex !== -1) {
|
|
601
|
-
segments.push(subpath.slice(segmentIndex));
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
subpath = segments.join("");
|
|
605
|
-
|
|
606
|
-
if (descriptor.#hostPreopen) {
|
|
607
|
-
return (
|
|
608
|
-
descriptor.#hostPreopen +
|
|
609
|
-
(descriptor.#hostPreopen.endsWith("/") ? "" : subpath.length > 0 ? "/" : "") +
|
|
610
|
-
subpath
|
|
611
|
-
);
|
|
612
|
-
}
|
|
613
|
-
return descriptor.#fullPath + (subpath.length > 0 ? "/" : "") + subpath;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
const descriptorCreatePreopen = Descriptor._createPreopen;
|
|
617
|
-
delete Descriptor._createPreopen;
|
|
618
|
-
const descriptorCreate = Descriptor._create;
|
|
619
|
-
delete Descriptor._create;
|
|
620
|
-
|
|
621
|
-
class DirectoryEntryStream {
|
|
622
|
-
#dir;
|
|
623
|
-
#finalizer;
|
|
624
|
-
readDirectoryEntry() {
|
|
625
|
-
let entry;
|
|
626
|
-
try {
|
|
627
|
-
entry = this.#dir.readSync();
|
|
628
|
-
} catch (e) {
|
|
629
|
-
throw convertFsError(e);
|
|
630
|
-
}
|
|
631
|
-
if (entry === null) {
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
const name = entry.name;
|
|
635
|
-
const type = lookupType(entry);
|
|
636
|
-
return { name, type };
|
|
637
|
-
}
|
|
638
|
-
static _create(dir) {
|
|
639
|
-
const dirStream = new DirectoryEntryStream();
|
|
640
|
-
dirStream.#finalizer = registerDispose(dirStream, null, null, dir.closeSync.bind(dir));
|
|
641
|
-
dirStream.#dir = dir;
|
|
642
|
-
return dirStream;
|
|
643
|
-
}
|
|
644
|
-
[symbolDispose]() {
|
|
645
|
-
if (this.#finalizer) {
|
|
646
|
-
earlyDispose(this.#finalizer);
|
|
647
|
-
this.#finalizer = null;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
const directoryEntryStreamCreate = DirectoryEntryStream._create;
|
|
652
|
-
delete DirectoryEntryStream._create;
|
|
653
|
-
|
|
654
|
-
let preopenEntries = [];
|
|
655
|
-
|
|
656
|
-
export const preopens = {
|
|
657
|
-
Descriptor,
|
|
658
|
-
getDirectories() {
|
|
659
|
-
return preopenEntries;
|
|
660
|
-
},
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
_addPreopen("/", isWindows ? "//" : "/");
|
|
664
|
-
|
|
665
|
-
export const types = {
|
|
666
|
-
Descriptor,
|
|
667
|
-
DirectoryEntryStream,
|
|
668
|
-
filesystemErrorCode(err) {
|
|
669
|
-
return convertFsError(err.payload);
|
|
670
|
-
},
|
|
671
|
-
};
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Replace all preopens with the given set.
|
|
675
|
-
* @param {Record<string, string>} preopens - Map of virtual paths to host paths
|
|
676
|
-
*/
|
|
677
|
-
export function _setPreopens(preopens) {
|
|
678
|
-
preopenEntries = [];
|
|
679
|
-
for (const [virtualPath, hostPreopen] of Object.entries(preopens)) {
|
|
680
|
-
_addPreopen(virtualPath, hostPreopen);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
/**
|
|
685
|
-
* Add a single preopen mapping.
|
|
686
|
-
* @param {string} virtualPath - The virtual path visible to the guest
|
|
687
|
-
* @param {string} hostPreopen - The host filesystem path
|
|
688
|
-
*/
|
|
689
|
-
export function _addPreopen(virtualPath, hostPreopen) {
|
|
690
|
-
const preopenEntry = [descriptorCreatePreopen(hostPreopen), virtualPath];
|
|
691
|
-
preopenEntries.push(preopenEntry);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Clear all preopens, giving the guest no filesystem access.
|
|
696
|
-
* Call this immediately after import to disable default full filesystem access.
|
|
697
|
-
*
|
|
698
|
-
* @example
|
|
699
|
-
* import { _clearPreopens } from '@bytecodealliance/preview2-shim/filesystem';
|
|
700
|
-
* _clearPreopens(); // Now guest has no filesystem access by default
|
|
701
|
-
*/
|
|
702
|
-
export function _clearPreopens() {
|
|
703
|
-
preopenEntries = [];
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* Get current preopens configuration.
|
|
708
|
-
* @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
|
|
709
|
-
*/
|
|
710
|
-
export function _getPreopens() {
|
|
711
|
-
return [...preopenEntries];
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
* Create a preopen descriptor for a host path.
|
|
716
|
-
* This is used internally to create isolated preopen instances.
|
|
717
|
-
* @param {string} hostPreopen - The host filesystem path
|
|
718
|
-
* @returns {Descriptor} A preopen descriptor
|
|
719
|
-
*/
|
|
720
|
-
export function _createPreopenDescriptor(hostPreopen) {
|
|
721
|
-
return descriptorCreatePreopen(hostPreopen);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function convertFsError(e) {
|
|
725
|
-
switch (e.code) {
|
|
726
|
-
case "EACCES":
|
|
727
|
-
return "access";
|
|
728
|
-
case "EAGAIN":
|
|
729
|
-
case "EWOULDBLOCK":
|
|
730
|
-
return "would-block";
|
|
731
|
-
case "EALREADY":
|
|
732
|
-
return "already";
|
|
733
|
-
case "EBADF":
|
|
734
|
-
return "bad-descriptor";
|
|
735
|
-
case "EBUSY":
|
|
736
|
-
return "busy";
|
|
737
|
-
case "EDEADLK":
|
|
738
|
-
return "deadlock";
|
|
739
|
-
case "EDQUOT":
|
|
740
|
-
return "quota";
|
|
741
|
-
case "EEXIST":
|
|
742
|
-
return "exist";
|
|
743
|
-
case "EFBIG":
|
|
744
|
-
return "file-too-large";
|
|
745
|
-
case "EILSEQ":
|
|
746
|
-
return "illegal-byte-sequence";
|
|
747
|
-
case "EINPROGRESS":
|
|
748
|
-
return "in-progress";
|
|
749
|
-
case "EINTR":
|
|
750
|
-
return "interrupted";
|
|
751
|
-
case "EINVAL":
|
|
752
|
-
return "invalid";
|
|
753
|
-
case "EIO":
|
|
754
|
-
return "io";
|
|
755
|
-
case "EISDIR":
|
|
756
|
-
return "is-directory";
|
|
757
|
-
case "ELOOP":
|
|
758
|
-
return "loop";
|
|
759
|
-
case "EMLINK":
|
|
760
|
-
return "too-many-links";
|
|
761
|
-
case "EMSGSIZE":
|
|
762
|
-
return "message-size";
|
|
763
|
-
case "ENAMETOOLONG":
|
|
764
|
-
return "name-too-long";
|
|
765
|
-
case "ENODEV":
|
|
766
|
-
return "no-device";
|
|
767
|
-
case "ENOENT":
|
|
768
|
-
return "no-entry";
|
|
769
|
-
case "ENOLCK":
|
|
770
|
-
return "no-lock";
|
|
771
|
-
case "ENOMEM":
|
|
772
|
-
return "insufficient-memory";
|
|
773
|
-
case "ENOSPC":
|
|
774
|
-
return "insufficient-space";
|
|
775
|
-
case "ENOTDIR":
|
|
776
|
-
case "ERR_FS_EISDIR":
|
|
777
|
-
return "not-directory";
|
|
778
|
-
case "ENOTEMPTY":
|
|
779
|
-
return "not-empty";
|
|
780
|
-
case "ENOTRECOVERABLE":
|
|
781
|
-
return "not-recoverable";
|
|
782
|
-
case "ENOTSUP":
|
|
783
|
-
return "unsupported";
|
|
784
|
-
case "ENOTTY":
|
|
785
|
-
return "no-tty";
|
|
786
|
-
// windows gives this error for badly structured `//` reads
|
|
787
|
-
// this seems like a slightly better error than unknown given
|
|
788
|
-
// that it's a common footgun
|
|
789
|
-
case -4094:
|
|
790
|
-
case "ENXIO":
|
|
791
|
-
return "no-such-device";
|
|
792
|
-
case "EOVERFLOW":
|
|
793
|
-
return "overflow";
|
|
794
|
-
case "EPERM":
|
|
795
|
-
return "not-permitted";
|
|
796
|
-
case "EPIPE":
|
|
797
|
-
return "pipe";
|
|
798
|
-
case "EROFS":
|
|
799
|
-
return "read-only";
|
|
800
|
-
case "ESPIPE":
|
|
801
|
-
return "invalid-seek";
|
|
802
|
-
case "ETXTBSY":
|
|
803
|
-
return "text-file-busy";
|
|
804
|
-
case "EXDEV":
|
|
805
|
-
return "cross-device";
|
|
806
|
-
case "UNKNOWN":
|
|
807
|
-
switch (e.errno) {
|
|
808
|
-
case -4094:
|
|
809
|
-
return "no-such-device";
|
|
810
|
-
default:
|
|
811
|
-
throw e;
|
|
812
|
-
}
|
|
813
|
-
default:
|
|
814
|
-
throw e;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
function timestampToMs(timestamp) {
|
|
819
|
-
let secondsInMillis = timestamp.seconds * 1000n;
|
|
820
|
-
if (secondsInMillis > Number.MAX_SAFE_INTEGER) {
|
|
821
|
-
throw new Error(`cannot represent millisecond amount as Number [${{ nanosInMillis }}]`);
|
|
822
|
-
}
|
|
823
|
-
if (timestamp.nanoseconds > Number.MAX_SAFE_INTEGER) {
|
|
824
|
-
throw new Error(`cannot represent millisecond amount as Number [${{ nanosInMillis }}]`);
|
|
825
|
-
}
|
|
826
|
-
let remainderFractionalMillis = timestamp.nanoseconds / 1_000_000;
|
|
827
|
-
const res = Number(secondsInMillis) + remainderFractionalMillis;
|
|
828
|
-
return res;
|
|
829
|
-
}
|