@bytecodealliance/preview2-shim 0.0.20 → 0.0.21
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/lib/browser/cli.js +79 -12
- package/lib/browser/filesystem.js +168 -198
- package/lib/browser/index.js +1 -3
- package/lib/browser/io.js +183 -0
- package/lib/common/io.js +4 -2
- package/lib/nodejs/cli.js +5 -4
- package/lib/nodejs/filesystem.js +106 -73
- package/lib/nodejs/http.js +1 -2
- package/package.json +1 -1
package/lib/browser/cli.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { _setCwd as fsSetCwd } from './filesystem.js';
|
|
2
|
+
import { streams } from './io.js';
|
|
3
|
+
const { InputStream, OutputStream } = streams;
|
|
4
|
+
|
|
5
|
+
const symbolDispose = Symbol.dispose ?? Symbol.for('dispose');
|
|
2
6
|
|
|
3
7
|
let _env = [], _args = [], _cwd = null;
|
|
4
8
|
export function _setEnv (envObj) {
|
|
@@ -38,50 +42,113 @@ export const exit = {
|
|
|
38
42
|
}
|
|
39
43
|
};
|
|
40
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @param {import('../common/io.js').InputStreamHandler} handler
|
|
47
|
+
*/
|
|
48
|
+
export function _setStdin (handler) {
|
|
49
|
+
stdinStream.handler = handler;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* @param {import('../common/io.js').OutputStreamHandler} handler
|
|
53
|
+
*/
|
|
54
|
+
export function _setStderr (handler) {
|
|
55
|
+
stderrStream.handler = handler;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @param {import('../common/io.js').OutputStreamHandler} handler
|
|
59
|
+
*/
|
|
60
|
+
export function _setStdout (handler) {
|
|
61
|
+
stdoutStream.handler = handler;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const stdinStream = new InputStream({
|
|
65
|
+
blockingRead (_len) {
|
|
66
|
+
// TODO
|
|
67
|
+
},
|
|
68
|
+
subscribe () {
|
|
69
|
+
// TODO
|
|
70
|
+
},
|
|
71
|
+
[symbolDispose] () {
|
|
72
|
+
// TODO
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
let textDecoder = new TextDecoder();
|
|
76
|
+
const stdoutStream = new OutputStream({
|
|
77
|
+
write (contents) {
|
|
78
|
+
console.log(textDecoder.decode(contents));
|
|
79
|
+
},
|
|
80
|
+
blockingFlush () {
|
|
81
|
+
},
|
|
82
|
+
[symbolDispose] () {
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const stderrStream = new OutputStream({
|
|
86
|
+
write (contents) {
|
|
87
|
+
console.error(textDecoder.decode(contents));
|
|
88
|
+
},
|
|
89
|
+
blockingFlush () {
|
|
90
|
+
|
|
91
|
+
},
|
|
92
|
+
[symbolDispose] () {
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
41
97
|
export const stdin = {
|
|
98
|
+
InputStream,
|
|
42
99
|
getStdin () {
|
|
43
|
-
return
|
|
100
|
+
return stdinStream;
|
|
44
101
|
}
|
|
45
102
|
};
|
|
46
103
|
|
|
47
104
|
export const stdout = {
|
|
105
|
+
OutputStream,
|
|
48
106
|
getStdout () {
|
|
49
|
-
return
|
|
107
|
+
return stdoutStream;
|
|
50
108
|
}
|
|
51
109
|
};
|
|
52
110
|
|
|
53
111
|
export const stderr = {
|
|
112
|
+
OutputStream,
|
|
54
113
|
getStderr () {
|
|
55
|
-
return
|
|
114
|
+
return stderrStream;
|
|
56
115
|
}
|
|
57
116
|
};
|
|
58
117
|
|
|
59
|
-
|
|
60
|
-
|
|
118
|
+
class TerminalInput {}
|
|
119
|
+
class TerminalOutput {}
|
|
61
120
|
|
|
62
|
-
|
|
121
|
+
const terminalStdoutInstance = new TerminalOutput();
|
|
122
|
+
const terminalStderrInstance = new TerminalOutput();
|
|
123
|
+
const terminalStdinInstance = new TerminalInput();
|
|
124
|
+
|
|
125
|
+
export const terminalInput = {
|
|
126
|
+
TerminalInput,
|
|
127
|
+
dropTerminalInput () {}
|
|
63
128
|
};
|
|
64
129
|
|
|
65
130
|
export const terminalOutput = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
131
|
+
TerminalOutput,
|
|
132
|
+
dropTerminalOutput () {}
|
|
69
133
|
};
|
|
70
134
|
|
|
71
135
|
export const terminalStderr = {
|
|
136
|
+
TerminalOutput,
|
|
72
137
|
getTerminalStderr () {
|
|
73
|
-
return
|
|
138
|
+
return terminalStderrInstance;
|
|
74
139
|
}
|
|
75
140
|
};
|
|
76
141
|
|
|
77
142
|
export const terminalStdin = {
|
|
143
|
+
TerminalInput,
|
|
78
144
|
getTerminalStdin () {
|
|
79
|
-
return
|
|
145
|
+
return terminalStdinInstance;
|
|
80
146
|
}
|
|
81
147
|
};
|
|
82
148
|
|
|
83
149
|
export const terminalStdout = {
|
|
150
|
+
TerminalOutput,
|
|
84
151
|
getTerminalStdout () {
|
|
85
|
-
return
|
|
152
|
+
return terminalStdoutInstance;
|
|
86
153
|
}
|
|
87
154
|
};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { streams } from './io.js';
|
|
2
2
|
import { environment } from './cli.js';
|
|
3
3
|
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
let _preopens = [[3, '/']], _rootPreopen = _preopens[0];
|
|
7
|
-
|
|
8
|
-
export function _setPreopens (preopens) {
|
|
9
|
-
_preopens = preopens;
|
|
10
|
-
descriptorCnt = 3 + _preopens.length;
|
|
11
|
-
_rootPreopen = _preopens.find(preopen => preopen[1] === '/');
|
|
12
|
-
}
|
|
4
|
+
const { InputStream, OutputStream } = streams;
|
|
13
5
|
|
|
14
6
|
let _cwd = null;
|
|
15
7
|
|
|
@@ -19,11 +11,7 @@ export function _setCwd (cwd) {
|
|
|
19
11
|
|
|
20
12
|
export function _setFileData (fileData) {
|
|
21
13
|
_fileData = fileData;
|
|
22
|
-
|
|
23
|
-
const fd = descriptorCnt++;
|
|
24
|
-
descriptorTable[fd] = { entry: fileData[key] };
|
|
25
|
-
return [fd, key];
|
|
26
|
-
}));
|
|
14
|
+
_rootPreopen[0] = new Descriptor(fileData);
|
|
27
15
|
const cwd = environment.initialCwd();
|
|
28
16
|
_setCwd(cwd || '/');
|
|
29
17
|
}
|
|
@@ -32,34 +20,20 @@ export function _getFileData () {
|
|
|
32
20
|
return JSON.stringify(_fileData);
|
|
33
21
|
}
|
|
34
22
|
|
|
35
|
-
let _fileData = {};
|
|
36
|
-
|
|
37
|
-
let descriptorCnt = 4;
|
|
38
|
-
const descriptorTable = {
|
|
39
|
-
0: { stream: 0 },
|
|
40
|
-
1: { stream: 1 },
|
|
41
|
-
2: { stream: 2 },
|
|
42
|
-
3: { entry: { dir: {} } },
|
|
43
|
-
};
|
|
23
|
+
let _fileData = { dir: {} };
|
|
44
24
|
|
|
45
25
|
const timeZero = {
|
|
46
26
|
seconds: BigInt(0),
|
|
47
27
|
nanoseconds: 0
|
|
48
28
|
};
|
|
49
29
|
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
if (!descriptor) throw 'bad-descriptor';
|
|
53
|
-
return descriptor;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getChildEntry (fd, subpath, openFlags) {
|
|
57
|
-
if (subpath === '.' && _rootPreopen && _rootPreopen[0] === fd) {
|
|
30
|
+
function getChildEntry (parentEntry, subpath, openFlags) {
|
|
31
|
+
if (subpath === '.' && _rootPreopen && descriptorGetEntry(_rootPreopen[0]) === parentEntry) {
|
|
58
32
|
subpath = _cwd;
|
|
59
|
-
if (subpath.startsWith('/'))
|
|
33
|
+
if (subpath.startsWith('/') && subpath !== '/')
|
|
60
34
|
subpath = subpath.slice(1);
|
|
61
35
|
}
|
|
62
|
-
let entry =
|
|
36
|
+
let entry = parentEntry;
|
|
63
37
|
let segmentIdx;
|
|
64
38
|
do {
|
|
65
39
|
if (!entry || !entry.dir) throw 'not-directory';
|
|
@@ -76,13 +50,6 @@ function getChildEntry (fd, subpath, openFlags) {
|
|
|
76
50
|
return entry;
|
|
77
51
|
}
|
|
78
52
|
|
|
79
|
-
function createChildDescriptor (fd, subpath, openFlags) {
|
|
80
|
-
const entry = getChildEntry(fd, subpath, openFlags);
|
|
81
|
-
const childFd = descriptorCnt++;
|
|
82
|
-
descriptorTable[childFd] = { entry };
|
|
83
|
-
return childFd;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
53
|
function getSource (fileEntry) {
|
|
87
54
|
if (typeof fileEntry.source === 'string') {
|
|
88
55
|
fileEntry.source = new TextEncoder().encode(fileEntry.source);
|
|
@@ -90,12 +57,12 @@ function getSource (fileEntry) {
|
|
|
90
57
|
return fileEntry.source;
|
|
91
58
|
}
|
|
92
59
|
|
|
93
|
-
class
|
|
60
|
+
class DirectoryEntryStream {
|
|
94
61
|
constructor (entries) {
|
|
95
62
|
this.idx = 0;
|
|
96
63
|
this.entries = entries;
|
|
97
64
|
}
|
|
98
|
-
|
|
65
|
+
readDirectoryEntry () {
|
|
99
66
|
if (this.idx === this.entries.length)
|
|
100
67
|
return null;
|
|
101
68
|
const [name, entry] = this.entries[this.idx];
|
|
@@ -107,117 +74,120 @@ class DirStream {
|
|
|
107
74
|
}
|
|
108
75
|
}
|
|
109
76
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
77
|
+
class Descriptor {
|
|
78
|
+
#stream;
|
|
79
|
+
#entry;
|
|
80
|
+
#mtime = 0;
|
|
81
|
+
|
|
82
|
+
_getEntry (descriptor) {
|
|
83
|
+
return descriptor.#entry;
|
|
113
84
|
}
|
|
114
|
-
}
|
|
115
85
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
86
|
+
constructor (entry, isStream) {
|
|
87
|
+
if (isStream)
|
|
88
|
+
this.#stream = entry;
|
|
89
|
+
else
|
|
90
|
+
this.#entry = entry;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
readViaStream(_offset) {
|
|
94
|
+
const source = getSource(this.#entry);
|
|
95
|
+
let offset = Number(_offset);
|
|
96
|
+
return new InputStream({
|
|
97
|
+
blockingRead (len) {
|
|
98
|
+
if (offset === source.byteLength)
|
|
99
|
+
throw { tag: 'closed' };
|
|
100
|
+
const bytes = source.slice(offset, offset + Number(len));
|
|
101
|
+
offset += bytes.byteLength;
|
|
102
|
+
return bytes;
|
|
127
103
|
}
|
|
128
104
|
});
|
|
129
|
-
}
|
|
105
|
+
}
|
|
130
106
|
|
|
131
|
-
writeViaStream(
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
entry: descriptor.entry,
|
|
107
|
+
writeViaStream(_offset) {
|
|
108
|
+
const entry = this.#entry;
|
|
109
|
+
let offset = Number(_offset);
|
|
110
|
+
return new OutputStream({
|
|
136
111
|
write (buf) {
|
|
137
|
-
const newSource = new Uint8Array(buf.byteLength +
|
|
138
|
-
newSource.set(
|
|
139
|
-
newSource.set(buf,
|
|
140
|
-
|
|
141
|
-
|
|
112
|
+
const newSource = new Uint8Array(buf.byteLength + entry.source.byteLength);
|
|
113
|
+
newSource.set(entry.source, 0);
|
|
114
|
+
newSource.set(buf, offset);
|
|
115
|
+
offset += buf.byteLength;
|
|
116
|
+
entry.source = newSource;
|
|
142
117
|
return buf.byteLength;
|
|
143
118
|
}
|
|
144
119
|
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
appendViaStream(
|
|
148
|
-
console.log(`[filesystem] APPEND STREAM
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
advise(
|
|
152
|
-
console.log(`[filesystem] ADVISE`,
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
syncData(
|
|
156
|
-
console.log(`[filesystem] SYNC DATA
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
getFlags(
|
|
160
|
-
console.log(`[filesystem] FLAGS FOR
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
getType(
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
if (
|
|
167
|
-
if (descriptor.entry.dir) return 'directory';
|
|
168
|
-
if (descriptor.entry.source) return 'regular-file';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
appendViaStream() {
|
|
123
|
+
console.log(`[filesystem] APPEND STREAM`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
advise(descriptor, offset, length, advice) {
|
|
127
|
+
console.log(`[filesystem] ADVISE`, descriptor, offset, length, advice);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
syncData() {
|
|
131
|
+
console.log(`[filesystem] SYNC DATA`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getFlags() {
|
|
135
|
+
console.log(`[filesystem] FLAGS FOR`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getType() {
|
|
139
|
+
if (this.#stream) return 'fifo';
|
|
140
|
+
if (this.#entry.dir) return 'directory';
|
|
141
|
+
if (this.#entry.source) return 'regular-file';
|
|
169
142
|
return 'unknown';
|
|
170
|
-
}
|
|
143
|
+
}
|
|
171
144
|
|
|
172
|
-
setFlags(
|
|
173
|
-
console.log(`[filesystem] SET FLAGS ${
|
|
174
|
-
}
|
|
145
|
+
setFlags(flags) {
|
|
146
|
+
console.log(`[filesystem] SET FLAGS ${JSON.stringify(flags)}`);
|
|
147
|
+
}
|
|
175
148
|
|
|
176
|
-
setSize(
|
|
177
|
-
console.log(`[filesystem] SET SIZE`,
|
|
178
|
-
}
|
|
149
|
+
setSize(size) {
|
|
150
|
+
console.log(`[filesystem] SET SIZE`, size);
|
|
151
|
+
}
|
|
179
152
|
|
|
180
|
-
setTimes(
|
|
181
|
-
console.log(`[filesystem] SET TIMES`,
|
|
182
|
-
}
|
|
153
|
+
setTimes(dataAccessTimestamp, dataModificationTimestamp) {
|
|
154
|
+
console.log(`[filesystem] SET TIMES`, dataAccessTimestamp, dataModificationTimestamp);
|
|
155
|
+
}
|
|
183
156
|
|
|
184
|
-
read(
|
|
185
|
-
const
|
|
186
|
-
const source = getSource(descriptor.entry);
|
|
157
|
+
read(length, offset) {
|
|
158
|
+
const source = getSource(this.#entry);
|
|
187
159
|
return [source.slice(offset, offset + length), offset + length >= source.byteLength];
|
|
188
|
-
}
|
|
160
|
+
}
|
|
189
161
|
|
|
190
|
-
write(
|
|
191
|
-
const descriptor = getDescriptor(fd);
|
|
162
|
+
write(buffer, offset) {
|
|
192
163
|
if (offset !== 0) throw 'invalid-seek';
|
|
193
|
-
|
|
164
|
+
this.#entry.source = buffer;
|
|
194
165
|
return buffer.byteLength;
|
|
195
|
-
}
|
|
166
|
+
}
|
|
196
167
|
|
|
197
|
-
readDirectory(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return
|
|
201
|
-
}
|
|
168
|
+
readDirectory() {
|
|
169
|
+
if (!this.#entry?.dir)
|
|
170
|
+
throw 'bad-descriptor';
|
|
171
|
+
return new DirectoryEntryStream(Object.entries(this.#entry.dir).sort(([a], [b]) => a > b ? 1 : -1));
|
|
172
|
+
}
|
|
202
173
|
|
|
203
|
-
sync(
|
|
204
|
-
console.log(`[filesystem] SYNC
|
|
205
|
-
}
|
|
174
|
+
sync() {
|
|
175
|
+
console.log(`[filesystem] SYNC`);
|
|
176
|
+
}
|
|
206
177
|
|
|
207
|
-
createDirectoryAt(
|
|
208
|
-
const entry = getChildEntry(
|
|
178
|
+
createDirectoryAt(path) {
|
|
179
|
+
const entry = getChildEntry(this.#entry, path, { create: true, directory: true });
|
|
209
180
|
if (entry.source) throw 'exist';
|
|
210
|
-
}
|
|
181
|
+
}
|
|
211
182
|
|
|
212
|
-
stat(
|
|
213
|
-
const descriptor = getDescriptor(fd);
|
|
183
|
+
stat() {
|
|
214
184
|
let type = 'unknown', size = BigInt(0);
|
|
215
|
-
if (
|
|
185
|
+
if (this.#entry.source) {
|
|
216
186
|
type = 'directory';
|
|
217
187
|
}
|
|
218
|
-
else if (
|
|
188
|
+
else if (this.#entry.dir) {
|
|
219
189
|
type = 'regular-file';
|
|
220
|
-
const source = getSource(
|
|
190
|
+
const source = getSource(this.#entry);
|
|
221
191
|
size = BigInt(source.byteLength);
|
|
222
192
|
}
|
|
223
193
|
return {
|
|
@@ -228,10 +198,10 @@ export const types = {
|
|
|
228
198
|
dataModificationTimestamp: timeZero,
|
|
229
199
|
statusChangeTimestamp: timeZero,
|
|
230
200
|
}
|
|
231
|
-
}
|
|
201
|
+
}
|
|
232
202
|
|
|
233
|
-
statAt(
|
|
234
|
-
const entry = getChildEntry(
|
|
203
|
+
statAt(_pathFlags, path) {
|
|
204
|
+
const entry = getChildEntry(this.#entry, path);
|
|
235
205
|
let type = 'unknown', size = BigInt(0);
|
|
236
206
|
if (entry.source) {
|
|
237
207
|
type = 'regular-file';
|
|
@@ -249,95 +219,95 @@ export const types = {
|
|
|
249
219
|
dataModificationTimestamp: timeZero,
|
|
250
220
|
statusChangeTimestamp: timeZero,
|
|
251
221
|
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
setTimesAt(fd) {
|
|
255
|
-
console.log(`[filesystem] SET TIMES AT`, fd);
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
linkAt(fd) {
|
|
259
|
-
console.log(`[filesystem] LINK AT`, fd);
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
openAt(fd, _pathFlags, path, openFlags, _descriptorFlags, _modes) {
|
|
263
|
-
return createChildDescriptor(fd, path, openFlags);
|
|
264
|
-
},
|
|
222
|
+
}
|
|
265
223
|
|
|
266
|
-
|
|
267
|
-
console.log(`[filesystem]
|
|
268
|
-
}
|
|
224
|
+
setTimesAt() {
|
|
225
|
+
console.log(`[filesystem] SET TIMES AT`);
|
|
226
|
+
}
|
|
269
227
|
|
|
270
|
-
|
|
271
|
-
console.log(`[filesystem]
|
|
272
|
-
}
|
|
228
|
+
linkAt() {
|
|
229
|
+
console.log(`[filesystem] LINK AT`);
|
|
230
|
+
}
|
|
273
231
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
232
|
+
openAt(_pathFlags, path, openFlags, _descriptorFlags, _modes) {
|
|
233
|
+
const childEntry = getChildEntry(this.#entry, path, openFlags);
|
|
234
|
+
return new Descriptor(childEntry);
|
|
235
|
+
}
|
|
277
236
|
|
|
278
|
-
|
|
279
|
-
console.log(`[filesystem]
|
|
280
|
-
}
|
|
237
|
+
readlinkAt() {
|
|
238
|
+
console.log(`[filesystem] READLINK AT`);
|
|
239
|
+
}
|
|
281
240
|
|
|
282
|
-
|
|
283
|
-
console.log(`[filesystem]
|
|
284
|
-
}
|
|
241
|
+
removeDirectoryAt() {
|
|
242
|
+
console.log(`[filesystem] REMOVE DIR AT`);
|
|
243
|
+
}
|
|
285
244
|
|
|
286
|
-
|
|
287
|
-
console.log(`[filesystem]
|
|
288
|
-
}
|
|
245
|
+
renameAt() {
|
|
246
|
+
console.log(`[filesystem] RENAME AT`);
|
|
247
|
+
}
|
|
289
248
|
|
|
290
|
-
|
|
291
|
-
console.log(`[filesystem]
|
|
292
|
-
}
|
|
249
|
+
symlinkAt() {
|
|
250
|
+
console.log(`[filesystem] SYMLINK AT`);
|
|
251
|
+
}
|
|
293
252
|
|
|
294
|
-
|
|
295
|
-
console.log(`[filesystem]
|
|
296
|
-
}
|
|
253
|
+
unlinkFileAt() {
|
|
254
|
+
console.log(`[filesystem] UNLINK FILE AT`);
|
|
255
|
+
}
|
|
297
256
|
|
|
298
|
-
|
|
299
|
-
console.log(`[filesystem]
|
|
300
|
-
}
|
|
257
|
+
changeFilePermissionsAt() {
|
|
258
|
+
console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`);
|
|
259
|
+
}
|
|
301
260
|
|
|
302
|
-
|
|
303
|
-
console.log(`[filesystem]
|
|
304
|
-
}
|
|
261
|
+
changeDirectoryPermissionsAt() {
|
|
262
|
+
console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`);
|
|
263
|
+
}
|
|
305
264
|
|
|
306
|
-
|
|
307
|
-
console.log(`[filesystem]
|
|
308
|
-
}
|
|
265
|
+
lockShared() {
|
|
266
|
+
console.log(`[filesystem] LOCK SHARED`);
|
|
267
|
+
}
|
|
309
268
|
|
|
310
|
-
|
|
311
|
-
console.log(`[filesystem]
|
|
312
|
-
}
|
|
269
|
+
lockExclusive() {
|
|
270
|
+
console.log(`[filesystem] LOCK EXCLUSIVE`);
|
|
271
|
+
}
|
|
313
272
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
delete descriptorTable[fd];
|
|
318
|
-
},
|
|
273
|
+
tryLockShared() {
|
|
274
|
+
console.log(`[filesystem] TRY LOCK SHARED`);
|
|
275
|
+
}
|
|
319
276
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
277
|
+
tryLockExclusive() {
|
|
278
|
+
console.log(`[filesystem] TRY LOCK EXCLUSIVE`);
|
|
279
|
+
}
|
|
323
280
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
281
|
+
unlock() {
|
|
282
|
+
console.log(`[filesystem] UNLOCK`);
|
|
283
|
+
}
|
|
327
284
|
|
|
328
|
-
metadataHash(
|
|
329
|
-
const descriptor = getDescriptor(fd);
|
|
285
|
+
metadataHash() {
|
|
330
286
|
let upper = BigInt(0);
|
|
331
|
-
upper += BigInt(
|
|
287
|
+
upper += BigInt(this.#mtime);
|
|
332
288
|
return { upper, lower: BigInt(0) };
|
|
333
|
-
}
|
|
289
|
+
}
|
|
334
290
|
|
|
335
|
-
metadataHashAt(
|
|
336
|
-
const descriptor = getDescriptor(fd);
|
|
291
|
+
metadataHashAt(_pathFlags, _path) {
|
|
337
292
|
let upper = BigInt(0);
|
|
338
|
-
upper += BigInt(
|
|
293
|
+
upper += BigInt(this.#mtime);
|
|
339
294
|
return { upper, lower: BigInt(0) };
|
|
340
295
|
}
|
|
296
|
+
}
|
|
297
|
+
const descriptorGetEntry = Descriptor.prototype._getEntry;
|
|
298
|
+
delete Descriptor.prototype._getEntry;
|
|
299
|
+
|
|
300
|
+
let _preopens = [[new Descriptor(_fileData), '/']], _rootPreopen = _preopens[0];
|
|
301
|
+
|
|
302
|
+
export const preopens = {
|
|
303
|
+
getDirectories () {
|
|
304
|
+
return _preopens;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export const types = {
|
|
309
|
+
Descriptor,
|
|
310
|
+
DirectoryEntryStream
|
|
341
311
|
};
|
|
342
312
|
|
|
343
|
-
export { types as filesystemTypes }
|
|
313
|
+
export { types as filesystemTypes }
|
package/lib/browser/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as clocks from "./clocks.js";
|
|
2
2
|
import * as filesystem from "./filesystem.js";
|
|
3
3
|
import * as http from "./http.js";
|
|
4
|
-
import * as io from "
|
|
4
|
+
import * as io from "./io.js";
|
|
5
5
|
import * as random from "./random.js";
|
|
6
6
|
import * as sockets from "./sockets.js";
|
|
7
7
|
import * as cli from "./cli.js";
|
|
@@ -15,5 +15,3 @@ export {
|
|
|
15
15
|
sockets,
|
|
16
16
|
cli,
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
export { WasiHttp } from "../http/wasi-http.js";
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
let id = 0;
|
|
2
|
+
|
|
3
|
+
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
|
|
4
|
+
|
|
5
|
+
class Error {
|
|
6
|
+
constructor (msg) {
|
|
7
|
+
this.msg = msg;
|
|
8
|
+
}
|
|
9
|
+
toDebugString () {
|
|
10
|
+
return this.msg;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {{
|
|
16
|
+
* read?: (len: BigInt) => Uint8Array,
|
|
17
|
+
* blockingRead: (len: BigInt) => Uint8Array,
|
|
18
|
+
* skip?: (len: BigInt) => BigInt,
|
|
19
|
+
* blockingSkip?: (len: BigInt) => BigInt,
|
|
20
|
+
* subscribe: () => void,
|
|
21
|
+
* drop?: () => void,
|
|
22
|
+
* }} InputStreamHandler
|
|
23
|
+
*
|
|
24
|
+
* @typedef {{
|
|
25
|
+
* checkWrite?: () -> BigInt,
|
|
26
|
+
* write: (buf: Uint8Array) => BigInt,
|
|
27
|
+
* blockingWriteAndFlush?: (buf: Uint8Array) => void,
|
|
28
|
+
* flush?: () => void,
|
|
29
|
+
* blockingFlush: () => void,
|
|
30
|
+
* writeZeroes?: (len: BigInt) => void,
|
|
31
|
+
* blockingWriteZeroes?: (len: BigInt) => void,
|
|
32
|
+
* blockingWriteZeroesAndFlush?: (len: BigInt) => void,
|
|
33
|
+
* splice?: (src: InputStream, len: BigInt) => BigInt,
|
|
34
|
+
* blockingSplice?: (src: InputStream, len: BigInt) => BigInt,
|
|
35
|
+
* forward?: (src: InputStream) => void,
|
|
36
|
+
* subscribe?: () => void,
|
|
37
|
+
* drop?: () => void,
|
|
38
|
+
* }} OutputStreamHandler
|
|
39
|
+
*
|
|
40
|
+
**/
|
|
41
|
+
|
|
42
|
+
class InputStream {
|
|
43
|
+
/**
|
|
44
|
+
* @param {InputStreamHandler} handler
|
|
45
|
+
*/
|
|
46
|
+
constructor (handler) {
|
|
47
|
+
if (!handler)
|
|
48
|
+
console.trace('no handler');
|
|
49
|
+
this.id = ++id;
|
|
50
|
+
this.handler = handler;
|
|
51
|
+
}
|
|
52
|
+
read(len) {
|
|
53
|
+
if (this.handler.read)
|
|
54
|
+
return this.handler.read(len);
|
|
55
|
+
return this.handler.blockingRead.call(this, len);
|
|
56
|
+
}
|
|
57
|
+
blockingRead(len) {
|
|
58
|
+
return this.handler.blockingRead.call(this, len);
|
|
59
|
+
}
|
|
60
|
+
skip(len) {
|
|
61
|
+
if (this.handler.skip)
|
|
62
|
+
return this.handler.skip.call(this, len);
|
|
63
|
+
if (this.handler.read) {
|
|
64
|
+
const bytes = this.handler.read.call(this, len);
|
|
65
|
+
return BigInt(bytes.byteLength);
|
|
66
|
+
}
|
|
67
|
+
return this.blockingSkip.call(this, len);
|
|
68
|
+
}
|
|
69
|
+
blockingSkip(len) {
|
|
70
|
+
if (this.handler.blockingSkip)
|
|
71
|
+
return this.handler.blockingSkip.call(this, len);
|
|
72
|
+
const bytes = this.handler.blockingRead.call(this, len);
|
|
73
|
+
return BigInt(bytes.byteLength);
|
|
74
|
+
}
|
|
75
|
+
subscribe() {
|
|
76
|
+
console.log(`[streams] Subscribe to input stream ${this.id}`);
|
|
77
|
+
}
|
|
78
|
+
[symbolDispose] () {
|
|
79
|
+
if (this.handler.drop)
|
|
80
|
+
this.handler.drop.call(this);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class OutputStream {
|
|
85
|
+
/**
|
|
86
|
+
* @param {OutputStreamHandler} handler
|
|
87
|
+
*/
|
|
88
|
+
constructor (handler) {
|
|
89
|
+
if (!handler)
|
|
90
|
+
console.trace('no handler');
|
|
91
|
+
this.id = ++id;
|
|
92
|
+
this.open = true;
|
|
93
|
+
this.handler = handler;
|
|
94
|
+
}
|
|
95
|
+
checkWrite(len) {
|
|
96
|
+
if (!this.open)
|
|
97
|
+
return 0n;
|
|
98
|
+
if (this.handler.checkWrite)
|
|
99
|
+
return this.handler.checkWrite.call(this, len);
|
|
100
|
+
return 1_000_000n;
|
|
101
|
+
}
|
|
102
|
+
write(buf) {
|
|
103
|
+
this.handler.write.call(this, buf);
|
|
104
|
+
}
|
|
105
|
+
blockingWriteAndFlush(buf) {
|
|
106
|
+
/// Perform a write of up to 4096 bytes, and then flush the stream. Block
|
|
107
|
+
/// until all of these operations are complete, or an error occurs.
|
|
108
|
+
///
|
|
109
|
+
/// This is a convenience wrapper around the use of `check-write`,
|
|
110
|
+
/// `subscribe`, `write`, and `flush`, and is implemented with the
|
|
111
|
+
/// following pseudo-code:
|
|
112
|
+
///
|
|
113
|
+
/// ```text
|
|
114
|
+
/// let pollable = this.subscribe();
|
|
115
|
+
/// while !contents.is_empty() {
|
|
116
|
+
/// // Wait for the stream to become writable
|
|
117
|
+
/// poll-one(pollable);
|
|
118
|
+
/// let Ok(n) = this.check-write(); // eliding error handling
|
|
119
|
+
/// let len = min(n, contents.len());
|
|
120
|
+
/// let (chunk, rest) = contents.split_at(len);
|
|
121
|
+
/// this.write(chunk ); // eliding error handling
|
|
122
|
+
/// contents = rest;
|
|
123
|
+
/// }
|
|
124
|
+
/// this.flush();
|
|
125
|
+
/// // Wait for completion of `flush`
|
|
126
|
+
/// poll-one(pollable);
|
|
127
|
+
/// // Check for any errors that arose during `flush`
|
|
128
|
+
/// let _ = this.check-write(); // eliding error handling
|
|
129
|
+
/// ```
|
|
130
|
+
this.handler.write.call(this, buf);
|
|
131
|
+
}
|
|
132
|
+
flush() {
|
|
133
|
+
if (this.handler.flush)
|
|
134
|
+
this.handler.flush.call(this);
|
|
135
|
+
}
|
|
136
|
+
blockingFlush() {
|
|
137
|
+
this.open = true;
|
|
138
|
+
}
|
|
139
|
+
writeZeroes(len) {
|
|
140
|
+
this.write.call(this, new Uint8Array(Number(len)));
|
|
141
|
+
}
|
|
142
|
+
blockingWriteZeroes(len) {
|
|
143
|
+
this.blockingWrite.call(this, new Uint8Array(Number(len)));
|
|
144
|
+
}
|
|
145
|
+
blockingWriteZeroesAndFlush(len) {
|
|
146
|
+
this.blockingWriteAndFlush.call(this, new Uint8Array(Number(len)));
|
|
147
|
+
}
|
|
148
|
+
splice(src, len) {
|
|
149
|
+
const spliceLen = Math.min(len, this.checkWrite.call(this));
|
|
150
|
+
const bytes = src.read(spliceLen);
|
|
151
|
+
this.write.call(this, bytes);
|
|
152
|
+
return bytes.byteLength;
|
|
153
|
+
}
|
|
154
|
+
blockingSplice(_src, _len) {
|
|
155
|
+
console.log(`[streams] Blocking splice ${this.id}`);
|
|
156
|
+
}
|
|
157
|
+
forward(_src) {
|
|
158
|
+
console.log(`[streams] Forward ${this.id}`);
|
|
159
|
+
}
|
|
160
|
+
subscribe() {
|
|
161
|
+
console.log(`[streams] Subscribe to output stream ${this.id}`);
|
|
162
|
+
}
|
|
163
|
+
[symbolDispose]() {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const streams = { Error, InputStream, OutputStream };
|
|
168
|
+
|
|
169
|
+
class Pollable {}
|
|
170
|
+
|
|
171
|
+
function pollList (_list) {
|
|
172
|
+
// TODO
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function pollOne (_poll) {
|
|
176
|
+
// TODO
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const poll = {
|
|
180
|
+
Pollable,
|
|
181
|
+
pollList,
|
|
182
|
+
pollOne
|
|
183
|
+
};
|
package/lib/common/io.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
let id = 0;
|
|
2
2
|
|
|
3
|
+
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
|
|
4
|
+
|
|
3
5
|
class Error {
|
|
4
6
|
constructor (msg) {
|
|
5
7
|
this.msg = msg;
|
|
@@ -73,7 +75,7 @@ class InputStream {
|
|
|
73
75
|
subscribe() {
|
|
74
76
|
console.log(`[streams] Subscribe to input stream ${this.id}`);
|
|
75
77
|
}
|
|
76
|
-
|
|
78
|
+
[symbolDispose] () {
|
|
77
79
|
if (this.handler.drop)
|
|
78
80
|
this.handler.drop.call(this);
|
|
79
81
|
}
|
|
@@ -158,7 +160,7 @@ class OutputStream {
|
|
|
158
160
|
subscribe() {
|
|
159
161
|
console.log(`[streams] Subscribe to output stream ${this.id}`);
|
|
160
162
|
}
|
|
161
|
-
|
|
163
|
+
[symbolDispose]() {
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
package/lib/nodejs/cli.js
CHANGED
|
@@ -2,7 +2,8 @@ import { argv, env, cwd } from 'node:process';
|
|
|
2
2
|
import { streams } from '../common/io.js';
|
|
3
3
|
const { InputStream, OutputStream } = streams;
|
|
4
4
|
|
|
5
|
-
let _env = Object.entries(env), _args = argv, _cwd = cwd();
|
|
5
|
+
let _env = Object.entries(env), _args = argv.slice(1), _cwd = cwd();
|
|
6
|
+
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
|
|
6
7
|
|
|
7
8
|
export const environment = {
|
|
8
9
|
getEnvironment () {
|
|
@@ -29,7 +30,7 @@ const stdinStream = new InputStream({
|
|
|
29
30
|
subscribe () {
|
|
30
31
|
// TODO
|
|
31
32
|
},
|
|
32
|
-
|
|
33
|
+
[symbolDispose] () {
|
|
33
34
|
// TODO
|
|
34
35
|
}
|
|
35
36
|
});
|
|
@@ -39,7 +40,7 @@ const stdoutStream = new OutputStream({
|
|
|
39
40
|
},
|
|
40
41
|
blockingFlush () {
|
|
41
42
|
},
|
|
42
|
-
|
|
43
|
+
[symbolDispose] () {
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
const stderrStream = new OutputStream({
|
|
@@ -49,7 +50,7 @@ const stderrStream = new OutputStream({
|
|
|
49
50
|
blockingFlush () {
|
|
50
51
|
|
|
51
52
|
},
|
|
52
|
-
|
|
53
|
+
[symbolDispose] () {
|
|
53
54
|
|
|
54
55
|
}
|
|
55
56
|
});
|
package/lib/nodejs/filesystem.js
CHANGED
|
@@ -5,6 +5,8 @@ import { platform } from 'node:process';
|
|
|
5
5
|
|
|
6
6
|
const { InputStream, OutputStream, Error: StreamError } = streams;
|
|
7
7
|
|
|
8
|
+
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
|
|
9
|
+
|
|
8
10
|
const isWindows = platform === 'win32';
|
|
9
11
|
|
|
10
12
|
const nsMagnitude = 1_000_000_000_000n;
|
|
@@ -39,35 +41,6 @@ function lookupType (obj) {
|
|
|
39
41
|
* } DescriptorProps
|
|
40
42
|
*/
|
|
41
43
|
export class FileSystem {
|
|
42
|
-
// Note: This should implement per-segment semantics of openAt, but we cannot currently
|
|
43
|
-
// due to the lack of support for openat() in Node.js.
|
|
44
|
-
// Tracking issue: https://github.com/libuv/libuv/issues/4167
|
|
45
|
-
|
|
46
|
-
// TODO: support followSymlinks
|
|
47
|
-
getFullPath (descriptor, subpath, _followSymlinks) {
|
|
48
|
-
if (subpath.indexOf('\\') !== -1)
|
|
49
|
-
subpath = subpath.replace(/\\/g, '/');
|
|
50
|
-
if (subpath[0] === '/') {
|
|
51
|
-
let bestPreopenMatch = '';
|
|
52
|
-
for (const preopenEntry of this.preopenEntries) {
|
|
53
|
-
if (subpath.startsWith(preopenEntry[1]) && (!bestPreopenMatch || bestPreopenMatch.length < preopenEntry[1].length)) {
|
|
54
|
-
bestPreopenMatch = preopenEntry;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (!bestPreopenMatch)
|
|
58
|
-
throw 'no-entry';
|
|
59
|
-
descriptor = bestPreopenMatch[0];
|
|
60
|
-
subpath = subpath.slice(bestPreopenMatch[1]);
|
|
61
|
-
if (subpath[0] === '/')
|
|
62
|
-
subpath = subpath.slice(1);
|
|
63
|
-
}
|
|
64
|
-
if (subpath.startsWith('.'))
|
|
65
|
-
subpath = subpath.slice(subpath[1] === '/' ? 2 : 1);
|
|
66
|
-
if (descriptor.hostPreopen)
|
|
67
|
-
return descriptor.hostPreopen + (descriptor.hostPreopen.endsWith('/') ? '' : '/') + subpath;
|
|
68
|
-
return descriptor.fullPath + '/' + subpath;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
44
|
/**
|
|
72
45
|
*
|
|
73
46
|
* @param {[string, string][]} preopens
|
|
@@ -79,16 +52,18 @@ export class FileSystem {
|
|
|
79
52
|
this.cwd = environment.initialCwd();
|
|
80
53
|
|
|
81
54
|
class FileInputStream extends InputStream {
|
|
55
|
+
#hostFd;
|
|
56
|
+
#position;
|
|
82
57
|
constructor (hostFd, position) {
|
|
83
58
|
super({
|
|
84
59
|
blockingRead (len) {
|
|
85
60
|
const buf = new Uint8Array(Number(len));
|
|
86
61
|
try {
|
|
87
|
-
var bytesRead = readSync(
|
|
62
|
+
var bytesRead = readSync(self.#hostFd, buf, 0, buf.byteLength, self.#position);
|
|
88
63
|
} catch (e) {
|
|
89
64
|
throw { tag: 'last-operation-failed', val: new StreamError(e.message) };
|
|
90
65
|
}
|
|
91
|
-
|
|
66
|
+
self.#position += bytesRead;
|
|
92
67
|
if (bytesRead < buf.byteLength) {
|
|
93
68
|
if (bytesRead === 0)
|
|
94
69
|
throw { tag: 'closed' };
|
|
@@ -99,26 +74,29 @@ export class FileSystem {
|
|
|
99
74
|
subscribe () {
|
|
100
75
|
// TODO
|
|
101
76
|
},
|
|
102
|
-
|
|
77
|
+
[symbolDispose] () {
|
|
103
78
|
// TODO
|
|
104
79
|
}
|
|
105
80
|
});
|
|
106
|
-
|
|
107
|
-
this
|
|
81
|
+
const self = this;
|
|
82
|
+
this.#hostFd = hostFd;
|
|
83
|
+
this.#position = Number(position);
|
|
108
84
|
}
|
|
109
85
|
}
|
|
110
86
|
|
|
111
87
|
class FileOutputStream extends OutputStream {
|
|
88
|
+
#hostFd;
|
|
89
|
+
#position;
|
|
112
90
|
constructor (hostFd, position) {
|
|
113
91
|
super({
|
|
114
92
|
write (contents) {
|
|
115
93
|
let totalWritten = 0;
|
|
116
94
|
while (totalWritten !== contents.byteLength) {
|
|
117
|
-
const bytesWritten = writeSync(
|
|
95
|
+
const bytesWritten = writeSync(self.#hostFd, contents, null, null, self.#position);
|
|
118
96
|
totalWritten += bytesWritten;
|
|
119
97
|
contents = new Uint8Array(contents.buffer, bytesWritten);
|
|
120
98
|
}
|
|
121
|
-
|
|
99
|
+
self.#position += contents.byteLength;
|
|
122
100
|
},
|
|
123
101
|
blockingFlush () {
|
|
124
102
|
|
|
@@ -127,19 +105,18 @@ export class FileSystem {
|
|
|
127
105
|
|
|
128
106
|
}
|
|
129
107
|
});
|
|
130
|
-
|
|
131
|
-
this
|
|
108
|
+
const self = this;
|
|
109
|
+
this.#hostFd = hostFd;
|
|
110
|
+
this.#position = Number(position);
|
|
132
111
|
}
|
|
133
112
|
}
|
|
134
113
|
|
|
135
114
|
class DirectoryEntryStream {
|
|
136
|
-
|
|
137
|
-
this.dir = dir;
|
|
138
|
-
}
|
|
115
|
+
#dir;
|
|
139
116
|
readDirectoryEntry () {
|
|
140
117
|
let entry;
|
|
141
118
|
try {
|
|
142
|
-
entry = this
|
|
119
|
+
entry = this.#dir.readSync();
|
|
143
120
|
} catch (e) {
|
|
144
121
|
throw convertFsError(e);
|
|
145
122
|
}
|
|
@@ -150,27 +127,54 @@ export class FileSystem {
|
|
|
150
127
|
const type = lookupType(entry);
|
|
151
128
|
return { name, type };
|
|
152
129
|
}
|
|
153
|
-
|
|
154
|
-
this
|
|
130
|
+
[symbolDispose] () {
|
|
131
|
+
this.#dir.closeSync();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static _create (dir) {
|
|
135
|
+
const dirStream = new DirectoryEntryStream();
|
|
136
|
+
dirStream.#dir = dir;
|
|
137
|
+
return dirStream;
|
|
155
138
|
}
|
|
156
139
|
}
|
|
140
|
+
const directoryEntryStreamCreate = DirectoryEntryStream._create;
|
|
141
|
+
delete DirectoryEntryStream._create;
|
|
157
142
|
|
|
143
|
+
// Note: This should implement per-segment semantics of openAt, but we cannot currently
|
|
144
|
+
// due to the lack of support for openat() in Node.js.
|
|
145
|
+
// Tracking issue: https://github.com/libuv/libuv/issues/4167
|
|
158
146
|
/**
|
|
159
147
|
* @implements {DescriptorProps}
|
|
160
148
|
*/
|
|
161
149
|
class Descriptor {
|
|
150
|
+
#hostPreopen;
|
|
151
|
+
#fd;
|
|
152
|
+
#fullPath;
|
|
153
|
+
|
|
154
|
+
static _createPreopen (hostPreopen) {
|
|
155
|
+
const descriptor = new Descriptor();
|
|
156
|
+
descriptor.#hostPreopen = hostPreopen;
|
|
157
|
+
return descriptor;
|
|
158
|
+
}
|
|
159
|
+
static _create (fd, fullPath) {
|
|
160
|
+
const descriptor = new Descriptor();
|
|
161
|
+
descriptor.#fd = fd;
|
|
162
|
+
descriptor.#fullPath = fullPath;
|
|
163
|
+
return descriptor;
|
|
164
|
+
}
|
|
165
|
+
|
|
162
166
|
constructor () {
|
|
163
167
|
this.id = fs.descriptorCnt++;
|
|
164
168
|
}
|
|
165
169
|
readViaStream(offset) {
|
|
166
|
-
if (this
|
|
170
|
+
if (this.#hostPreopen)
|
|
167
171
|
throw { tag: 'last-operation-failed', val: new StreamError };
|
|
168
|
-
return new FileInputStream(this
|
|
172
|
+
return new FileInputStream(this.#fd, offset);
|
|
169
173
|
}
|
|
170
174
|
writeViaStream(offset) {
|
|
171
|
-
if (this
|
|
175
|
+
if (this.#hostPreopen)
|
|
172
176
|
throw 'is-directory';
|
|
173
|
-
return new FileOutputStream(this
|
|
177
|
+
return new FileOutputStream(this.#fd, offset);
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
appendViaStream() {
|
|
@@ -190,8 +194,8 @@ export class FileSystem {
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
getType() {
|
|
193
|
-
if (this
|
|
194
|
-
const stats = fstatSync(this
|
|
197
|
+
if (this.#hostPreopen) return 'directory';
|
|
198
|
+
const stats = fstatSync(this.#fd);
|
|
195
199
|
return lookupType(stats);
|
|
196
200
|
}
|
|
197
201
|
|
|
@@ -208,23 +212,23 @@ export class FileSystem {
|
|
|
208
212
|
}
|
|
209
213
|
|
|
210
214
|
read(length, offset) {
|
|
211
|
-
if (!this
|
|
215
|
+
if (!this.#fullPath) throw 'bad-descriptor';
|
|
212
216
|
const buf = new Uint8Array(length);
|
|
213
|
-
const bytesRead = readSync(this
|
|
217
|
+
const bytesRead = readSync(this.#fd, buf, Number(offset), length, 0);
|
|
214
218
|
const out = new Uint8Array(buf.buffer, 0, bytesRead);
|
|
215
219
|
return [out, bytesRead === 0 ? 'ended' : 'open'];
|
|
216
220
|
}
|
|
217
221
|
|
|
218
222
|
write(buffer, offset) {
|
|
219
|
-
if (!this
|
|
220
|
-
return BigInt(writeSync(this
|
|
223
|
+
if (!this.#fullPath) throw 'bad-descriptor';
|
|
224
|
+
return BigInt(writeSync(this.#fd, buffer, Number(offset), buffer.byteLength - offset, 0));
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
readDirectory() {
|
|
224
|
-
if (!this
|
|
228
|
+
if (!this.#fullPath) throw 'bad-descriptor';
|
|
225
229
|
try {
|
|
226
|
-
const dir = opendirSync(isWindows ? this
|
|
227
|
-
return
|
|
230
|
+
const dir = opendirSync(isWindows ? this.#fullPath.slice(1) : this.#fullPath);
|
|
231
|
+
return directoryEntryStreamCreate(dir);
|
|
228
232
|
}
|
|
229
233
|
catch (e) {
|
|
230
234
|
throw convertFsError(e);
|
|
@@ -236,7 +240,7 @@ export class FileSystem {
|
|
|
236
240
|
}
|
|
237
241
|
|
|
238
242
|
createDirectoryAt(path) {
|
|
239
|
-
const fullPath =
|
|
243
|
+
const fullPath = this.#getFullPath(path);
|
|
240
244
|
try {
|
|
241
245
|
mkdirSync(fullPath);
|
|
242
246
|
}
|
|
@@ -246,10 +250,10 @@ export class FileSystem {
|
|
|
246
250
|
}
|
|
247
251
|
|
|
248
252
|
stat() {
|
|
249
|
-
if (this
|
|
253
|
+
if (this.#hostPreopen) throw 'invalid';
|
|
250
254
|
let stats;
|
|
251
255
|
try {
|
|
252
|
-
stats = fstatSync(this
|
|
256
|
+
stats = fstatSync(this.#fd, { bigint: true });
|
|
253
257
|
}
|
|
254
258
|
catch (e) {
|
|
255
259
|
convertFsError(e);
|
|
@@ -266,7 +270,7 @@ export class FileSystem {
|
|
|
266
270
|
}
|
|
267
271
|
|
|
268
272
|
statAt(pathFlags, path) {
|
|
269
|
-
const fullPath =
|
|
273
|
+
const fullPath = this.#getFullPath(path, false);
|
|
270
274
|
let stats;
|
|
271
275
|
try {
|
|
272
276
|
stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(isWindows ? fullPath.slice(1) : fullPath, { bigint: true });
|
|
@@ -294,7 +298,7 @@ export class FileSystem {
|
|
|
294
298
|
}
|
|
295
299
|
|
|
296
300
|
openAt(pathFlags, path, openFlags, descriptorFlags, modes) {
|
|
297
|
-
const fullPath =
|
|
301
|
+
const fullPath = this.#getFullPath(path, pathFlags.symlinkFollow);
|
|
298
302
|
let fsOpenFlags = 0x0;
|
|
299
303
|
if (openFlags.create)
|
|
300
304
|
fsOpenFlags |= constants.O_CREAT;
|
|
@@ -325,7 +329,7 @@ export class FileSystem {
|
|
|
325
329
|
|
|
326
330
|
try {
|
|
327
331
|
const fd = openSync(isWindows ? fullPath.slice(1) : fullPath, fsOpenFlags, fsMode);
|
|
328
|
-
return
|
|
332
|
+
return descriptorCreate(fd, fullPath);
|
|
329
333
|
}
|
|
330
334
|
catch (e) {
|
|
331
335
|
throw convertFsError(e);
|
|
@@ -380,16 +384,16 @@ export class FileSystem {
|
|
|
380
384
|
console.log(`[filesystem] UNLOCK`, this.id);
|
|
381
385
|
}
|
|
382
386
|
|
|
383
|
-
|
|
384
|
-
if (this
|
|
385
|
-
closeSync(this
|
|
387
|
+
[symbolDispose]() {
|
|
388
|
+
if (this.#fd)
|
|
389
|
+
closeSync(this.#fd);
|
|
386
390
|
}
|
|
387
391
|
|
|
388
392
|
metadataHash() {
|
|
389
|
-
if (this
|
|
393
|
+
if (this.#hostPreopen)
|
|
390
394
|
return { upper: 0n, lower: BigInt(this.id) };
|
|
391
395
|
try {
|
|
392
|
-
const stats = fstatSync(this
|
|
396
|
+
const stats = fstatSync(this.#fd, { bigint: true });
|
|
393
397
|
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
394
398
|
}
|
|
395
399
|
catch (e) {
|
|
@@ -398,7 +402,7 @@ export class FileSystem {
|
|
|
398
402
|
}
|
|
399
403
|
|
|
400
404
|
metadataHashAt(pathFlags, path) {
|
|
401
|
-
const fullPath =
|
|
405
|
+
const fullPath = this.#getFullPath(path, false);
|
|
402
406
|
try {
|
|
403
407
|
const stats = (pathFlags.symlinkFollow ? statSync : lstatSync)(isWindows ? fullPath.slice(1) : fullPath, { bigint: true });
|
|
404
408
|
return { upper: stats.mtimeNs, lower: stats.ino };
|
|
@@ -407,12 +411,43 @@ export class FileSystem {
|
|
|
407
411
|
convertFsError(e);
|
|
408
412
|
}
|
|
409
413
|
}
|
|
414
|
+
|
|
415
|
+
// TODO: support followSymlinks
|
|
416
|
+
#getFullPath (subpath, _followSymlinks) {
|
|
417
|
+
let descriptor = this;
|
|
418
|
+
if (subpath.indexOf('\\') !== -1)
|
|
419
|
+
subpath = subpath.replace(/\\/g, '/');
|
|
420
|
+
if (subpath[0] === '/') {
|
|
421
|
+
let bestPreopenMatch = '';
|
|
422
|
+
for (const preopenEntry of fs.preopenEntries) {
|
|
423
|
+
if (subpath.startsWith(preopenEntry[1]) && (!bestPreopenMatch || bestPreopenMatch.length < preopenEntry[1].length)) {
|
|
424
|
+
bestPreopenMatch = preopenEntry;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (!bestPreopenMatch)
|
|
428
|
+
throw 'no-entry';
|
|
429
|
+
descriptor = bestPreopenMatch[0];
|
|
430
|
+
subpath = subpath.slice(bestPreopenMatch[1]);
|
|
431
|
+
if (subpath[0] === '/')
|
|
432
|
+
subpath = subpath.slice(1);
|
|
433
|
+
}
|
|
434
|
+
if (subpath.startsWith('.'))
|
|
435
|
+
subpath = subpath.slice(subpath[1] === '/' ? 2 : 1);
|
|
436
|
+
if (descriptor.#hostPreopen)
|
|
437
|
+
return descriptor.#hostPreopen + (descriptor.#hostPreopen.endsWith('/') ? '' : '/') + subpath;
|
|
438
|
+
return descriptor.#fullPath + '/' + subpath;
|
|
439
|
+
}
|
|
410
440
|
}
|
|
411
441
|
|
|
442
|
+
const descriptorCreatePreopen = Descriptor._createPreopen;
|
|
443
|
+
delete Descriptor._createPreopen;
|
|
444
|
+
const descriptorCreate = Descriptor._create;
|
|
445
|
+
delete Descriptor._create;
|
|
446
|
+
|
|
412
447
|
this.descriptorCnt = 3;
|
|
413
448
|
this.preopenEntries = [];
|
|
414
449
|
for (const [virtualPath, hostPreopen] of Object.entries(preopens)) {
|
|
415
|
-
const preopenEntry = [
|
|
450
|
+
const preopenEntry = [descriptorCreatePreopen(hostPreopen), virtualPath];
|
|
416
451
|
this.preopenEntries.push(preopenEntry);
|
|
417
452
|
}
|
|
418
453
|
this.preopens = {
|
|
@@ -428,9 +463,7 @@ export class FileSystem {
|
|
|
428
463
|
}
|
|
429
464
|
}
|
|
430
465
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
export const { preopens, types } = _fs;
|
|
466
|
+
export const { preopens, types } = new FileSystem({ '/': '/' }, environment);
|
|
434
467
|
|
|
435
468
|
function convertFsError (e) {
|
|
436
469
|
switch (e.code) {
|
package/lib/nodejs/http.js
CHANGED
package/package.json
CHANGED