@bytecodealliance/preview2-shim 0.17.7 → 0.17.9
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 +18 -18
- package/lib/browser/cli.js +71 -71
- package/lib/browser/clocks.js +34 -30
- package/lib/browser/config.js +3 -3
- package/lib/browser/environment.js +15 -15
- package/lib/browser/filesystem.js +382 -396
- package/lib/browser/http.js +683 -144
- package/lib/browser/index.js +7 -7
- package/lib/browser/io.js +199 -133
- package/lib/browser/random.js +42 -44
- package/lib/browser/sockets.js +52 -52
- package/lib/common/instantiation.js +147 -151
- package/lib/io/calls.js +7 -9
- package/lib/io/worker-http.js +167 -178
- package/lib/io/worker-io.js +338 -406
- package/lib/io/worker-socket-tcp.js +259 -271
- package/lib/io/worker-socket-udp.js +437 -491
- package/lib/io/worker-sockets.js +230 -251
- package/lib/io/worker-thread.js +774 -822
- package/lib/nodejs/cli.js +53 -65
- package/lib/nodejs/clocks.js +49 -52
- package/lib/nodejs/filesystem.js +726 -785
- package/lib/nodejs/http.js +651 -697
- package/lib/nodejs/index.js +7 -7
- package/lib/nodejs/io.js +1 -1
- package/lib/nodejs/random.js +32 -32
- package/lib/nodejs/sockets.js +468 -538
- package/lib/synckit/index.js +85 -94
- package/package.json +11 -10
package/lib/nodejs/filesystem.js
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from
|
|
8
|
-
import { INPUT_STREAM_CREATE, OUTPUT_STREAM_CREATE } from
|
|
9
|
-
import { FILE } from
|
|
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
10
|
import nodeFs, {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from
|
|
33
|
-
import { platform } from
|
|
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
34
|
|
|
35
35
|
const lutimesSync = nodeFs.lutimesSync;
|
|
36
36
|
|
|
37
|
-
const symbolDispose = Symbol.dispose || Symbol.for(
|
|
37
|
+
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
38
38
|
|
|
39
|
-
const isWindows = platform ===
|
|
40
|
-
const isMac = platform ===
|
|
39
|
+
const isWindows = platform === "win32";
|
|
40
|
+
const isMac = platform === "darwin";
|
|
41
41
|
|
|
42
|
-
const nsMagnitude =
|
|
42
|
+
const nsMagnitude = 1_000_000_000n;
|
|
43
43
|
function nsToDateTime(ns) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const seconds = ns / nsMagnitude;
|
|
45
|
+
const nanoseconds = Number(ns % nsMagnitude);
|
|
46
|
+
return { seconds, nanoseconds };
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function lookupType(obj) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
66
|
}
|
|
67
67
|
|
|
68
68
|
// Note: This should implement per-segment semantics of openAt, but we cannot
|
|
@@ -73,608 +73,545 @@ function lookupType(obj) {
|
|
|
73
73
|
* @implements {DescriptorProps}
|
|
74
74
|
*/
|
|
75
75
|
class Descriptor {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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;
|
|
158
398
|
try {
|
|
159
|
-
|
|
160
|
-
} catch
|
|
161
|
-
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
throw convertFsError(e);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
getFlags() {
|
|
169
|
-
return this.#mode;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
getType() {
|
|
173
|
-
if (this.#hostPreopen) {
|
|
174
|
-
return 'directory';
|
|
399
|
+
isSymlink = lstatSync(fullPath).isSymbolicLink();
|
|
400
|
+
} catch {
|
|
401
|
+
//
|
|
175
402
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
setSize(size) {
|
|
181
|
-
if (this.#hostPreopen) {
|
|
182
|
-
throw 'is-directory';
|
|
403
|
+
if (isSymlink) {
|
|
404
|
+
throw openFlags.directory ? "not-directory" : "loop";
|
|
183
405
|
}
|
|
406
|
+
}
|
|
407
|
+
if (pathFlags.symlinkFollow && openFlags.directory) {
|
|
408
|
+
let isFile = false;
|
|
184
409
|
try {
|
|
185
|
-
|
|
186
|
-
} catch
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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;
|
|
214
479
|
try {
|
|
215
|
-
|
|
216
|
-
} catch
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
#getNewTimestamp(newTimestamp, maybeNow) {
|
|
222
|
-
switch (newTimestamp.tag) {
|
|
223
|
-
case 'no-change':
|
|
224
|
-
return timestampToMs(maybeNow);
|
|
225
|
-
case 'now':
|
|
226
|
-
return Math.floor(Date.now() / 1e3);
|
|
227
|
-
case 'timestamp':
|
|
228
|
-
return timestampToMs(newTimestamp.val);
|
|
480
|
+
isDir = statSync(fullPath).isDirectory();
|
|
481
|
+
} catch {
|
|
482
|
+
//
|
|
229
483
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
read(length, offset) {
|
|
233
|
-
if (!this.#fullPath) {
|
|
234
|
-
throw 'bad-descriptor';
|
|
484
|
+
if (!isDir) {
|
|
485
|
+
throw isWindows ? "no-entry" : "not-directory";
|
|
235
486
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
0,
|
|
241
|
-
Number(length),
|
|
242
|
-
Number(offset)
|
|
243
|
-
);
|
|
244
|
-
const out = new Uint8Array(buf.buffer, 0, bytesRead);
|
|
245
|
-
return [out, bytesRead === 0 ? 'ended' : 'open'];
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
write(buffer, offset) {
|
|
249
|
-
if (!this.#fullPath) {
|
|
250
|
-
throw 'bad-descriptor';
|
|
487
|
+
}
|
|
488
|
+
if (isWindows) {
|
|
489
|
+
if (e.code === "EPERM" || e.code === "EEXIST") {
|
|
490
|
+
throw "no-entry";
|
|
251
491
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
);
|
|
492
|
+
}
|
|
493
|
+
throw convertFsError(e);
|
|
255
494
|
}
|
|
495
|
+
}
|
|
256
496
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
497
|
+
unlinkFileAt(path) {
|
|
498
|
+
const fullPath = this.#getFullPath(path, false);
|
|
499
|
+
try {
|
|
500
|
+
if (fullPath.endsWith("/")) {
|
|
501
|
+
let isDir = false;
|
|
261
502
|
try {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const oldFullPath = this.#getFullPath(
|
|
375
|
-
oldPath,
|
|
376
|
-
oldPathFlags.symlinkFollow
|
|
377
|
-
);
|
|
378
|
-
const newFullPath = newDescriptor.#getFullPath(newPath, false);
|
|
379
|
-
// Windows doesn't automatically fail on trailing slashes
|
|
380
|
-
if (isWindows && newFullPath.endsWith('/')) {
|
|
381
|
-
throw 'no-entry';
|
|
382
|
-
}
|
|
383
|
-
try {
|
|
384
|
-
linkSync(oldFullPath, newFullPath);
|
|
385
|
-
} catch (e) {
|
|
386
|
-
throw convertFsError(e);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
openAt(pathFlags, path, openFlags, descriptorFlags) {
|
|
391
|
-
if (preopenEntries.length === 0) {
|
|
392
|
-
throw 'access';
|
|
393
|
-
}
|
|
394
|
-
const fullPath = this.#getFullPath(path, pathFlags.symlinkFollow);
|
|
395
|
-
let fsOpenFlags = 0x0;
|
|
396
|
-
if (openFlags.create) {
|
|
397
|
-
fsOpenFlags |= constants.O_CREAT;
|
|
398
|
-
}
|
|
399
|
-
if (openFlags.directory) {
|
|
400
|
-
fsOpenFlags |= constants.O_DIRECTORY;
|
|
401
|
-
}
|
|
402
|
-
if (openFlags.exclusive) {
|
|
403
|
-
fsOpenFlags |= constants.O_EXCL;
|
|
404
|
-
}
|
|
405
|
-
if (openFlags.truncate) {
|
|
406
|
-
fsOpenFlags |= constants.O_TRUNC;
|
|
407
|
-
}
|
|
408
|
-
if (descriptorFlags.read && descriptorFlags.write) {
|
|
409
|
-
fsOpenFlags |= constants.O_RDWR;
|
|
410
|
-
} else if (descriptorFlags.write) {
|
|
411
|
-
fsOpenFlags |= constants.O_WRONLY;
|
|
412
|
-
} else if (descriptorFlags.read) {
|
|
413
|
-
fsOpenFlags |= constants.O_RDONLY;
|
|
414
|
-
}
|
|
415
|
-
if (descriptorFlags.fileIntegritySync) {
|
|
416
|
-
fsOpenFlags |= constants.O_SYNC;
|
|
417
|
-
}
|
|
418
|
-
if (descriptorFlags.dataIntegritySync) {
|
|
419
|
-
fsOpenFlags |= constants.O_DSYNC;
|
|
420
|
-
}
|
|
421
|
-
if (!pathFlags.symlinkFollow) {
|
|
422
|
-
fsOpenFlags |= constants.O_NOFOLLOW;
|
|
423
|
-
}
|
|
424
|
-
if (
|
|
425
|
-
descriptorFlags.requestedWriteSync ||
|
|
426
|
-
descriptorFlags.mutateDirectory
|
|
427
|
-
) {
|
|
428
|
-
throw 'unsupported';
|
|
429
|
-
}
|
|
430
|
-
// Currently throw to match Wasmtime
|
|
431
|
-
if (
|
|
432
|
-
descriptorFlags.fileIntegritySync ||
|
|
433
|
-
descriptorFlags.dataIntegritySync
|
|
434
|
-
) {
|
|
435
|
-
throw 'unsupported';
|
|
436
|
-
}
|
|
437
|
-
if (isWindows) {
|
|
438
|
-
if (!pathFlags.symlinkFollow && !openFlags.create) {
|
|
439
|
-
let isSymlink = false;
|
|
440
|
-
try {
|
|
441
|
-
isSymlink = lstatSync(fullPath).isSymbolicLink();
|
|
442
|
-
} catch {
|
|
443
|
-
//
|
|
444
|
-
}
|
|
445
|
-
if (isSymlink) {
|
|
446
|
-
throw openFlags.directory ? 'not-directory' : 'loop';
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
if (pathFlags.symlinkFollow && openFlags.directory) {
|
|
450
|
-
let isFile = false;
|
|
451
|
-
try {
|
|
452
|
-
isFile = !statSync(fullPath).isDirectory();
|
|
453
|
-
} catch {
|
|
454
|
-
//
|
|
455
|
-
}
|
|
456
|
-
if (isFile) {
|
|
457
|
-
throw 'not-directory';
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
try {
|
|
462
|
-
const fd = openSync(
|
|
463
|
-
fullPath.endsWith('/') ? fullPath.slice(0, -1) : fullPath,
|
|
464
|
-
fsOpenFlags
|
|
465
|
-
);
|
|
466
|
-
const descriptor = descriptorCreate(
|
|
467
|
-
fd,
|
|
468
|
-
descriptorFlags,
|
|
469
|
-
fullPath,
|
|
470
|
-
preopenEntries
|
|
471
|
-
);
|
|
472
|
-
if (
|
|
473
|
-
fullPath.endsWith('/') &&
|
|
474
|
-
descriptor.getType() !== 'directory'
|
|
475
|
-
) {
|
|
476
|
-
descriptor[symbolDispose]();
|
|
477
|
-
throw 'not-directory';
|
|
478
|
-
}
|
|
479
|
-
return descriptor;
|
|
480
|
-
} catch (e) {
|
|
481
|
-
if (e.code === 'ERR_INVALID_ARG_VALUE') {
|
|
482
|
-
throw isWindows ? 'no-entry' : 'invalid';
|
|
483
|
-
}
|
|
484
|
-
throw convertFsError(e);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
readlinkAt(path) {
|
|
489
|
-
const fullPath = this.#getFullPath(path, false);
|
|
490
|
-
try {
|
|
491
|
-
return readlinkSync(fullPath);
|
|
492
|
-
} catch (e) {
|
|
493
|
-
throw convertFsError(e);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
removeDirectoryAt(path) {
|
|
498
|
-
const fullPath = this.#getFullPath(path, false);
|
|
499
|
-
try {
|
|
500
|
-
rmdirSync(fullPath);
|
|
501
|
-
} catch (e) {
|
|
502
|
-
if (isWindows && e.code === 'ENOENT') {
|
|
503
|
-
throw 'not-directory';
|
|
504
|
-
}
|
|
505
|
-
throw convertFsError(e);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
renameAt(oldPath, newDescriptor, newPath) {
|
|
510
|
-
const oldFullPath = this.#getFullPath(oldPath, false);
|
|
511
|
-
const newFullPath = newDescriptor.#getFullPath(newPath, false);
|
|
512
|
-
try {
|
|
513
|
-
renameSync(oldFullPath, newFullPath);
|
|
514
|
-
} catch (e) {
|
|
515
|
-
if (isWindows && e.code === 'EPERM') {
|
|
516
|
-
throw 'access';
|
|
517
|
-
}
|
|
518
|
-
throw convertFsError(e);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
symlinkAt(target, path) {
|
|
523
|
-
const fullPath = this.#getFullPath(path, false);
|
|
524
|
-
if (target.startsWith('/')) {
|
|
525
|
-
throw 'not-permitted';
|
|
526
|
-
}
|
|
527
|
-
try {
|
|
528
|
-
symlinkSync(target, fullPath);
|
|
529
|
-
} catch (e) {
|
|
530
|
-
if (fullPath.endsWith('/') && e.code === 'EEXIST') {
|
|
531
|
-
let isDir = false;
|
|
532
|
-
try {
|
|
533
|
-
isDir = statSync(fullPath).isDirectory();
|
|
534
|
-
} catch {
|
|
535
|
-
//
|
|
536
|
-
}
|
|
537
|
-
if (!isDir) {
|
|
538
|
-
throw isWindows ? 'no-entry' : 'not-directory';
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
if (isWindows) {
|
|
542
|
-
if (e.code === 'EPERM' || e.code === 'EEXIST') {
|
|
543
|
-
throw 'no-entry';
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
throw convertFsError(e);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
unlinkFileAt(path) {
|
|
551
|
-
const fullPath = this.#getFullPath(path, false);
|
|
552
|
-
try {
|
|
553
|
-
if (fullPath.endsWith('/')) {
|
|
554
|
-
let isDir = false;
|
|
555
|
-
try {
|
|
556
|
-
isDir = statSync(fullPath).isDirectory();
|
|
557
|
-
} catch {
|
|
558
|
-
//
|
|
559
|
-
}
|
|
560
|
-
throw isDir
|
|
561
|
-
? isWindows
|
|
562
|
-
? 'access'
|
|
563
|
-
: isMac
|
|
564
|
-
? 'not-permitted'
|
|
565
|
-
: 'is-directory'
|
|
566
|
-
: 'not-directory';
|
|
567
|
-
}
|
|
568
|
-
unlinkSync(fullPath);
|
|
569
|
-
} catch (e) {
|
|
570
|
-
if (isWindows && e.code === 'EPERM') {
|
|
571
|
-
throw 'access';
|
|
572
|
-
}
|
|
573
|
-
throw convertFsError(e);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
isSameObject(other) {
|
|
578
|
-
return other === this;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
metadataHash() {
|
|
582
|
-
if (this.#hostPreopen) {
|
|
583
|
-
return { upper: 0n, lower: BigInt(this._id) };
|
|
584
|
-
}
|
|
585
|
-
try {
|
|
586
|
-
const stats = fstatSync(this.#fd, { bigint: true });
|
|
587
|
-
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
588
|
-
} catch (e) {
|
|
589
|
-
throw convertFsError(e);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
metadataHashAt(pathFlags, path) {
|
|
594
|
-
const fullPath = this.#getFullPath(path, false);
|
|
595
|
-
try {
|
|
596
|
-
const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(
|
|
597
|
-
fullPath,
|
|
598
|
-
{
|
|
599
|
-
bigint: true,
|
|
600
|
-
}
|
|
601
|
-
);
|
|
602
|
-
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
603
|
-
} catch (e) {
|
|
604
|
-
throw convertFsError(e);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// TODO: support followSymlinks
|
|
609
|
-
#getFullPath(subpath, _followSymlinks) {
|
|
610
|
-
let descriptor = this;
|
|
611
|
-
if (subpath.indexOf('\\') !== -1) {
|
|
612
|
-
subpath = subpath.replace(/\\/g, '/');
|
|
613
|
-
}
|
|
614
|
-
if (subpath.indexOf('//') !== -1) {
|
|
615
|
-
subpath = subpath.replace(/\/\/+/g, '/');
|
|
616
|
-
}
|
|
617
|
-
if (subpath[0] === '/') {
|
|
618
|
-
throw 'not-permitted';
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// segment resolution
|
|
622
|
-
const segments = [];
|
|
623
|
-
let segmentIndex = -1;
|
|
624
|
-
for (let i = 0; i < subpath.length; i++) {
|
|
625
|
-
// busy reading a segment - only terminate on '/'
|
|
626
|
-
if (segmentIndex !== -1) {
|
|
627
|
-
if (subpath[i] === '/') {
|
|
628
|
-
segments.push(subpath.slice(segmentIndex, i + 1));
|
|
629
|
-
segmentIndex = -1;
|
|
630
|
-
}
|
|
631
|
-
continue;
|
|
632
|
-
}
|
|
633
|
-
// new segment - check if it is relative
|
|
634
|
-
else if (subpath[i] === '.') {
|
|
635
|
-
// ../ segment
|
|
636
|
-
if (
|
|
637
|
-
subpath[i + 1] === '.' &&
|
|
638
|
-
(subpath[i + 2] === '/' || i + 2 === subpath.length)
|
|
639
|
-
) {
|
|
640
|
-
if (segments.pop() === undefined) {
|
|
641
|
-
throw 'not-permitted';
|
|
642
|
-
}
|
|
643
|
-
i += 2;
|
|
644
|
-
continue;
|
|
645
|
-
}
|
|
646
|
-
// ./ segment
|
|
647
|
-
else if (subpath[i + 1] === '/' || i + 1 === subpath.length) {
|
|
648
|
-
i += 1;
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
// it is the start of a new segment
|
|
653
|
-
while (subpath[i] === '/') {
|
|
654
|
-
i++;
|
|
655
|
-
}
|
|
656
|
-
segmentIndex = i;
|
|
657
|
-
}
|
|
658
|
-
// finish reading out the last segment
|
|
659
|
-
if (segmentIndex !== -1) {
|
|
660
|
-
segments.push(subpath.slice(segmentIndex));
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
subpath = segments.join('');
|
|
664
|
-
|
|
665
|
-
if (descriptor.#hostPreopen) {
|
|
666
|
-
return (
|
|
667
|
-
descriptor.#hostPreopen +
|
|
668
|
-
(descriptor.#hostPreopen.endsWith('/')
|
|
669
|
-
? ''
|
|
670
|
-
: subpath.length > 0
|
|
671
|
-
? '/'
|
|
672
|
-
: '') +
|
|
673
|
-
subpath
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
return descriptor.#fullPath + (subpath.length > 0 ? '/' : '') + subpath;
|
|
677
|
-
}
|
|
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
|
+
}
|
|
678
615
|
}
|
|
679
616
|
const descriptorCreatePreopen = Descriptor._createPreopen;
|
|
680
617
|
delete Descriptor._createPreopen;
|
|
@@ -682,39 +619,34 @@ const descriptorCreate = Descriptor._create;
|
|
|
682
619
|
delete Descriptor._create;
|
|
683
620
|
|
|
684
621
|
class DirectoryEntryStream {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
if (this.#finalizer) {
|
|
714
|
-
earlyDispose(this.#finalizer);
|
|
715
|
-
this.#finalizer = null;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
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
|
+
}
|
|
718
650
|
}
|
|
719
651
|
const directoryEntryStreamCreate = DirectoryEntryStream._create;
|
|
720
652
|
delete DirectoryEntryStream._create;
|
|
@@ -722,20 +654,20 @@ delete DirectoryEntryStream._create;
|
|
|
722
654
|
let preopenEntries = [];
|
|
723
655
|
|
|
724
656
|
export const preopens = {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
657
|
+
Descriptor,
|
|
658
|
+
getDirectories() {
|
|
659
|
+
return preopenEntries;
|
|
660
|
+
},
|
|
729
661
|
};
|
|
730
662
|
|
|
731
|
-
_addPreopen(
|
|
663
|
+
_addPreopen("/", isWindows ? "//" : "/");
|
|
732
664
|
|
|
733
665
|
export const types = {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
666
|
+
Descriptor,
|
|
667
|
+
DirectoryEntryStream,
|
|
668
|
+
filesystemErrorCode(err) {
|
|
669
|
+
return convertFsError(err.payload);
|
|
670
|
+
},
|
|
739
671
|
};
|
|
740
672
|
|
|
741
673
|
/**
|
|
@@ -743,10 +675,10 @@ export const types = {
|
|
|
743
675
|
* @param {Record<string, string>} preopens - Map of virtual paths to host paths
|
|
744
676
|
*/
|
|
745
677
|
export function _setPreopens(preopens) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
678
|
+
preopenEntries = [];
|
|
679
|
+
for (const [virtualPath, hostPreopen] of Object.entries(preopens)) {
|
|
680
|
+
_addPreopen(virtualPath, hostPreopen);
|
|
681
|
+
}
|
|
750
682
|
}
|
|
751
683
|
|
|
752
684
|
/**
|
|
@@ -755,8 +687,8 @@ export function _setPreopens(preopens) {
|
|
|
755
687
|
* @param {string} hostPreopen - The host filesystem path
|
|
756
688
|
*/
|
|
757
689
|
export function _addPreopen(virtualPath, hostPreopen) {
|
|
758
|
-
|
|
759
|
-
|
|
690
|
+
const preopenEntry = [descriptorCreatePreopen(hostPreopen), virtualPath];
|
|
691
|
+
preopenEntries.push(preopenEntry);
|
|
760
692
|
}
|
|
761
693
|
|
|
762
694
|
/**
|
|
@@ -768,7 +700,7 @@ export function _addPreopen(virtualPath, hostPreopen) {
|
|
|
768
700
|
* _clearPreopens(); // Now guest has no filesystem access by default
|
|
769
701
|
*/
|
|
770
702
|
export function _clearPreopens() {
|
|
771
|
-
|
|
703
|
+
preopenEntries = [];
|
|
772
704
|
}
|
|
773
705
|
|
|
774
706
|
/**
|
|
@@ -776,7 +708,7 @@ export function _clearPreopens() {
|
|
|
776
708
|
* @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
|
|
777
709
|
*/
|
|
778
710
|
export function _getPreopens() {
|
|
779
|
-
|
|
711
|
+
return [...preopenEntries];
|
|
780
712
|
}
|
|
781
713
|
|
|
782
714
|
/**
|
|
@@ -786,103 +718,112 @@ export function _getPreopens() {
|
|
|
786
718
|
* @returns {Descriptor} A preopen descriptor
|
|
787
719
|
*/
|
|
788
720
|
export function _createPreopenDescriptor(hostPreopen) {
|
|
789
|
-
|
|
721
|
+
return descriptorCreatePreopen(hostPreopen);
|
|
790
722
|
}
|
|
791
723
|
|
|
792
724
|
function convertFsError(e) {
|
|
793
|
-
|
|
794
|
-
case
|
|
795
|
-
|
|
796
|
-
case
|
|
797
|
-
case
|
|
798
|
-
|
|
799
|
-
case
|
|
800
|
-
|
|
801
|
-
case
|
|
802
|
-
|
|
803
|
-
case
|
|
804
|
-
|
|
805
|
-
case
|
|
806
|
-
|
|
807
|
-
case
|
|
808
|
-
|
|
809
|
-
case
|
|
810
|
-
|
|
811
|
-
case
|
|
812
|
-
|
|
813
|
-
case
|
|
814
|
-
|
|
815
|
-
case
|
|
816
|
-
|
|
817
|
-
case
|
|
818
|
-
|
|
819
|
-
case
|
|
820
|
-
|
|
821
|
-
case
|
|
822
|
-
|
|
823
|
-
case
|
|
824
|
-
|
|
825
|
-
case
|
|
826
|
-
|
|
827
|
-
case
|
|
828
|
-
|
|
829
|
-
case
|
|
830
|
-
|
|
831
|
-
case
|
|
832
|
-
|
|
833
|
-
case
|
|
834
|
-
|
|
835
|
-
case
|
|
836
|
-
|
|
837
|
-
case
|
|
838
|
-
|
|
839
|
-
case
|
|
840
|
-
|
|
841
|
-
case
|
|
842
|
-
|
|
843
|
-
case
|
|
844
|
-
case
|
|
845
|
-
|
|
846
|
-
case
|
|
847
|
-
|
|
848
|
-
case
|
|
849
|
-
|
|
850
|
-
case
|
|
851
|
-
|
|
852
|
-
case
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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
|
|
857
789
|
case -4094:
|
|
858
|
-
case
|
|
859
|
-
|
|
860
|
-
case
|
|
861
|
-
|
|
862
|
-
case
|
|
863
|
-
|
|
864
|
-
case
|
|
865
|
-
|
|
866
|
-
case
|
|
867
|
-
|
|
868
|
-
case
|
|
869
|
-
|
|
870
|
-
case
|
|
871
|
-
|
|
872
|
-
case
|
|
873
|
-
|
|
874
|
-
case
|
|
875
|
-
|
|
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) {
|
|
876
808
|
case -4094:
|
|
877
|
-
|
|
809
|
+
return "no-such-device";
|
|
878
810
|
default:
|
|
879
|
-
|
|
880
|
-
|
|
811
|
+
throw e;
|
|
812
|
+
}
|
|
881
813
|
default:
|
|
882
|
-
|
|
883
|
-
|
|
814
|
+
throw e;
|
|
815
|
+
}
|
|
884
816
|
}
|
|
885
817
|
|
|
886
818
|
function timestampToMs(timestamp) {
|
|
887
|
-
|
|
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;
|
|
888
829
|
}
|