quickjs-wasi-reactor 0.0.1
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/LICENSE +25 -0
- package/README.md +230 -0
- package/dist/fd.d.ts +106 -0
- package/dist/fd.d.ts.map +1 -0
- package/dist/fd.js +110 -0
- package/dist/fd.js.map +1 -0
- package/dist/fs-mem.d.ts +255 -0
- package/dist/fs-mem.d.ts.map +1 -0
- package/dist/fs-mem.js +679 -0
- package/dist/fs-mem.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/quickjs.d.ts +136 -0
- package/dist/quickjs.d.ts.map +1 -0
- package/dist/quickjs.js +334 -0
- package/dist/quickjs.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/wasi-defs.d.ts +119 -0
- package/dist/wasi-defs.d.ts.map +1 -0
- package/dist/wasi-defs.js +247 -0
- package/dist/wasi-defs.js.map +1 -0
- package/dist/wasi.d.ts +41 -0
- package/dist/wasi.d.ts.map +1 -0
- package/dist/wasi.js +638 -0
- package/dist/wasi.js.map +1 -0
- package/package.json +61 -0
- package/qjs-wasi.wasm +0 -0
package/dist/wasi.js
ADDED
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
// WASI implementation for QuickJS reactor
|
|
2
|
+
import * as wasi from "./wasi-defs.js";
|
|
3
|
+
/**
|
|
4
|
+
* An exception that is thrown when the process exits.
|
|
5
|
+
*/
|
|
6
|
+
export class WASIProcExit extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code) {
|
|
9
|
+
super("exit with exit code " + code);
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class WASI {
|
|
14
|
+
#freeFds = [];
|
|
15
|
+
args = [];
|
|
16
|
+
env = [];
|
|
17
|
+
fds = [];
|
|
18
|
+
inst;
|
|
19
|
+
debug = false;
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
wasiImport;
|
|
22
|
+
/** Start a WASI command */
|
|
23
|
+
start(instance) {
|
|
24
|
+
this.inst = instance;
|
|
25
|
+
try {
|
|
26
|
+
instance.exports._start();
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
if (e instanceof WASIProcExit) {
|
|
31
|
+
return e.code;
|
|
32
|
+
}
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Initialize a WASI reactor */
|
|
37
|
+
initialize(instance) {
|
|
38
|
+
this.inst = instance;
|
|
39
|
+
if (instance.exports._initialize) {
|
|
40
|
+
instance.exports._initialize();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
log(...args) {
|
|
44
|
+
if (this.debug) {
|
|
45
|
+
console.log("[WASI]", ...args);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
constructor(args, env, fds, options = {}) {
|
|
49
|
+
this.debug = options.debug ?? false;
|
|
50
|
+
this.args = args;
|
|
51
|
+
this.env = env;
|
|
52
|
+
this.fds = fds;
|
|
53
|
+
this.wasiImport = {
|
|
54
|
+
args_sizes_get: (argc, argv_buf_size) => {
|
|
55
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
56
|
+
buffer.setUint32(argc, this.args.length, true);
|
|
57
|
+
let buf_size = 0;
|
|
58
|
+
for (const arg of this.args) {
|
|
59
|
+
buf_size += arg.length + 1;
|
|
60
|
+
}
|
|
61
|
+
buffer.setUint32(argv_buf_size, buf_size, true);
|
|
62
|
+
this.log("args_sizes_get", this.args.length, buf_size);
|
|
63
|
+
return 0;
|
|
64
|
+
},
|
|
65
|
+
args_get: (argv, argv_buf) => {
|
|
66
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
67
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
68
|
+
for (let i = 0; i < this.args.length; i++) {
|
|
69
|
+
buffer.setUint32(argv, argv_buf, true);
|
|
70
|
+
argv += 4;
|
|
71
|
+
const arg = new TextEncoder().encode(this.args[i]);
|
|
72
|
+
buffer8.set(arg, argv_buf);
|
|
73
|
+
buffer.setUint8(argv_buf + arg.length, 0);
|
|
74
|
+
argv_buf += arg.length + 1;
|
|
75
|
+
}
|
|
76
|
+
return 0;
|
|
77
|
+
},
|
|
78
|
+
environ_sizes_get: (environ_count, environ_size) => {
|
|
79
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
80
|
+
buffer.setUint32(environ_count, this.env.length, true);
|
|
81
|
+
let buf_size = 0;
|
|
82
|
+
for (const environ of this.env) {
|
|
83
|
+
buf_size += new TextEncoder().encode(environ).length + 1;
|
|
84
|
+
}
|
|
85
|
+
buffer.setUint32(environ_size, buf_size, true);
|
|
86
|
+
return 0;
|
|
87
|
+
},
|
|
88
|
+
environ_get: (environ, environ_buf) => {
|
|
89
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
90
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
91
|
+
for (let i = 0; i < this.env.length; i++) {
|
|
92
|
+
buffer.setUint32(environ, environ_buf, true);
|
|
93
|
+
environ += 4;
|
|
94
|
+
const e = new TextEncoder().encode(this.env[i]);
|
|
95
|
+
buffer8.set(e, environ_buf);
|
|
96
|
+
buffer.setUint8(environ_buf + e.length, 0);
|
|
97
|
+
environ_buf += e.length + 1;
|
|
98
|
+
}
|
|
99
|
+
return 0;
|
|
100
|
+
},
|
|
101
|
+
clock_res_get: (id, res_ptr) => {
|
|
102
|
+
let resolutionValue;
|
|
103
|
+
switch (id) {
|
|
104
|
+
case wasi.CLOCKID_MONOTONIC: {
|
|
105
|
+
resolutionValue = 5000n;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case wasi.CLOCKID_REALTIME: {
|
|
109
|
+
resolutionValue = 1000000n;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
return wasi.ERRNO_NOSYS;
|
|
114
|
+
}
|
|
115
|
+
const view = new DataView(this.inst.exports.memory.buffer);
|
|
116
|
+
view.setBigUint64(res_ptr, resolutionValue, true);
|
|
117
|
+
return wasi.ERRNO_SUCCESS;
|
|
118
|
+
},
|
|
119
|
+
clock_time_get: (id, _precision, time) => {
|
|
120
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
121
|
+
if (id === wasi.CLOCKID_REALTIME) {
|
|
122
|
+
buffer.setBigUint64(time, BigInt(new Date().getTime()) * 1000000n, true);
|
|
123
|
+
}
|
|
124
|
+
else if (id == wasi.CLOCKID_MONOTONIC) {
|
|
125
|
+
let monotonic_time;
|
|
126
|
+
try {
|
|
127
|
+
monotonic_time = BigInt(Math.round(performance.now() * 1000000));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
monotonic_time = 0n;
|
|
131
|
+
}
|
|
132
|
+
buffer.setBigUint64(time, monotonic_time, true);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
buffer.setBigUint64(time, 0n, true);
|
|
136
|
+
}
|
|
137
|
+
return 0;
|
|
138
|
+
},
|
|
139
|
+
fd_advise: (fd, _offset, _len, _advice) => {
|
|
140
|
+
if (this.fds[fd] != undefined) {
|
|
141
|
+
return wasi.ERRNO_SUCCESS;
|
|
142
|
+
}
|
|
143
|
+
return wasi.ERRNO_BADF;
|
|
144
|
+
},
|
|
145
|
+
fd_allocate: (fd, offset, len) => {
|
|
146
|
+
if (this.fds[fd] != undefined) {
|
|
147
|
+
return this.fds[fd].fd_allocate(offset, len);
|
|
148
|
+
}
|
|
149
|
+
return wasi.ERRNO_BADF;
|
|
150
|
+
},
|
|
151
|
+
fd_close: (fd) => {
|
|
152
|
+
if (this.fds[fd] != undefined) {
|
|
153
|
+
const ret = this.fds[fd].fd_close();
|
|
154
|
+
this.fds[fd] = undefined;
|
|
155
|
+
this.#freeFds.push(fd);
|
|
156
|
+
return ret;
|
|
157
|
+
}
|
|
158
|
+
return wasi.ERRNO_BADF;
|
|
159
|
+
},
|
|
160
|
+
fd_datasync: (fd) => {
|
|
161
|
+
if (this.fds[fd] != undefined) {
|
|
162
|
+
return this.fds[fd].fd_sync();
|
|
163
|
+
}
|
|
164
|
+
return wasi.ERRNO_BADF;
|
|
165
|
+
},
|
|
166
|
+
fd_fdstat_get: (fd, fdstat_ptr) => {
|
|
167
|
+
if (this.fds[fd] != undefined) {
|
|
168
|
+
const { ret, fdstat } = this.fds[fd].fd_fdstat_get();
|
|
169
|
+
if (fdstat != null) {
|
|
170
|
+
fdstat.write_bytes(new DataView(this.inst.exports.memory.buffer), fdstat_ptr);
|
|
171
|
+
}
|
|
172
|
+
return ret;
|
|
173
|
+
}
|
|
174
|
+
return wasi.ERRNO_BADF;
|
|
175
|
+
},
|
|
176
|
+
fd_fdstat_set_flags: (fd, flags) => {
|
|
177
|
+
if (this.fds[fd] != undefined) {
|
|
178
|
+
return this.fds[fd].fd_fdstat_set_flags(flags);
|
|
179
|
+
}
|
|
180
|
+
return wasi.ERRNO_BADF;
|
|
181
|
+
},
|
|
182
|
+
fd_fdstat_set_rights: (fd, fs_rights_base, fs_rights_inheriting) => {
|
|
183
|
+
if (this.fds[fd] != undefined) {
|
|
184
|
+
return this.fds[fd].fd_fdstat_set_rights(fs_rights_base, fs_rights_inheriting);
|
|
185
|
+
}
|
|
186
|
+
return wasi.ERRNO_BADF;
|
|
187
|
+
},
|
|
188
|
+
fd_filestat_get: (fd, filestat_ptr) => {
|
|
189
|
+
if (this.fds[fd] != undefined) {
|
|
190
|
+
const { ret, filestat } = this.fds[fd].fd_filestat_get();
|
|
191
|
+
if (filestat != null) {
|
|
192
|
+
filestat.write_bytes(new DataView(this.inst.exports.memory.buffer), filestat_ptr);
|
|
193
|
+
}
|
|
194
|
+
return ret;
|
|
195
|
+
}
|
|
196
|
+
return wasi.ERRNO_BADF;
|
|
197
|
+
},
|
|
198
|
+
fd_filestat_set_size: (fd, size) => {
|
|
199
|
+
if (this.fds[fd] != undefined) {
|
|
200
|
+
return this.fds[fd].fd_filestat_set_size(size);
|
|
201
|
+
}
|
|
202
|
+
return wasi.ERRNO_BADF;
|
|
203
|
+
},
|
|
204
|
+
fd_filestat_set_times: (fd, atim, mtim, fst_flags) => {
|
|
205
|
+
if (this.fds[fd] != undefined) {
|
|
206
|
+
return this.fds[fd].fd_filestat_set_times(atim, mtim, fst_flags);
|
|
207
|
+
}
|
|
208
|
+
return wasi.ERRNO_BADF;
|
|
209
|
+
},
|
|
210
|
+
fd_pread: (fd, iovs_ptr, iovs_len, offset, nread_ptr) => {
|
|
211
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
212
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
213
|
+
if (this.fds[fd] != undefined) {
|
|
214
|
+
const iovecs = wasi.Iovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
|
|
215
|
+
let nread = 0;
|
|
216
|
+
for (const iovec of iovecs) {
|
|
217
|
+
const { ret, data } = this.fds[fd].fd_pread(iovec.buf_len, offset);
|
|
218
|
+
if (ret != wasi.ERRNO_SUCCESS) {
|
|
219
|
+
buffer.setUint32(nread_ptr, nread, true);
|
|
220
|
+
return ret;
|
|
221
|
+
}
|
|
222
|
+
buffer8.set(data, iovec.buf);
|
|
223
|
+
nread += data.length;
|
|
224
|
+
offset += BigInt(data.length);
|
|
225
|
+
if (data.length != iovec.buf_len) {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
buffer.setUint32(nread_ptr, nread, true);
|
|
230
|
+
return wasi.ERRNO_SUCCESS;
|
|
231
|
+
}
|
|
232
|
+
return wasi.ERRNO_BADF;
|
|
233
|
+
},
|
|
234
|
+
fd_prestat_get: (fd, buf_ptr) => {
|
|
235
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
236
|
+
if (this.fds[fd] != undefined) {
|
|
237
|
+
const { ret, prestat } = this.fds[fd].fd_prestat_get();
|
|
238
|
+
if (prestat != null) {
|
|
239
|
+
prestat.write_bytes(buffer, buf_ptr);
|
|
240
|
+
}
|
|
241
|
+
return ret;
|
|
242
|
+
}
|
|
243
|
+
return wasi.ERRNO_BADF;
|
|
244
|
+
},
|
|
245
|
+
fd_prestat_dir_name: (fd, path_ptr, path_len) => {
|
|
246
|
+
if (this.fds[fd] != undefined) {
|
|
247
|
+
const { ret, prestat } = this.fds[fd].fd_prestat_get();
|
|
248
|
+
if (prestat == null) {
|
|
249
|
+
return ret;
|
|
250
|
+
}
|
|
251
|
+
const prestat_dir_name = prestat.inner.pr_name;
|
|
252
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
253
|
+
buffer8.set(prestat_dir_name.slice(0, path_len), path_ptr);
|
|
254
|
+
return prestat_dir_name.byteLength > path_len
|
|
255
|
+
? wasi.ERRNO_NAMETOOLONG
|
|
256
|
+
: wasi.ERRNO_SUCCESS;
|
|
257
|
+
}
|
|
258
|
+
return wasi.ERRNO_BADF;
|
|
259
|
+
},
|
|
260
|
+
fd_pwrite: (fd, iovs_ptr, iovs_len, offset, nwritten_ptr) => {
|
|
261
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
262
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
263
|
+
if (this.fds[fd] != undefined) {
|
|
264
|
+
const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
|
|
265
|
+
let nwritten = 0;
|
|
266
|
+
for (const iovec of iovecs) {
|
|
267
|
+
const data = buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len);
|
|
268
|
+
const { ret, nwritten: nwritten_part } = this.fds[fd].fd_pwrite(data, offset);
|
|
269
|
+
if (ret != wasi.ERRNO_SUCCESS) {
|
|
270
|
+
buffer.setUint32(nwritten_ptr, nwritten, true);
|
|
271
|
+
return ret;
|
|
272
|
+
}
|
|
273
|
+
nwritten += nwritten_part;
|
|
274
|
+
offset += BigInt(nwritten_part);
|
|
275
|
+
if (nwritten_part != data.byteLength) {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
buffer.setUint32(nwritten_ptr, nwritten, true);
|
|
280
|
+
return wasi.ERRNO_SUCCESS;
|
|
281
|
+
}
|
|
282
|
+
return wasi.ERRNO_BADF;
|
|
283
|
+
},
|
|
284
|
+
fd_read: (fd, iovs_ptr, iovs_len, nread_ptr) => {
|
|
285
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
286
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
287
|
+
if (this.fds[fd] != undefined) {
|
|
288
|
+
const iovecs = wasi.Iovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
|
|
289
|
+
let nread = 0;
|
|
290
|
+
for (const iovec of iovecs) {
|
|
291
|
+
const { ret, data } = this.fds[fd].fd_read(iovec.buf_len);
|
|
292
|
+
if (ret != wasi.ERRNO_SUCCESS) {
|
|
293
|
+
buffer.setUint32(nread_ptr, nread, true);
|
|
294
|
+
return ret;
|
|
295
|
+
}
|
|
296
|
+
buffer8.set(data, iovec.buf);
|
|
297
|
+
nread += data.length;
|
|
298
|
+
if (data.length != iovec.buf_len) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
buffer.setUint32(nread_ptr, nread, true);
|
|
303
|
+
return wasi.ERRNO_SUCCESS;
|
|
304
|
+
}
|
|
305
|
+
return wasi.ERRNO_BADF;
|
|
306
|
+
},
|
|
307
|
+
fd_readdir: (fd, buf, buf_len, cookie, bufused_ptr) => {
|
|
308
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
309
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
310
|
+
if (this.fds[fd] != undefined) {
|
|
311
|
+
let bufused = 0;
|
|
312
|
+
for (;;) {
|
|
313
|
+
const { ret, dirent } = this.fds[fd].fd_readdir_single(cookie);
|
|
314
|
+
if (ret != 0) {
|
|
315
|
+
buffer.setUint32(bufused_ptr, bufused, true);
|
|
316
|
+
return ret;
|
|
317
|
+
}
|
|
318
|
+
if (dirent == null) {
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
if (buf_len - bufused < dirent.head_length()) {
|
|
322
|
+
bufused = buf_len;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
const head_bytes = new ArrayBuffer(dirent.head_length());
|
|
326
|
+
dirent.write_head_bytes(new DataView(head_bytes), 0);
|
|
327
|
+
buffer8.set(new Uint8Array(head_bytes).slice(0, Math.min(head_bytes.byteLength, buf_len - bufused)), buf);
|
|
328
|
+
buf += dirent.head_length();
|
|
329
|
+
bufused += dirent.head_length();
|
|
330
|
+
if (buf_len - bufused < dirent.name_length()) {
|
|
331
|
+
bufused = buf_len;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
dirent.write_name_bytes(buffer8, buf, buf_len - bufused);
|
|
335
|
+
buf += dirent.name_length();
|
|
336
|
+
bufused += dirent.name_length();
|
|
337
|
+
cookie = dirent.d_next;
|
|
338
|
+
}
|
|
339
|
+
buffer.setUint32(bufused_ptr, bufused, true);
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
return wasi.ERRNO_BADF;
|
|
343
|
+
},
|
|
344
|
+
fd_renumber: (fd, to) => {
|
|
345
|
+
if (this.fds[fd] != undefined && this.fds[to] != undefined) {
|
|
346
|
+
const ret = this.fds[to].fd_close();
|
|
347
|
+
if (ret != 0) {
|
|
348
|
+
return ret;
|
|
349
|
+
}
|
|
350
|
+
this.fds[to] = this.fds[fd];
|
|
351
|
+
this.fds[fd] = undefined;
|
|
352
|
+
this.#freeFds.push(fd);
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
return wasi.ERRNO_BADF;
|
|
356
|
+
},
|
|
357
|
+
fd_seek: (fd, offset, whence, offset_out_ptr) => {
|
|
358
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
359
|
+
if (this.fds[fd] != undefined) {
|
|
360
|
+
const { ret, offset: offset_out } = this.fds[fd].fd_seek(offset, whence);
|
|
361
|
+
buffer.setBigInt64(offset_out_ptr, offset_out, true);
|
|
362
|
+
return ret;
|
|
363
|
+
}
|
|
364
|
+
return wasi.ERRNO_BADF;
|
|
365
|
+
},
|
|
366
|
+
fd_sync: (fd) => {
|
|
367
|
+
if (this.fds[fd] != undefined) {
|
|
368
|
+
return this.fds[fd].fd_sync();
|
|
369
|
+
}
|
|
370
|
+
return wasi.ERRNO_BADF;
|
|
371
|
+
},
|
|
372
|
+
fd_tell: (fd, offset_ptr) => {
|
|
373
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
374
|
+
if (this.fds[fd] != undefined) {
|
|
375
|
+
const { ret, offset } = this.fds[fd].fd_tell();
|
|
376
|
+
buffer.setBigUint64(offset_ptr, offset, true);
|
|
377
|
+
return ret;
|
|
378
|
+
}
|
|
379
|
+
return wasi.ERRNO_BADF;
|
|
380
|
+
},
|
|
381
|
+
fd_write: (fd, iovs_ptr, iovs_len, nwritten_ptr) => {
|
|
382
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
383
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
384
|
+
if (this.fds[fd] != undefined) {
|
|
385
|
+
const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
|
|
386
|
+
let nwritten = 0;
|
|
387
|
+
for (const iovec of iovecs) {
|
|
388
|
+
const data = buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len);
|
|
389
|
+
const { ret, nwritten: nwritten_part } = this.fds[fd].fd_write(data);
|
|
390
|
+
if (ret != wasi.ERRNO_SUCCESS) {
|
|
391
|
+
buffer.setUint32(nwritten_ptr, nwritten, true);
|
|
392
|
+
return ret;
|
|
393
|
+
}
|
|
394
|
+
nwritten += nwritten_part;
|
|
395
|
+
if (nwritten_part != data.byteLength) {
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
buffer.setUint32(nwritten_ptr, nwritten, true);
|
|
400
|
+
return wasi.ERRNO_SUCCESS;
|
|
401
|
+
}
|
|
402
|
+
return wasi.ERRNO_BADF;
|
|
403
|
+
},
|
|
404
|
+
path_create_directory: (fd, path_ptr, path_len) => {
|
|
405
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
406
|
+
if (this.fds[fd] != undefined) {
|
|
407
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
408
|
+
return this.fds[fd].path_create_directory(path);
|
|
409
|
+
}
|
|
410
|
+
return wasi.ERRNO_BADF;
|
|
411
|
+
},
|
|
412
|
+
path_filestat_get: (fd, flags, path_ptr, path_len, filestat_ptr) => {
|
|
413
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
414
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
415
|
+
if (this.fds[fd] != undefined) {
|
|
416
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
417
|
+
const { ret, filestat } = this.fds[fd].path_filestat_get(flags, path);
|
|
418
|
+
if (filestat != null) {
|
|
419
|
+
filestat.write_bytes(buffer, filestat_ptr);
|
|
420
|
+
}
|
|
421
|
+
return ret;
|
|
422
|
+
}
|
|
423
|
+
return wasi.ERRNO_BADF;
|
|
424
|
+
},
|
|
425
|
+
path_filestat_set_times: (fd, flags, path_ptr, path_len, atim, mtim, fst_flags) => {
|
|
426
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
427
|
+
if (this.fds[fd] != undefined) {
|
|
428
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
429
|
+
return this.fds[fd].path_filestat_set_times(flags, path, atim, mtim, fst_flags);
|
|
430
|
+
}
|
|
431
|
+
return wasi.ERRNO_BADF;
|
|
432
|
+
},
|
|
433
|
+
path_link: (old_fd, old_flags, old_path_ptr, old_path_len, new_fd, new_path_ptr, new_path_len) => {
|
|
434
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
435
|
+
if (this.fds[old_fd] != undefined && this.fds[new_fd] != undefined) {
|
|
436
|
+
const old_path = new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr, old_path_ptr + old_path_len));
|
|
437
|
+
const new_path = new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr, new_path_ptr + new_path_len));
|
|
438
|
+
const { ret, inode_obj } = this.fds[old_fd].path_lookup(old_path, old_flags);
|
|
439
|
+
if (inode_obj == null) {
|
|
440
|
+
return ret;
|
|
441
|
+
}
|
|
442
|
+
return this.fds[new_fd].path_link(new_path, inode_obj, false);
|
|
443
|
+
}
|
|
444
|
+
return wasi.ERRNO_BADF;
|
|
445
|
+
},
|
|
446
|
+
path_open: (fd, dirflags, path_ptr, path_len, oflags, fs_rights_base, fs_rights_inheriting, fd_flags, opened_fd_ptr) => {
|
|
447
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
448
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
449
|
+
if (this.fds[fd] != undefined) {
|
|
450
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
451
|
+
this.log("path_open", path);
|
|
452
|
+
const { ret, fd_obj } = this.fds[fd].path_open(dirflags, path, oflags, fs_rights_base, fs_rights_inheriting, fd_flags);
|
|
453
|
+
if (ret != 0) {
|
|
454
|
+
return ret;
|
|
455
|
+
}
|
|
456
|
+
const opened_fd = (() => {
|
|
457
|
+
if (this.#freeFds.length > 0) {
|
|
458
|
+
const fd = this.#freeFds.pop();
|
|
459
|
+
this.fds[fd] = fd_obj;
|
|
460
|
+
return fd;
|
|
461
|
+
}
|
|
462
|
+
this.fds.push(fd_obj);
|
|
463
|
+
return this.fds.length - 1;
|
|
464
|
+
})();
|
|
465
|
+
buffer.setUint32(opened_fd_ptr, opened_fd, true);
|
|
466
|
+
return 0;
|
|
467
|
+
}
|
|
468
|
+
return wasi.ERRNO_BADF;
|
|
469
|
+
},
|
|
470
|
+
path_readlink: (fd, path_ptr, path_len, buf_ptr, buf_len, nread_ptr) => {
|
|
471
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
472
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
473
|
+
if (this.fds[fd] != undefined) {
|
|
474
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
475
|
+
const { ret, data } = this.fds[fd].path_readlink(path);
|
|
476
|
+
if (data != null) {
|
|
477
|
+
const data_buf = new TextEncoder().encode(data);
|
|
478
|
+
if (data_buf.length > buf_len) {
|
|
479
|
+
buffer.setUint32(nread_ptr, 0, true);
|
|
480
|
+
return wasi.ERRNO_BADF;
|
|
481
|
+
}
|
|
482
|
+
buffer8.set(data_buf, buf_ptr);
|
|
483
|
+
buffer.setUint32(nread_ptr, data_buf.length, true);
|
|
484
|
+
}
|
|
485
|
+
return ret;
|
|
486
|
+
}
|
|
487
|
+
return wasi.ERRNO_BADF;
|
|
488
|
+
},
|
|
489
|
+
path_remove_directory: (fd, path_ptr, path_len) => {
|
|
490
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
491
|
+
if (this.fds[fd] != undefined) {
|
|
492
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
493
|
+
return this.fds[fd].path_remove_directory(path);
|
|
494
|
+
}
|
|
495
|
+
return wasi.ERRNO_BADF;
|
|
496
|
+
},
|
|
497
|
+
path_rename: (fd, old_path_ptr, old_path_len, new_fd, new_path_ptr, new_path_len) => {
|
|
498
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
499
|
+
if (this.fds[fd] != undefined && this.fds[new_fd] != undefined) {
|
|
500
|
+
const old_path = new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr, old_path_ptr + old_path_len));
|
|
501
|
+
const new_path = new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr, new_path_ptr + new_path_len));
|
|
502
|
+
const { ret: unlinkRet, inode_obj } = this.fds[fd].path_unlink(old_path);
|
|
503
|
+
if (inode_obj == null) {
|
|
504
|
+
return unlinkRet;
|
|
505
|
+
}
|
|
506
|
+
const linkRet = this.fds[new_fd].path_link(new_path, inode_obj, true);
|
|
507
|
+
if (linkRet != wasi.ERRNO_SUCCESS) {
|
|
508
|
+
if (this.fds[fd].path_link(old_path, inode_obj, true) !=
|
|
509
|
+
wasi.ERRNO_SUCCESS) {
|
|
510
|
+
throw "path_link should always return success when relinking an inode back to the original place";
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return linkRet;
|
|
514
|
+
}
|
|
515
|
+
return wasi.ERRNO_BADF;
|
|
516
|
+
},
|
|
517
|
+
path_symlink: (old_path_ptr, old_path_len, fd, _new_path_ptr, _new_path_len) => {
|
|
518
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
519
|
+
if (this.fds[fd] != undefined) {
|
|
520
|
+
new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr, old_path_ptr + old_path_len));
|
|
521
|
+
return wasi.ERRNO_NOTSUP;
|
|
522
|
+
}
|
|
523
|
+
return wasi.ERRNO_BADF;
|
|
524
|
+
},
|
|
525
|
+
path_unlink_file: (fd, path_ptr, path_len) => {
|
|
526
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer);
|
|
527
|
+
if (this.fds[fd] != undefined) {
|
|
528
|
+
const path = new TextDecoder("utf-8").decode(buffer8.slice(path_ptr, path_ptr + path_len));
|
|
529
|
+
return this.fds[fd].path_unlink_file(path);
|
|
530
|
+
}
|
|
531
|
+
return wasi.ERRNO_BADF;
|
|
532
|
+
},
|
|
533
|
+
poll_oneoff: (in_ptr, out_ptr, nsubscriptions, nevents_ptr) => {
|
|
534
|
+
if (nsubscriptions === 0) {
|
|
535
|
+
return wasi.ERRNO_INVAL;
|
|
536
|
+
}
|
|
537
|
+
const buffer = new DataView(this.inst.exports.memory.buffer);
|
|
538
|
+
const subscriptions = [];
|
|
539
|
+
for (let i = 0; i < nsubscriptions; i++) {
|
|
540
|
+
subscriptions.push(wasi.Subscription.read_bytes(buffer, in_ptr + i * wasi.Subscription.size()));
|
|
541
|
+
}
|
|
542
|
+
this.log("poll_oneoff: subscriptions", subscriptions);
|
|
543
|
+
const events = [];
|
|
544
|
+
let clockTimeout = null;
|
|
545
|
+
let clockUserdata = 0n;
|
|
546
|
+
for (const s of subscriptions) {
|
|
547
|
+
if (s.eventtype === wasi.EVENTTYPE_CLOCK) {
|
|
548
|
+
let getNow;
|
|
549
|
+
if (s.clockid === wasi.CLOCKID_MONOTONIC) {
|
|
550
|
+
getNow = () => BigInt(Math.round(performance.now() * 1_000_000));
|
|
551
|
+
}
|
|
552
|
+
else if (s.clockid === wasi.CLOCKID_REALTIME) {
|
|
553
|
+
getNow = () => BigInt(new Date().getTime()) * 1000000n;
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
events.push(new wasi.Event(s.userdata, wasi.ERRNO_INVAL, s.eventtype));
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
const endTime = (s.flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0
|
|
560
|
+
? s.timeout
|
|
561
|
+
: getNow() + s.timeout;
|
|
562
|
+
if (clockTimeout === null || endTime < clockTimeout) {
|
|
563
|
+
clockTimeout = endTime;
|
|
564
|
+
clockUserdata = s.userdata;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else if (s.eventtype === wasi.EVENTTYPE_FD_READ ||
|
|
568
|
+
s.eventtype === wasi.EVENTTYPE_FD_WRITE) {
|
|
569
|
+
if (this.fds[s.fd] == undefined) {
|
|
570
|
+
events.push(new wasi.Event(s.userdata, wasi.ERRNO_BADF, s.eventtype));
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
const pollResult = this.fds[s.fd].fd_poll(s.eventtype);
|
|
574
|
+
this.log("poll_oneoff: fd", s.fd, "poll result", pollResult);
|
|
575
|
+
if (pollResult.ready) {
|
|
576
|
+
events.push(new wasi.Event(s.userdata, wasi.ERRNO_SUCCESS, s.eventtype, pollResult.nbytes, pollResult.flags));
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
events.push(new wasi.Event(s.userdata, wasi.ERRNO_NOTSUP, s.eventtype));
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
// If no events ready and we have a clock, check if it expired
|
|
584
|
+
if (events.length === 0 && clockTimeout !== null) {
|
|
585
|
+
const getNow = subscriptions.find((s) => s.eventtype === wasi.EVENTTYPE_CLOCK)
|
|
586
|
+
?.clockid === wasi.CLOCKID_REALTIME
|
|
587
|
+
? () => BigInt(new Date().getTime()) * 1000000n
|
|
588
|
+
: () => BigInt(Math.round(performance.now() * 1_000_000));
|
|
589
|
+
if (getNow() >= clockTimeout) {
|
|
590
|
+
events.push(new wasi.Event(clockUserdata, wasi.ERRNO_SUCCESS, wasi.EVENTTYPE_CLOCK));
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// Write events to output buffer
|
|
594
|
+
for (let i = 0; i < events.length; i++) {
|
|
595
|
+
events[i].write_bytes(buffer, out_ptr + i * wasi.Event.size());
|
|
596
|
+
}
|
|
597
|
+
buffer.setUint32(nevents_ptr, events.length, true);
|
|
598
|
+
this.log("poll_oneoff: returning", events.length, "events");
|
|
599
|
+
return wasi.ERRNO_SUCCESS;
|
|
600
|
+
},
|
|
601
|
+
proc_exit: (exit_code) => {
|
|
602
|
+
throw new WASIProcExit(exit_code);
|
|
603
|
+
},
|
|
604
|
+
proc_raise: (sig) => {
|
|
605
|
+
throw "raised signal " + sig;
|
|
606
|
+
},
|
|
607
|
+
sched_yield: () => { },
|
|
608
|
+
random_get: (buf, buf_len) => {
|
|
609
|
+
const buffer8 = new Uint8Array(this.inst.exports.memory.buffer).subarray(buf, buf + buf_len);
|
|
610
|
+
if ("crypto" in globalThis &&
|
|
611
|
+
(typeof SharedArrayBuffer === "undefined" ||
|
|
612
|
+
!(this.inst.exports.memory.buffer instanceof SharedArrayBuffer))) {
|
|
613
|
+
for (let i = 0; i < buf_len; i += 65536) {
|
|
614
|
+
crypto.getRandomValues(buffer8.subarray(i, i + 65536));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
for (let i = 0; i < buf_len; i++) {
|
|
619
|
+
buffer8[i] = (Math.random() * 256) | 0;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
sock_recv: (_fd, _ri_data, _ri_flags) => {
|
|
624
|
+
throw "sockets not supported";
|
|
625
|
+
},
|
|
626
|
+
sock_send: (_fd, _si_data, _si_flags) => {
|
|
627
|
+
throw "sockets not supported";
|
|
628
|
+
},
|
|
629
|
+
sock_shutdown: (_fd, _how) => {
|
|
630
|
+
throw "sockets not supported";
|
|
631
|
+
},
|
|
632
|
+
sock_accept: (_fd, _flags) => {
|
|
633
|
+
throw "sockets not supported";
|
|
634
|
+
},
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
//# sourceMappingURL=wasi.js.map
|