@tybys/wasm-util 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +190 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/wasm-util.d.ts +113 -0
- package/dist/wasm-util.esm-bundler.js +1879 -0
- package/dist/wasm-util.esm.js +1879 -0
- package/dist/wasm-util.esm.min.js +1 -0
- package/dist/wasm-util.js +1894 -0
- package/dist/wasm-util.min.js +1 -0
- package/lib/cjs/asyncify.js +173 -0
- package/lib/cjs/index.js +11 -0
- package/lib/cjs/load.js +78 -0
- package/lib/cjs/memfs.js +2689 -0
- package/lib/cjs/memory.js +31 -0
- package/lib/cjs/wasi/error.js +103 -0
- package/lib/cjs/wasi/fd.js +226 -0
- package/lib/cjs/wasi/index.js +137 -0
- package/lib/cjs/wasi/path.js +174 -0
- package/lib/cjs/wasi/preview1.js +889 -0
- package/lib/cjs/wasi/rights.js +139 -0
- package/lib/cjs/wasi/types.js +179 -0
- package/lib/cjs/wasi/util.js +56 -0
- package/lib/mjs/asyncify.mjs +168 -0
- package/lib/mjs/index.mjs +7 -0
- package/lib/mjs/load.mjs +72 -0
- package/lib/mjs/memfs.mjs +2688 -0
- package/lib/mjs/memory.mjs +25 -0
- package/lib/mjs/wasi/error.mjs +97 -0
- package/lib/mjs/wasi/fd.mjs +216 -0
- package/lib/mjs/wasi/index.mjs +132 -0
- package/lib/mjs/wasi/path.mjs +168 -0
- package/lib/mjs/wasi/preview1.mjs +884 -0
- package/lib/mjs/wasi/rights.mjs +134 -0
- package/lib/mjs/wasi/types.mjs +175 -0
- package/lib/mjs/wasi/util.mjs +44 -0
- package/package.json +57 -0
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
import { resolve } from "./path.mjs";
|
|
2
|
+
import { WasiErrno, WasiRights, FileControlFlag, WasiFileControlFlag, WasiFdFlag, WasiFileType, WasiClockid, WasiFstFlag } from "./types.mjs";
|
|
3
|
+
import { FileDescriptorTable, concatBuffer, toFileStat } from "./fd.mjs";
|
|
4
|
+
import { WasiError } from "./error.mjs";
|
|
5
|
+
import { isPromiseLike } from "./util.mjs";
|
|
6
|
+
import { getRights } from "./rights.mjs";
|
|
7
|
+
import { extendMemory } from "../memory.mjs";
|
|
8
|
+
function copyMemory(targets, src) {
|
|
9
|
+
if (targets.length === 0 || src.length === 0)
|
|
10
|
+
return 0;
|
|
11
|
+
let copied = 0;
|
|
12
|
+
let left = src.length - copied;
|
|
13
|
+
for (let i = 0; i < targets.length; ++i) {
|
|
14
|
+
const target = targets[i];
|
|
15
|
+
if (left < target.length) {
|
|
16
|
+
target.set(src.subarray(copied, copied + left), 0);
|
|
17
|
+
copied += left;
|
|
18
|
+
left = 0;
|
|
19
|
+
return copied;
|
|
20
|
+
}
|
|
21
|
+
target.set(src.subarray(copied, copied + target.length), 0);
|
|
22
|
+
copied += target.length;
|
|
23
|
+
left -= target.length;
|
|
24
|
+
}
|
|
25
|
+
return copied;
|
|
26
|
+
}
|
|
27
|
+
const _memory = new WeakMap();
|
|
28
|
+
const _wasi = new WeakMap();
|
|
29
|
+
const _fs = new WeakMap();
|
|
30
|
+
function getMemory(wasi) {
|
|
31
|
+
return _memory.get(wasi);
|
|
32
|
+
}
|
|
33
|
+
function getFs(wasi) {
|
|
34
|
+
const fs = _fs.get(wasi);
|
|
35
|
+
if (!fs)
|
|
36
|
+
throw new Error('filesystem is unavailable');
|
|
37
|
+
return fs;
|
|
38
|
+
}
|
|
39
|
+
function handleError(err) {
|
|
40
|
+
if (err instanceof WasiError) {
|
|
41
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
42
|
+
console.warn(err);
|
|
43
|
+
}
|
|
44
|
+
return err.errno;
|
|
45
|
+
}
|
|
46
|
+
switch (err.code) {
|
|
47
|
+
case 'ENOENT': return WasiErrno.ENOENT;
|
|
48
|
+
case 'EBADF': return WasiErrno.EBADF;
|
|
49
|
+
case 'EINVAL': return WasiErrno.EINVAL;
|
|
50
|
+
case 'EPERM': return WasiErrno.EPERM;
|
|
51
|
+
case 'EPROTO': return WasiErrno.EPROTO;
|
|
52
|
+
case 'EEXIST': return WasiErrno.EEXIST;
|
|
53
|
+
case 'ENOTDIR': return WasiErrno.ENOTDIR;
|
|
54
|
+
case 'EMFILE': return WasiErrno.EMFILE;
|
|
55
|
+
case 'EACCES': return WasiErrno.EACCES;
|
|
56
|
+
case 'EISDIR': return WasiErrno.EISDIR;
|
|
57
|
+
case 'ENOTEMPTY': return WasiErrno.ENOTEMPTY;
|
|
58
|
+
case 'ENOSYS': return WasiErrno.ENOSYS;
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
function defineName(name, f) {
|
|
63
|
+
Object.defineProperty(f, 'name', { value: name });
|
|
64
|
+
return f;
|
|
65
|
+
}
|
|
66
|
+
function syscallWrap(name, f) {
|
|
67
|
+
return defineName(name, function () {
|
|
68
|
+
if (process.env.NODE_DEBUG_NATIVE === 'wasi') {
|
|
69
|
+
const args = Array.prototype.slice.call(arguments);
|
|
70
|
+
let debugArgs = [`${name}(${Array.from({ length: arguments.length }).map(() => '%d').join(', ')})`];
|
|
71
|
+
debugArgs = debugArgs.concat(args);
|
|
72
|
+
console.debug.apply(console, debugArgs);
|
|
73
|
+
}
|
|
74
|
+
let r;
|
|
75
|
+
try {
|
|
76
|
+
r = f.apply(this, arguments);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return handleError(err);
|
|
80
|
+
}
|
|
81
|
+
if (isPromiseLike(r)) {
|
|
82
|
+
return r.then(_ => _, handleError);
|
|
83
|
+
}
|
|
84
|
+
return r;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function resolvePath(fs, fileDescriptor, path, flags) {
|
|
88
|
+
let resolvedPath = resolve(fileDescriptor.realPath, path);
|
|
89
|
+
if ((flags & 1) === 1) {
|
|
90
|
+
try {
|
|
91
|
+
resolvedPath = fs.readlinkSync(resolvedPath);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (err.code !== 'EINVAL' && err.code !== 'ENOENT') {
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return resolvedPath;
|
|
100
|
+
}
|
|
101
|
+
const encoder = new TextEncoder();
|
|
102
|
+
const decoder = new TextDecoder();
|
|
103
|
+
function readStdin() {
|
|
104
|
+
const value = window.prompt();
|
|
105
|
+
if (value === null)
|
|
106
|
+
return new Uint8Array();
|
|
107
|
+
const buffer = new TextEncoder().encode(value + '\n');
|
|
108
|
+
return buffer;
|
|
109
|
+
}
|
|
110
|
+
export class WASI {
|
|
111
|
+
constructor(args, env, preopens, stdio, filesystem, print, printErr) {
|
|
112
|
+
this._setMemory = function _setMemory(m) {
|
|
113
|
+
if (!(m instanceof WebAssembly.Memory)) {
|
|
114
|
+
throw new TypeError('"instance.exports.memory" property must be a WebAssembly.Memory');
|
|
115
|
+
}
|
|
116
|
+
_memory.set(this, extendMemory(m));
|
|
117
|
+
};
|
|
118
|
+
this.args_get = syscallWrap('args_get', function (argv, argv_buf) {
|
|
119
|
+
argv = Number(argv);
|
|
120
|
+
argv_buf = Number(argv_buf);
|
|
121
|
+
if (argv === 0 || argv_buf === 0) {
|
|
122
|
+
return WasiErrno.EINVAL;
|
|
123
|
+
}
|
|
124
|
+
const { HEAPU8, view } = getMemory(this);
|
|
125
|
+
const wasi = _wasi.get(this);
|
|
126
|
+
const args = wasi.args;
|
|
127
|
+
for (let i = 0; i < args.length; ++i) {
|
|
128
|
+
const arg = args[i];
|
|
129
|
+
view.setInt32(argv, argv_buf, true);
|
|
130
|
+
argv += 4;
|
|
131
|
+
const data = encoder.encode(arg + '\0');
|
|
132
|
+
HEAPU8.set(data, argv_buf);
|
|
133
|
+
argv_buf += data.length;
|
|
134
|
+
}
|
|
135
|
+
return WasiErrno.ESUCCESS;
|
|
136
|
+
});
|
|
137
|
+
this.args_sizes_get = syscallWrap('args_sizes_get', function (argc, argv_buf_size) {
|
|
138
|
+
argc = Number(argc);
|
|
139
|
+
argv_buf_size = Number(argv_buf_size);
|
|
140
|
+
if (argc === 0 || argv_buf_size === 0) {
|
|
141
|
+
return WasiErrno.EINVAL;
|
|
142
|
+
}
|
|
143
|
+
const { view } = getMemory(this);
|
|
144
|
+
const wasi = _wasi.get(this);
|
|
145
|
+
const args = wasi.args;
|
|
146
|
+
view.setUint32(argc, args.length, true);
|
|
147
|
+
view.setUint32(argv_buf_size, encoder.encode(args.join('\0') + '\0').length, true);
|
|
148
|
+
return WasiErrno.ESUCCESS;
|
|
149
|
+
});
|
|
150
|
+
this.environ_get = syscallWrap('environ_get', function (environ, environ_buf) {
|
|
151
|
+
environ = Number(environ);
|
|
152
|
+
environ_buf = Number(environ_buf);
|
|
153
|
+
if (environ === 0 || environ_buf === 0) {
|
|
154
|
+
return WasiErrno.EINVAL;
|
|
155
|
+
}
|
|
156
|
+
const { HEAPU8, view } = getMemory(this);
|
|
157
|
+
const wasi = _wasi.get(this);
|
|
158
|
+
const env = wasi.env;
|
|
159
|
+
for (let i = 0; i < env.length; ++i) {
|
|
160
|
+
const pair = env[i];
|
|
161
|
+
view.setInt32(environ, environ_buf, true);
|
|
162
|
+
environ += 4;
|
|
163
|
+
const data = encoder.encode(pair + '\0');
|
|
164
|
+
HEAPU8.set(data, environ_buf);
|
|
165
|
+
environ_buf += data.length;
|
|
166
|
+
}
|
|
167
|
+
return WasiErrno.ESUCCESS;
|
|
168
|
+
});
|
|
169
|
+
this.environ_sizes_get = syscallWrap('environ_sizes_get', function (len, buflen) {
|
|
170
|
+
len = Number(len);
|
|
171
|
+
buflen = Number(buflen);
|
|
172
|
+
if (len === 0 || buflen === 0) {
|
|
173
|
+
return WasiErrno.EINVAL;
|
|
174
|
+
}
|
|
175
|
+
const { view } = getMemory(this);
|
|
176
|
+
const wasi = _wasi.get(this);
|
|
177
|
+
view.setUint32(len, wasi.env.length, true);
|
|
178
|
+
view.setUint32(buflen, encoder.encode(wasi.env.join('\0') + '\0').length, true);
|
|
179
|
+
return WasiErrno.ESUCCESS;
|
|
180
|
+
});
|
|
181
|
+
this.clock_res_get = syscallWrap('clock_res_get', function (id, resolution) {
|
|
182
|
+
resolution = Number(resolution);
|
|
183
|
+
if (resolution === 0) {
|
|
184
|
+
return WasiErrno.EINVAL;
|
|
185
|
+
}
|
|
186
|
+
const { view } = getMemory(this);
|
|
187
|
+
switch (id) {
|
|
188
|
+
case WasiClockid.REALTIME:
|
|
189
|
+
view.setBigUint64(resolution, BigInt(1000000), true);
|
|
190
|
+
return WasiErrno.ESUCCESS;
|
|
191
|
+
case WasiClockid.MONOTONIC:
|
|
192
|
+
case WasiClockid.PROCESS_CPUTIME_ID:
|
|
193
|
+
case WasiClockid.THREAD_CPUTIME_ID:
|
|
194
|
+
view.setBigUint64(resolution, BigInt(1000), true);
|
|
195
|
+
return WasiErrno.ESUCCESS;
|
|
196
|
+
default: return WasiErrno.EINVAL;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
this.clock_time_get = syscallWrap('clock_time_get', function (id, _percision, time) {
|
|
200
|
+
time = Number(time);
|
|
201
|
+
if (time === 0) {
|
|
202
|
+
return WasiErrno.EINVAL;
|
|
203
|
+
}
|
|
204
|
+
const { view } = getMemory(this);
|
|
205
|
+
switch (id) {
|
|
206
|
+
case WasiClockid.REALTIME:
|
|
207
|
+
view.setBigUint64(time, BigInt(Date.now()) * BigInt(1000000), true);
|
|
208
|
+
return WasiErrno.ESUCCESS;
|
|
209
|
+
case WasiClockid.MONOTONIC:
|
|
210
|
+
case WasiClockid.PROCESS_CPUTIME_ID:
|
|
211
|
+
case WasiClockid.THREAD_CPUTIME_ID: {
|
|
212
|
+
const t = performance.now();
|
|
213
|
+
const s = Math.trunc(t);
|
|
214
|
+
const ms = Math.floor((t - s) * 1000);
|
|
215
|
+
const result = BigInt(s) * BigInt(1000000000) + BigInt(ms) * BigInt(1000000);
|
|
216
|
+
view.setBigUint64(time, result, true);
|
|
217
|
+
return WasiErrno.ESUCCESS;
|
|
218
|
+
}
|
|
219
|
+
default: return WasiErrno.EINVAL;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
this.fd_advise = syscallWrap('fd_advise', function (_fd, _offset, _len, _advice) {
|
|
223
|
+
return WasiErrno.ENOSYS;
|
|
224
|
+
});
|
|
225
|
+
this.fd_allocate = syscallWrap('fd_allocate', function (fd, offset, len) {
|
|
226
|
+
const wasi = _wasi.get(this);
|
|
227
|
+
const fs = getFs(this);
|
|
228
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_ALLOCATE, BigInt(0));
|
|
229
|
+
const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
|
|
230
|
+
if (stat.size < offset + len) {
|
|
231
|
+
fs.truncateSync(fileDescriptor.fd, Number(offset + len));
|
|
232
|
+
}
|
|
233
|
+
return WasiErrno.ESUCCESS;
|
|
234
|
+
});
|
|
235
|
+
this.fd_close = syscallWrap('fd_close', function (fd) {
|
|
236
|
+
const wasi = _wasi.get(this);
|
|
237
|
+
const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
|
|
238
|
+
const fs = getFs(this);
|
|
239
|
+
fs.closeSync(fileDescriptor.fd);
|
|
240
|
+
wasi.fds.remove(fd);
|
|
241
|
+
return WasiErrno.ESUCCESS;
|
|
242
|
+
});
|
|
243
|
+
this.fd_datasync = syscallWrap('fd_datasync', function (fd) {
|
|
244
|
+
const wasi = _wasi.get(this);
|
|
245
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_DATASYNC, BigInt(0));
|
|
246
|
+
const fs = getFs(this);
|
|
247
|
+
fs.fdatasyncSync(fileDescriptor.fd);
|
|
248
|
+
return WasiErrno.ESUCCESS;
|
|
249
|
+
});
|
|
250
|
+
this.fd_fdstat_get = syscallWrap('fd_fdstat_get', function (fd, fdstat) {
|
|
251
|
+
fdstat = Number(fdstat);
|
|
252
|
+
if (fdstat === 0) {
|
|
253
|
+
return WasiErrno.EINVAL;
|
|
254
|
+
}
|
|
255
|
+
const wasi = _wasi.get(this);
|
|
256
|
+
const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
|
|
257
|
+
const { view } = getMemory(this);
|
|
258
|
+
view.setUint16(fdstat, fileDescriptor.type, true);
|
|
259
|
+
view.setUint16(fdstat + 2, 0, true);
|
|
260
|
+
view.setBigUint64(fdstat + 8, fileDescriptor.rightsBase, true);
|
|
261
|
+
view.setBigUint64(fdstat + 16, fileDescriptor.rightsInheriting, true);
|
|
262
|
+
return WasiErrno.ESUCCESS;
|
|
263
|
+
});
|
|
264
|
+
this.fd_fdstat_set_flags = syscallWrap('fd_fdstat_set_flags', function (_fd, _flags) {
|
|
265
|
+
return WasiErrno.ENOSYS;
|
|
266
|
+
});
|
|
267
|
+
this.fd_fdstat_set_rights = syscallWrap('fd_fdstat_set_rights', function (fd, rightsBase, rightsInheriting) {
|
|
268
|
+
const wasi = _wasi.get(this);
|
|
269
|
+
const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
|
|
270
|
+
if ((rightsBase | fileDescriptor.rightsBase) > fileDescriptor.rightsBase) {
|
|
271
|
+
return WasiErrno.ENOTCAPABLE;
|
|
272
|
+
}
|
|
273
|
+
if ((rightsInheriting | fileDescriptor.rightsInheriting) >
|
|
274
|
+
fileDescriptor.rightsInheriting) {
|
|
275
|
+
return WasiErrno.ENOTCAPABLE;
|
|
276
|
+
}
|
|
277
|
+
fileDescriptor.rightsBase = rightsBase;
|
|
278
|
+
fileDescriptor.rightsInheriting = rightsInheriting;
|
|
279
|
+
return WasiErrno.ESUCCESS;
|
|
280
|
+
});
|
|
281
|
+
this.fd_filestat_get = syscallWrap('fd_filestat_get', function (fd, buf) {
|
|
282
|
+
buf = Number(buf);
|
|
283
|
+
if (buf === 0)
|
|
284
|
+
return WasiErrno.EINVAL;
|
|
285
|
+
const wasi = _wasi.get(this);
|
|
286
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_FILESTAT_GET, BigInt(0));
|
|
287
|
+
const fs = getFs(this);
|
|
288
|
+
const stat = fs.fstatSync(fileDescriptor.fd, { bigint: true });
|
|
289
|
+
const { view } = getMemory(this);
|
|
290
|
+
toFileStat(view, buf, stat);
|
|
291
|
+
return WasiErrno.ESUCCESS;
|
|
292
|
+
});
|
|
293
|
+
this.fd_filestat_set_size = syscallWrap('fd_filestat_set_size', function (fd, size) {
|
|
294
|
+
const wasi = _wasi.get(this);
|
|
295
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_FILESTAT_SET_SIZE, BigInt(0));
|
|
296
|
+
const fs = getFs(this);
|
|
297
|
+
fs.ftruncateSync(fileDescriptor.fd, Number(size));
|
|
298
|
+
return WasiErrno.ESUCCESS;
|
|
299
|
+
});
|
|
300
|
+
this.fd_filestat_set_times = syscallWrap('fd_filestat_set_times', function (fd, atim, mtim, flags) {
|
|
301
|
+
const wasi = _wasi.get(this);
|
|
302
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_FILESTAT_SET_TIMES, BigInt(0));
|
|
303
|
+
if ((flags & WasiFstFlag.SET_ATIM_NOW) === WasiFstFlag.SET_ATIM_NOW) {
|
|
304
|
+
atim = BigInt(Date.now() * 1000000);
|
|
305
|
+
}
|
|
306
|
+
if ((flags & WasiFstFlag.SET_MTIM_NOW) === WasiFstFlag.SET_MTIM_NOW) {
|
|
307
|
+
mtim = BigInt(Date.now() * 1000000);
|
|
308
|
+
}
|
|
309
|
+
const fs = getFs(this);
|
|
310
|
+
fs.futimesSync(fileDescriptor.fd, Number(atim), Number(mtim));
|
|
311
|
+
return WasiErrno.ESUCCESS;
|
|
312
|
+
});
|
|
313
|
+
this.fd_pread = syscallWrap('fd_pread', function (fd, iovs, iovslen, offset, size) {
|
|
314
|
+
iovs = Number(iovs);
|
|
315
|
+
size = Number(size);
|
|
316
|
+
if (iovs === 0 || size === 0) {
|
|
317
|
+
return WasiErrno.EINVAL;
|
|
318
|
+
}
|
|
319
|
+
const { HEAPU8, view } = getMemory(this);
|
|
320
|
+
const wasi = _wasi.get(this);
|
|
321
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ | WasiRights.FD_SEEK, BigInt(0));
|
|
322
|
+
let totalSize = 0;
|
|
323
|
+
const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
|
|
324
|
+
const offset = iovs + (i * 8);
|
|
325
|
+
const buf = view.getInt32(offset, true);
|
|
326
|
+
const bufLen = view.getUint32(offset + 4, true);
|
|
327
|
+
totalSize += bufLen;
|
|
328
|
+
return HEAPU8.subarray(buf, buf + bufLen);
|
|
329
|
+
});
|
|
330
|
+
let nread = 0;
|
|
331
|
+
const buffer = new Uint8Array(totalSize);
|
|
332
|
+
buffer._isBuffer = true;
|
|
333
|
+
const fs = getFs(this);
|
|
334
|
+
const bytesRead = fs.readSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(offset));
|
|
335
|
+
nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
|
|
336
|
+
view.setUint32(size, nread, true);
|
|
337
|
+
return WasiErrno.ESUCCESS;
|
|
338
|
+
});
|
|
339
|
+
this.fd_prestat_get = syscallWrap('fd_prestat_get', function (fd, prestat) {
|
|
340
|
+
prestat = Number(prestat);
|
|
341
|
+
if (prestat === 0) {
|
|
342
|
+
return WasiErrno.EINVAL;
|
|
343
|
+
}
|
|
344
|
+
const wasi = _wasi.get(this);
|
|
345
|
+
let fileDescriptor;
|
|
346
|
+
try {
|
|
347
|
+
fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
if (err instanceof WasiError)
|
|
351
|
+
return err.errno;
|
|
352
|
+
throw err;
|
|
353
|
+
}
|
|
354
|
+
if (fileDescriptor.preopen !== 1)
|
|
355
|
+
return WasiErrno.EINVAL;
|
|
356
|
+
const { view } = getMemory(this);
|
|
357
|
+
// preopen type is dir(0)
|
|
358
|
+
view.setUint32(prestat, 0, true);
|
|
359
|
+
view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length + 1, true);
|
|
360
|
+
return WasiErrno.ESUCCESS;
|
|
361
|
+
});
|
|
362
|
+
this.fd_prestat_dir_name = syscallWrap('fd_prestat_dir_name', function (fd, path, path_len) {
|
|
363
|
+
path = Number(path);
|
|
364
|
+
path_len = Number(path_len);
|
|
365
|
+
if (path === 0) {
|
|
366
|
+
return WasiErrno.EINVAL;
|
|
367
|
+
}
|
|
368
|
+
const wasi = _wasi.get(this);
|
|
369
|
+
const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
|
|
370
|
+
if (fileDescriptor.preopen !== 1)
|
|
371
|
+
return WasiErrno.EBADF;
|
|
372
|
+
const buffer = encoder.encode(fileDescriptor.path + '\0');
|
|
373
|
+
const size = buffer.length;
|
|
374
|
+
if (size > path_len)
|
|
375
|
+
return WasiErrno.ENOBUFS;
|
|
376
|
+
const { HEAPU8 } = getMemory(this);
|
|
377
|
+
HEAPU8.set(buffer, path);
|
|
378
|
+
return WasiErrno.ESUCCESS;
|
|
379
|
+
});
|
|
380
|
+
this.fd_pwrite = syscallWrap('fd_pwrite', function (fd, iovs, iovslen, offset, size) {
|
|
381
|
+
iovs = Number(iovs);
|
|
382
|
+
size = Number(size);
|
|
383
|
+
if (iovs === 0 || size === 0) {
|
|
384
|
+
return WasiErrno.EINVAL;
|
|
385
|
+
}
|
|
386
|
+
const { HEAPU8, view } = getMemory(this);
|
|
387
|
+
const wasi = _wasi.get(this);
|
|
388
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE | WasiRights.FD_SEEK, BigInt(0));
|
|
389
|
+
const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
|
|
390
|
+
const offset = iovs + (i * 8);
|
|
391
|
+
const buf = view.getInt32(offset, true);
|
|
392
|
+
const bufLen = view.getUint32(offset + 4, true);
|
|
393
|
+
return HEAPU8.subarray(buf, buf + bufLen);
|
|
394
|
+
}));
|
|
395
|
+
const fs = getFs(this);
|
|
396
|
+
const nwritten = fs.writeSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(offset));
|
|
397
|
+
view.setUint32(size, nwritten, true);
|
|
398
|
+
return WasiErrno.ESUCCESS;
|
|
399
|
+
});
|
|
400
|
+
this.fd_read = syscallWrap('fd_read', function (fd, iovs, iovslen, size) {
|
|
401
|
+
iovs = Number(iovs);
|
|
402
|
+
size = Number(size);
|
|
403
|
+
if (iovs === 0 || size === 0) {
|
|
404
|
+
return WasiErrno.EINVAL;
|
|
405
|
+
}
|
|
406
|
+
const { HEAPU8, view } = getMemory(this);
|
|
407
|
+
const wasi = _wasi.get(this);
|
|
408
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ, BigInt(0));
|
|
409
|
+
let totalSize = 0;
|
|
410
|
+
const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
|
|
411
|
+
const offset = iovs + (i * 8);
|
|
412
|
+
const buf = view.getInt32(offset, true);
|
|
413
|
+
const bufLen = view.getUint32(offset + 4, true);
|
|
414
|
+
totalSize += bufLen;
|
|
415
|
+
return HEAPU8.subarray(buf, buf + bufLen);
|
|
416
|
+
});
|
|
417
|
+
let buffer;
|
|
418
|
+
let nread = 0;
|
|
419
|
+
if (fd === 0) {
|
|
420
|
+
buffer = readStdin();
|
|
421
|
+
nread = buffer ? copyMemory(ioVecs, buffer) : 0;
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
buffer = new Uint8Array(totalSize);
|
|
425
|
+
buffer._isBuffer = true;
|
|
426
|
+
const fs = getFs(this);
|
|
427
|
+
const bytesRead = fs.readSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(fileDescriptor.pos));
|
|
428
|
+
nread = buffer ? copyMemory(ioVecs, buffer.subarray(0, bytesRead)) : 0;
|
|
429
|
+
fileDescriptor.pos += BigInt(nread);
|
|
430
|
+
}
|
|
431
|
+
view.setUint32(size, nread, true);
|
|
432
|
+
return WasiErrno.ESUCCESS;
|
|
433
|
+
});
|
|
434
|
+
this.fd_seek = syscallWrap('fd_seek', function (fd, offset, whence, newOffset) {
|
|
435
|
+
newOffset = Number(newOffset);
|
|
436
|
+
if (newOffset === 0) {
|
|
437
|
+
return WasiErrno.EINVAL;
|
|
438
|
+
}
|
|
439
|
+
if (fd === 0 || fd === 1 || fd === 2)
|
|
440
|
+
return WasiErrno.ESUCCESS;
|
|
441
|
+
const wasi = _wasi.get(this);
|
|
442
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_SEEK, BigInt(0));
|
|
443
|
+
const r = fileDescriptor.seek(offset, whence);
|
|
444
|
+
const { view } = getMemory(this);
|
|
445
|
+
view.setBigUint64(newOffset, r, true);
|
|
446
|
+
return WasiErrno.ESUCCESS;
|
|
447
|
+
});
|
|
448
|
+
this.fd_readdir = syscallWrap('fd_readdir', function (fd, buf, buf_len, cookie, bufused) {
|
|
449
|
+
buf = Number(buf);
|
|
450
|
+
buf_len = Number(buf_len);
|
|
451
|
+
bufused = Number(bufused);
|
|
452
|
+
if (buf === 0 || bufused === 0)
|
|
453
|
+
return WasiErrno.ESUCCESS;
|
|
454
|
+
const wasi = _wasi.get(this);
|
|
455
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READDIR, BigInt(0));
|
|
456
|
+
const fs = getFs(this);
|
|
457
|
+
const entries = fs.readdirSync(fileDescriptor.realPath, { withFileTypes: true });
|
|
458
|
+
const { HEAPU8, view } = getMemory(this);
|
|
459
|
+
let bufferUsed = 0;
|
|
460
|
+
for (let i = Number(cookie); i < entries.length; i++) {
|
|
461
|
+
const nameData = encoder.encode(entries[i].name);
|
|
462
|
+
const entryInfo = fs.statSync(resolve(fileDescriptor.realPath, entries[i].name), { bigint: true });
|
|
463
|
+
const entryData = new Uint8Array(24 + nameData.byteLength);
|
|
464
|
+
const entryView = new DataView(entryData.buffer);
|
|
465
|
+
entryView.setBigUint64(0, BigInt(i + 1), true);
|
|
466
|
+
entryView.setBigUint64(8, BigInt(entryInfo.ino ? entryInfo.ino : 0), true);
|
|
467
|
+
entryView.setUint32(16, nameData.byteLength, true);
|
|
468
|
+
let type;
|
|
469
|
+
if (entries[i].isFile()) {
|
|
470
|
+
type = WasiFileType.REGULAR_FILE;
|
|
471
|
+
}
|
|
472
|
+
else if (entries[i].isDirectory()) {
|
|
473
|
+
type = WasiFileType.DIRECTORY;
|
|
474
|
+
}
|
|
475
|
+
else if (entries[i].isSymbolicLink()) {
|
|
476
|
+
type = WasiFileType.SYMBOLIC_LINK;
|
|
477
|
+
}
|
|
478
|
+
else if (entries[i].isCharacterDevice()) {
|
|
479
|
+
type = WasiFileType.CHARACTER_DEVICE;
|
|
480
|
+
}
|
|
481
|
+
else if (entries[i].isBlockDevice()) {
|
|
482
|
+
type = WasiFileType.BLOCK_DEVICE;
|
|
483
|
+
}
|
|
484
|
+
else if (entries[i].isSocket()) {
|
|
485
|
+
type = WasiFileType.SOCKET_STREAM;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
type = WasiFileType.UNKNOWN;
|
|
489
|
+
}
|
|
490
|
+
entryView.setUint8(20, type);
|
|
491
|
+
entryData.set(nameData, 24);
|
|
492
|
+
const data = entryData.slice(0, Math.min(entryData.length, buf_len - bufferUsed));
|
|
493
|
+
HEAPU8.set(data, buf + bufferUsed);
|
|
494
|
+
bufferUsed += data.byteLength;
|
|
495
|
+
}
|
|
496
|
+
view.setUint32(bufused, bufferUsed, true);
|
|
497
|
+
return WasiErrno.ESUCCESS;
|
|
498
|
+
});
|
|
499
|
+
this.fd_renumber = syscallWrap('fd_renumber', function (from, to) {
|
|
500
|
+
const wasi = _wasi.get(this);
|
|
501
|
+
wasi.fds.renumber(to, from);
|
|
502
|
+
return WasiErrno.ESUCCESS;
|
|
503
|
+
});
|
|
504
|
+
this.fd_sync = syscallWrap('fd_sync', function (fd) {
|
|
505
|
+
const wasi = _wasi.get(this);
|
|
506
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_SYNC, BigInt(0));
|
|
507
|
+
const fs = getFs(this);
|
|
508
|
+
fs.fsyncSync(fileDescriptor.fd);
|
|
509
|
+
return WasiErrno.ESUCCESS;
|
|
510
|
+
});
|
|
511
|
+
this.fd_tell = syscallWrap('fd_tell', function (fd, offset) {
|
|
512
|
+
const wasi = _wasi.get(this);
|
|
513
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_TELL, BigInt(0));
|
|
514
|
+
const pos = BigInt(fileDescriptor.pos);
|
|
515
|
+
const { view } = getMemory(this);
|
|
516
|
+
view.setBigUint64(Number(offset), pos, true);
|
|
517
|
+
return WasiErrno.ESUCCESS;
|
|
518
|
+
});
|
|
519
|
+
this.fd_write = syscallWrap('fd_write', function (fd, iovs, iovslen, size) {
|
|
520
|
+
iovs = Number(iovs);
|
|
521
|
+
size = Number(size);
|
|
522
|
+
if (iovs === 0 || size === 0) {
|
|
523
|
+
return WasiErrno.EINVAL;
|
|
524
|
+
}
|
|
525
|
+
const { HEAPU8, view } = getMemory(this);
|
|
526
|
+
const wasi = _wasi.get(this);
|
|
527
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE, BigInt(0));
|
|
528
|
+
const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
|
|
529
|
+
const offset = iovs + (i * 8);
|
|
530
|
+
const buf = view.getInt32(offset, true);
|
|
531
|
+
const bufLen = view.getUint32(offset + 4, true);
|
|
532
|
+
return HEAPU8.subarray(buf, buf + bufLen);
|
|
533
|
+
}));
|
|
534
|
+
let nwritten;
|
|
535
|
+
if (fd === 1 || fd === 2) {
|
|
536
|
+
nwritten = fileDescriptor.write(buffer);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
const fs = getFs(this);
|
|
540
|
+
nwritten = fs.writeSync(fileDescriptor.fd, buffer, 0, buffer.length, Number(fileDescriptor.pos));
|
|
541
|
+
fileDescriptor.pos += BigInt(nwritten);
|
|
542
|
+
}
|
|
543
|
+
view.setUint32(size, nwritten, true);
|
|
544
|
+
return WasiErrno.ESUCCESS;
|
|
545
|
+
});
|
|
546
|
+
this.path_create_directory = syscallWrap('path_create_directory', function (fd, path, path_len) {
|
|
547
|
+
path = Number(path);
|
|
548
|
+
path_len = Number(path_len);
|
|
549
|
+
if (path === 0) {
|
|
550
|
+
return WasiErrno.EINVAL;
|
|
551
|
+
}
|
|
552
|
+
const { HEAPU8 } = getMemory(this);
|
|
553
|
+
const wasi = _wasi.get(this);
|
|
554
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_CREATE_DIRECTORY, BigInt(0));
|
|
555
|
+
let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
556
|
+
pathString = resolve(fileDescriptor.realPath, pathString);
|
|
557
|
+
const fs = getFs(this);
|
|
558
|
+
fs.mkdirSync(pathString);
|
|
559
|
+
return WasiErrno.ESUCCESS;
|
|
560
|
+
});
|
|
561
|
+
this.path_filestat_get = syscallWrap('path_filestat_get', function (fd, flags, path, path_len, filestat) {
|
|
562
|
+
path = Number(path);
|
|
563
|
+
path_len = Number(path_len);
|
|
564
|
+
filestat = Number(filestat);
|
|
565
|
+
if (path === 0 || filestat === 0) {
|
|
566
|
+
return WasiErrno.EINVAL;
|
|
567
|
+
}
|
|
568
|
+
const { HEAPU8, view } = getMemory(this);
|
|
569
|
+
const wasi = _wasi.get(this);
|
|
570
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_FILESTAT_GET, BigInt(0));
|
|
571
|
+
let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
572
|
+
const fs = getFs(this);
|
|
573
|
+
pathString = resolve(fileDescriptor.realPath, pathString);
|
|
574
|
+
let stat;
|
|
575
|
+
if ((flags & 1) === 1) {
|
|
576
|
+
stat = fs.statSync(pathString, { bigint: true });
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
stat = fs.lstatSync(pathString, { bigint: true });
|
|
580
|
+
}
|
|
581
|
+
toFileStat(view, filestat, stat);
|
|
582
|
+
return WasiErrno.ESUCCESS;
|
|
583
|
+
});
|
|
584
|
+
this.path_filestat_set_times = syscallWrap('path_filestat_set_times', function (fd, flags, path, path_len, atim, mtim, fst_flags) {
|
|
585
|
+
path = Number(path);
|
|
586
|
+
path_len = Number(path_len);
|
|
587
|
+
if (path === 0)
|
|
588
|
+
return WasiErrno.EINVAL;
|
|
589
|
+
if ((fst_flags) & ~(WasiFstFlag.SET_ATIM |
|
|
590
|
+
WasiFstFlag.SET_ATIM_NOW |
|
|
591
|
+
WasiFstFlag.SET_MTIM |
|
|
592
|
+
WasiFstFlag.SET_MTIM_NOW)) {
|
|
593
|
+
return WasiErrno.EINVAL;
|
|
594
|
+
}
|
|
595
|
+
const { HEAPU8 } = getMemory(this);
|
|
596
|
+
const wasi = _wasi.get(this);
|
|
597
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
|
|
598
|
+
const fs = getFs(this);
|
|
599
|
+
const resolvedPath = resolvePath(fs, fileDescriptor, decoder.decode(HEAPU8.subarray(path, path + path_len)), flags);
|
|
600
|
+
if ((fst_flags & WasiFstFlag.SET_ATIM_NOW) === WasiFstFlag.SET_ATIM_NOW) {
|
|
601
|
+
atim = BigInt(Date.now() * 1000000);
|
|
602
|
+
}
|
|
603
|
+
if ((fst_flags & WasiFstFlag.SET_MTIM_NOW) === WasiFstFlag.SET_MTIM_NOW) {
|
|
604
|
+
mtim = BigInt(Date.now() * 1000000);
|
|
605
|
+
}
|
|
606
|
+
fs.utimesSync(resolvedPath, Number(atim), Number(mtim));
|
|
607
|
+
return WasiErrno.ESUCCESS;
|
|
608
|
+
});
|
|
609
|
+
this.path_link = syscallWrap('path_link', function (old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) {
|
|
610
|
+
old_path = Number(old_path);
|
|
611
|
+
old_path_len = Number(old_path_len);
|
|
612
|
+
new_path = Number(new_path);
|
|
613
|
+
new_path_len = Number(new_path_len);
|
|
614
|
+
if (old_path === 0 || new_path === 0) {
|
|
615
|
+
return WasiErrno.EINVAL;
|
|
616
|
+
}
|
|
617
|
+
const wasi = _wasi.get(this);
|
|
618
|
+
let oldWrap;
|
|
619
|
+
let newWrap;
|
|
620
|
+
if (old_fd === new_fd) {
|
|
621
|
+
oldWrap = newWrap = wasi.fds.get(old_fd, WasiRights.PATH_LINK_SOURCE | WasiRights.PATH_LINK_TARGET, BigInt(0));
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
oldWrap = wasi.fds.get(old_fd, WasiRights.PATH_LINK_SOURCE, BigInt(0));
|
|
625
|
+
newWrap = wasi.fds.get(new_fd, WasiRights.PATH_LINK_TARGET, BigInt(0));
|
|
626
|
+
}
|
|
627
|
+
const { HEAPU8 } = getMemory(this);
|
|
628
|
+
const fs = getFs(this);
|
|
629
|
+
const resolvedOldPath = resolvePath(fs, oldWrap, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)), old_flags);
|
|
630
|
+
const resolvedNewPath = resolve(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
|
|
631
|
+
fs.linkSync(resolvedOldPath, resolvedNewPath);
|
|
632
|
+
return WasiErrno.ESUCCESS;
|
|
633
|
+
});
|
|
634
|
+
this.path_open = syscallWrap('path_open', function (dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
|
|
635
|
+
path = Number(path);
|
|
636
|
+
fd = Number(fd);
|
|
637
|
+
if (path === 0 || fd === 0) {
|
|
638
|
+
return WasiErrno.EINVAL;
|
|
639
|
+
}
|
|
640
|
+
path_len = Number(path_len);
|
|
641
|
+
fs_rights_base = BigInt(fs_rights_base);
|
|
642
|
+
fs_rights_base = BigInt(fs_rights_base);
|
|
643
|
+
const read = (fs_rights_base & (WasiRights.FD_READ |
|
|
644
|
+
WasiRights.FD_READDIR)) !== BigInt(0);
|
|
645
|
+
const write = (fs_rights_base & (WasiRights.FD_DATASYNC |
|
|
646
|
+
WasiRights.FD_WRITE |
|
|
647
|
+
WasiRights.FD_ALLOCATE |
|
|
648
|
+
WasiRights.FD_FILESTAT_SET_SIZE)) !== BigInt(0);
|
|
649
|
+
let flags = write ? read ? FileControlFlag.O_RDWR : FileControlFlag.O_WRONLY : FileControlFlag.O_RDONLY;
|
|
650
|
+
let needed_base = WasiRights.PATH_OPEN;
|
|
651
|
+
let needed_inheriting = fs_rights_base | fs_rights_inheriting;
|
|
652
|
+
if ((o_flags & WasiFileControlFlag.O_CREAT) !== 0) {
|
|
653
|
+
flags |= FileControlFlag.O_CREAT;
|
|
654
|
+
needed_base |= WasiRights.PATH_CREATE_FILE;
|
|
655
|
+
}
|
|
656
|
+
if ((o_flags & WasiFileControlFlag.O_DIRECTORY) !== 0) {
|
|
657
|
+
flags |= FileControlFlag.O_DIRECTORY;
|
|
658
|
+
}
|
|
659
|
+
if ((o_flags & WasiFileControlFlag.O_EXCL) !== 0) {
|
|
660
|
+
flags |= FileControlFlag.O_EXCL;
|
|
661
|
+
}
|
|
662
|
+
if ((o_flags & WasiFileControlFlag.O_TRUNC) !== 0) {
|
|
663
|
+
flags |= FileControlFlag.O_TRUNC;
|
|
664
|
+
needed_base |= WasiRights.PATH_FILESTAT_SET_SIZE;
|
|
665
|
+
}
|
|
666
|
+
if ((fs_flags & WasiFdFlag.APPEND) !== 0) {
|
|
667
|
+
flags |= FileControlFlag.O_APPEND;
|
|
668
|
+
}
|
|
669
|
+
if ((fs_flags & WasiFdFlag.DSYNC) !== 0) {
|
|
670
|
+
// flags |= FileControlFlag.O_DSYNC;
|
|
671
|
+
needed_inheriting |= WasiRights.FD_DATASYNC;
|
|
672
|
+
}
|
|
673
|
+
if ((fs_flags & WasiFdFlag.NONBLOCK) !== 0) {
|
|
674
|
+
flags |= FileControlFlag.O_NONBLOCK;
|
|
675
|
+
}
|
|
676
|
+
if ((fs_flags & WasiFdFlag.RSYNC) !== 0) {
|
|
677
|
+
flags |= FileControlFlag.O_SYNC;
|
|
678
|
+
needed_inheriting |= WasiRights.FD_SYNC;
|
|
679
|
+
}
|
|
680
|
+
if ((fs_flags & WasiFdFlag.SYNC) !== 0) {
|
|
681
|
+
flags |= FileControlFlag.O_SYNC;
|
|
682
|
+
needed_inheriting |= WasiRights.FD_SYNC;
|
|
683
|
+
}
|
|
684
|
+
if (write && (flags & (FileControlFlag.O_APPEND | FileControlFlag.O_TRUNC)) === 0) {
|
|
685
|
+
needed_inheriting |= WasiRights.FD_SEEK;
|
|
686
|
+
}
|
|
687
|
+
const wasi = _wasi.get(this);
|
|
688
|
+
const fileDescriptor = wasi.fds.get(dirfd, needed_base, needed_inheriting);
|
|
689
|
+
const memory = getMemory(this);
|
|
690
|
+
const HEAPU8 = memory.HEAPU8;
|
|
691
|
+
const pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
692
|
+
const fs = getFs(this);
|
|
693
|
+
const resolved_path = resolvePath(fs, fileDescriptor, pathString, dirflags);
|
|
694
|
+
const r = fs.openSync(resolved_path, flags, 0o666);
|
|
695
|
+
const filetype = wasi.fds.getFileTypeByFd(r);
|
|
696
|
+
if ((o_flags & WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== WasiFileType.DIRECTORY) {
|
|
697
|
+
return WasiErrno.ENOTDIR;
|
|
698
|
+
}
|
|
699
|
+
const { base: max_base, inheriting: max_inheriting } = getRights(wasi.fds.stdio, r, flags, filetype);
|
|
700
|
+
const wrap = wasi.fds.insert(r, resolved_path, resolved_path, filetype, fs_rights_base & max_base, fs_rights_inheriting & max_inheriting, 0);
|
|
701
|
+
const stat = fs.fstatSync(r, { bigint: true });
|
|
702
|
+
if (stat.isFile()) {
|
|
703
|
+
wrap.size = stat.size;
|
|
704
|
+
if ((flags & FileControlFlag.O_APPEND) !== 0) {
|
|
705
|
+
wrap.pos = stat.size;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const view = memory.view;
|
|
709
|
+
view.setInt32(fd, wrap.id, true);
|
|
710
|
+
return WasiErrno.ESUCCESS;
|
|
711
|
+
});
|
|
712
|
+
this.path_readlink = syscallWrap('path_readlink', function (fd, path, path_len, buf, buf_len, bufused) {
|
|
713
|
+
path = Number(path);
|
|
714
|
+
path_len = Number(path_len);
|
|
715
|
+
buf = Number(buf);
|
|
716
|
+
buf_len = Number(buf_len);
|
|
717
|
+
bufused = Number(bufused);
|
|
718
|
+
if (path === 0 || buf === 0 || bufused === 0) {
|
|
719
|
+
return WasiErrno.EINVAL;
|
|
720
|
+
}
|
|
721
|
+
const { HEAPU8, view } = getMemory(this);
|
|
722
|
+
const wasi = _wasi.get(this);
|
|
723
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_READLINK, BigInt(0));
|
|
724
|
+
let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
725
|
+
pathString = resolve(fileDescriptor.realPath, pathString);
|
|
726
|
+
const fs = getFs(this);
|
|
727
|
+
const link = fs.readlinkSync(pathString);
|
|
728
|
+
const linkData = encoder.encode(link);
|
|
729
|
+
const len = Math.min(linkData.length, buf_len);
|
|
730
|
+
if (len >= buf_len)
|
|
731
|
+
return WasiErrno.ENOBUFS;
|
|
732
|
+
HEAPU8.set(linkData.subarray(0, len), buf);
|
|
733
|
+
HEAPU8[buf + len] = 0;
|
|
734
|
+
view.setUint32(bufused, len + 1, true);
|
|
735
|
+
return WasiErrno.ESUCCESS;
|
|
736
|
+
});
|
|
737
|
+
this.path_remove_directory = syscallWrap('path_remove_directory', function (fd, path, path_len) {
|
|
738
|
+
path = Number(path);
|
|
739
|
+
path_len = Number(path_len);
|
|
740
|
+
if (path === 0) {
|
|
741
|
+
return WasiErrno.EINVAL;
|
|
742
|
+
}
|
|
743
|
+
const { HEAPU8 } = getMemory(this);
|
|
744
|
+
const wasi = _wasi.get(this);
|
|
745
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_REMOVE_DIRECTORY, BigInt(0));
|
|
746
|
+
let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
747
|
+
pathString = resolve(fileDescriptor.realPath, pathString);
|
|
748
|
+
const fs = getFs(this);
|
|
749
|
+
fs.rmdirSync(pathString);
|
|
750
|
+
return WasiErrno.ESUCCESS;
|
|
751
|
+
});
|
|
752
|
+
this.path_rename = syscallWrap('path_rename', function (old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) {
|
|
753
|
+
old_path = Number(old_path);
|
|
754
|
+
old_path_len = Number(old_path_len);
|
|
755
|
+
new_path = Number(new_path);
|
|
756
|
+
new_path_len = Number(new_path_len);
|
|
757
|
+
if (old_path === 0 || new_path === 0) {
|
|
758
|
+
return WasiErrno.EINVAL;
|
|
759
|
+
}
|
|
760
|
+
const wasi = _wasi.get(this);
|
|
761
|
+
let oldWrap;
|
|
762
|
+
let newWrap;
|
|
763
|
+
if (old_fd === new_fd) {
|
|
764
|
+
oldWrap = newWrap = wasi.fds.get(old_fd, WasiRights.PATH_RENAME_SOURCE | WasiRights.PATH_RENAME_TARGET, BigInt(0));
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
oldWrap = wasi.fds.get(old_fd, WasiRights.PATH_RENAME_SOURCE, BigInt(0));
|
|
768
|
+
newWrap = wasi.fds.get(new_fd, WasiRights.PATH_RENAME_TARGET, BigInt(0));
|
|
769
|
+
}
|
|
770
|
+
const { HEAPU8 } = getMemory(this);
|
|
771
|
+
const resolvedOldPath = resolve(oldWrap.realPath, decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len)));
|
|
772
|
+
const resolvedNewPath = resolve(newWrap.realPath, decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len)));
|
|
773
|
+
const fs = getFs(this);
|
|
774
|
+
fs.renameSync(resolvedOldPath, resolvedNewPath);
|
|
775
|
+
return WasiErrno.ESUCCESS;
|
|
776
|
+
});
|
|
777
|
+
this.path_symlink = syscallWrap('path_symlink', function (old_path, old_path_len, fd, new_path, new_path_len) {
|
|
778
|
+
old_path = Number(old_path);
|
|
779
|
+
old_path_len = Number(old_path_len);
|
|
780
|
+
new_path = Number(new_path);
|
|
781
|
+
new_path_len = Number(new_path_len);
|
|
782
|
+
if (old_path === 0 || new_path === 0) {
|
|
783
|
+
return WasiErrno.EINVAL;
|
|
784
|
+
}
|
|
785
|
+
const { HEAPU8 } = getMemory(this);
|
|
786
|
+
const wasi = _wasi.get(this);
|
|
787
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_SYMLINK, BigInt(0));
|
|
788
|
+
const oldPath = decoder.decode(HEAPU8.subarray(old_path, old_path + old_path_len));
|
|
789
|
+
let newPath = decoder.decode(HEAPU8.subarray(new_path, new_path + new_path_len));
|
|
790
|
+
newPath = resolve(fileDescriptor.realPath, newPath);
|
|
791
|
+
const fs = getFs(this);
|
|
792
|
+
fs.symlinkSync(oldPath, newPath);
|
|
793
|
+
return WasiErrno.ESUCCESS;
|
|
794
|
+
});
|
|
795
|
+
this.path_unlink_file = syscallWrap('path_unlink_file', function (fd, path, path_len) {
|
|
796
|
+
path = Number(path);
|
|
797
|
+
path_len = Number(path_len);
|
|
798
|
+
if (path === 0) {
|
|
799
|
+
return WasiErrno.EINVAL;
|
|
800
|
+
}
|
|
801
|
+
const { HEAPU8 } = getMemory(this);
|
|
802
|
+
const wasi = _wasi.get(this);
|
|
803
|
+
const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_UNLINK_FILE, BigInt(0));
|
|
804
|
+
let pathString = decoder.decode(HEAPU8.subarray(path, path + path_len));
|
|
805
|
+
pathString = resolve(fileDescriptor.realPath, pathString);
|
|
806
|
+
const fs = getFs(this);
|
|
807
|
+
fs.unlinkSync(pathString);
|
|
808
|
+
return WasiErrno.ESUCCESS;
|
|
809
|
+
});
|
|
810
|
+
this.poll_oneoff = syscallWrap('poll_oneoff', function (_in, _out, _sub, _nevents) {
|
|
811
|
+
return WasiErrno.ENOSYS;
|
|
812
|
+
});
|
|
813
|
+
this.proc_exit = syscallWrap('proc_exit', function (_rval) {
|
|
814
|
+
return WasiErrno.ESUCCESS;
|
|
815
|
+
});
|
|
816
|
+
this.proc_raise = syscallWrap('proc_raise', function (_sig) {
|
|
817
|
+
return WasiErrno.ENOSYS;
|
|
818
|
+
});
|
|
819
|
+
this.sched_yield = syscallWrap('sched_yield', function () {
|
|
820
|
+
return WasiErrno.ESUCCESS;
|
|
821
|
+
});
|
|
822
|
+
this.random_get = typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function'
|
|
823
|
+
? syscallWrap('random_get', function (buf, buf_len) {
|
|
824
|
+
buf = Number(buf);
|
|
825
|
+
if (buf === 0) {
|
|
826
|
+
return WasiErrno.EINVAL;
|
|
827
|
+
}
|
|
828
|
+
buf_len = Number(buf_len);
|
|
829
|
+
const { HEAPU8 } = getMemory(this);
|
|
830
|
+
let pos;
|
|
831
|
+
const stride = 65536;
|
|
832
|
+
for (pos = 0; pos + stride < buf_len; pos += stride) {
|
|
833
|
+
crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + pos + stride));
|
|
834
|
+
}
|
|
835
|
+
crypto.getRandomValues(HEAPU8.subarray(buf + pos, buf + buf_len));
|
|
836
|
+
return WasiErrno.ESUCCESS;
|
|
837
|
+
})
|
|
838
|
+
: syscallWrap('random_get', function (buf, buf_len) {
|
|
839
|
+
buf = Number(buf);
|
|
840
|
+
if (buf === 0) {
|
|
841
|
+
return WasiErrno.EINVAL;
|
|
842
|
+
}
|
|
843
|
+
buf_len = Number(buf_len);
|
|
844
|
+
const { view } = getMemory(this);
|
|
845
|
+
for (let i = buf; i < buf + buf_len; ++i) {
|
|
846
|
+
view.setUint8(i, Math.floor(Math.random() * 256));
|
|
847
|
+
}
|
|
848
|
+
return WasiErrno.ESUCCESS;
|
|
849
|
+
});
|
|
850
|
+
this.sock_recv = syscallWrap('sock_recv', function () {
|
|
851
|
+
return WasiErrno.ENOTSUP;
|
|
852
|
+
});
|
|
853
|
+
this.sock_send = syscallWrap('sock_send', function () {
|
|
854
|
+
return WasiErrno.ENOTSUP;
|
|
855
|
+
});
|
|
856
|
+
this.sock_shutdown = syscallWrap('sock_shutdown', function () {
|
|
857
|
+
return WasiErrno.ENOTSUP;
|
|
858
|
+
});
|
|
859
|
+
const fs = filesystem ? filesystem.fs : undefined;
|
|
860
|
+
const fds = new FileDescriptorTable({
|
|
861
|
+
size: 3,
|
|
862
|
+
in: stdio[0],
|
|
863
|
+
out: stdio[1],
|
|
864
|
+
err: stdio[2],
|
|
865
|
+
fs,
|
|
866
|
+
print,
|
|
867
|
+
printErr
|
|
868
|
+
});
|
|
869
|
+
_wasi.set(this, {
|
|
870
|
+
fds,
|
|
871
|
+
args,
|
|
872
|
+
env
|
|
873
|
+
});
|
|
874
|
+
if (fs)
|
|
875
|
+
_fs.set(this, fs);
|
|
876
|
+
if (preopens.length > 0) {
|
|
877
|
+
for (let i = 0; i < preopens.length; ++i) {
|
|
878
|
+
const realPath = fs.realpathSync(preopens[i].realPath, 'utf8');
|
|
879
|
+
const fd = fs.openSync(realPath, 'r', 0o666);
|
|
880
|
+
fds.insertPreopen(fd, preopens[i].mappedPath, realPath);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|