@ai-ecoverse/slicc-kernel 1.88.0 → 1.89.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 +18 -9
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +533 -162
- package/dist/kernel-worker.js.map +3 -3
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +5507 -5256
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +531 -161
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +302 -51
- package/dist/process-worker.js.map +4 -4
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -140,6 +140,14 @@ function inodeOf(path) {
|
|
|
140
140
|
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
141
141
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
|
|
142
142
|
}
|
|
143
|
+
function redirected(of, to) {
|
|
144
|
+
return Object.assign(fsError("EXDEV", `${of} leads to the mount at ${to}`), {
|
|
145
|
+
redirect: { of: normalizePath(of), to: normalizePath(to) }
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function redirectOf(err) {
|
|
149
|
+
return err?.redirect;
|
|
150
|
+
}
|
|
143
151
|
|
|
144
152
|
// src/fs/owners.ts
|
|
145
153
|
var ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
|
|
@@ -311,7 +319,10 @@ var Perms = class {
|
|
|
311
319
|
function parts(path) {
|
|
312
320
|
return path.split("/").filter((part) => part !== "" && part !== ".");
|
|
313
321
|
}
|
|
314
|
-
|
|
322
|
+
function trustedLink(perm, links) {
|
|
323
|
+
return links === void 0 || perm.uid === 0 || perm.uid === links;
|
|
324
|
+
}
|
|
325
|
+
async function walk(fs, cred, path, follow2, links) {
|
|
315
326
|
const perms = new Perms(fs);
|
|
316
327
|
await perms.learn(path);
|
|
317
328
|
const queue = parts(path);
|
|
@@ -329,6 +340,7 @@ async function walk(fs, cred, path, follow2) {
|
|
|
329
340
|
const perm = await perms.at(next2);
|
|
330
341
|
const last = queue.length === 0;
|
|
331
342
|
if (perm?.link !== void 0 && (!last || follow2)) {
|
|
343
|
+
if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next2, link: true };
|
|
332
344
|
if (++hops > MAX_LINKS2) return { path: next2, perm: void 0 };
|
|
333
345
|
queue.unshift(...parts(perm.link));
|
|
334
346
|
if (perm.link.startsWith("/")) at = "/";
|
|
@@ -353,9 +365,9 @@ async function finalOf(fs, walked, want, options) {
|
|
|
353
365
|
return st ? [permOf(st), st.isDirectory] : [perm, false];
|
|
354
366
|
}
|
|
355
367
|
async function access(fs, cred, path, want, options = {}) {
|
|
356
|
-
const walked = await walk(fs, cred, path, options.follow !== false);
|
|
368
|
+
const walked = await walk(fs, cred, path, options.follow !== false, options.links);
|
|
357
369
|
if (walked.denied !== void 0) {
|
|
358
|
-
if (await present(fs, walked.denied, true)) return walked;
|
|
370
|
+
if (walked.link || await present(fs, walked.denied, true)) return walked;
|
|
359
371
|
return { path, perm: void 0, missing: true };
|
|
360
372
|
}
|
|
361
373
|
if (!walked.perm) return { ...walked, missing: true };
|
|
@@ -422,6 +434,9 @@ var Created = class {
|
|
|
422
434
|
return this.paths.delete(normalizePath(path));
|
|
423
435
|
}
|
|
424
436
|
};
|
|
437
|
+
function linked(g, options) {
|
|
438
|
+
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
439
|
+
}
|
|
425
440
|
function deny(g, op, path, errno = "EACCES") {
|
|
426
441
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
427
442
|
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno, ...tag });
|
|
@@ -432,8 +447,8 @@ function ttyOpenable(g, tty) {
|
|
|
432
447
|
deny(g, "open", tty.name ?? "/dev/tty");
|
|
433
448
|
}
|
|
434
449
|
async function need(g, op, path, want, options = {}, shown = path) {
|
|
435
|
-
const walked = await access(g.fs, g.cred, path, want, options);
|
|
436
|
-
if (walked.denied !== void 0) deny(g, op, shown);
|
|
450
|
+
const walked = await access(g.fs, g.cred, path, want, linked(g, options));
|
|
451
|
+
if (walked.denied !== void 0) deny(g, op, walked.link ? walked.denied : shown);
|
|
437
452
|
return walked;
|
|
438
453
|
}
|
|
439
454
|
function entryIn(dir, path) {
|
|
@@ -452,14 +467,16 @@ async function inParent(g, op, path, old = false) {
|
|
|
452
467
|
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
453
468
|
}
|
|
454
469
|
if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
|
|
455
|
-
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, DIR);
|
|
470
|
+
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, linked(g, DIR));
|
|
456
471
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
472
|
+
if (dir.link) return deny(g, op, dir.denied);
|
|
457
473
|
const lookup3 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
458
474
|
if (!lookup3 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
459
475
|
}
|
|
460
476
|
async function makeIn(g, op, path) {
|
|
461
477
|
for (let dir = parentOf(path); ; dir = parentOf(dir)) {
|
|
462
|
-
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
|
|
478
|
+
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
479
|
+
if (walked.link) return deny(g, op, walked.denied);
|
|
463
480
|
if (walked.denied !== void 0) {
|
|
464
481
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
465
482
|
return;
|
|
@@ -3086,39 +3103,47 @@ var Integrity = class {
|
|
|
3086
3103
|
this.unknown = integrityUnknown(options);
|
|
3087
3104
|
this.report = report;
|
|
3088
3105
|
}
|
|
3089
|
-
async real(path) {
|
|
3106
|
+
async real(path, asked) {
|
|
3090
3107
|
const at = normalizePath(path);
|
|
3091
3108
|
const real = await this.root.realpath?.(at, true).catch(() => void 0) ?? at;
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
const
|
|
3096
|
-
|
|
3109
|
+
if (isProtected(this.prefixes, real)) return { real, name: real };
|
|
3110
|
+
const names = asked === void 0 ? [] : await namesOf(this.root, asked);
|
|
3111
|
+
if (real !== at) names.push(...await namesOf(this.root, at));
|
|
3112
|
+
const name2 = names.findLast((p) => isProtected(this.prefixes, p));
|
|
3113
|
+
return name2 === void 0 ? void 0 : { real, name: name2 };
|
|
3114
|
+
}
|
|
3115
|
+
async key(path, asked) {
|
|
3116
|
+
const found = await this.real(path, asked);
|
|
3117
|
+
if (found === void 0) return void 0;
|
|
3118
|
+
const { real, name: name2 } = found;
|
|
3119
|
+
if (name2 !== real) return `${name2}\0${real}\0`;
|
|
3120
|
+
if (!this.root.version) return void 0;
|
|
3097
3121
|
return `${real}\0${await this.root.version(real)}`;
|
|
3098
3122
|
}
|
|
3099
|
-
async read(path, caller, plain) {
|
|
3100
|
-
return (await this.readKeyed(path, caller, plain)).bytes;
|
|
3123
|
+
async read(path, caller, plain, asked) {
|
|
3124
|
+
return (await this.readKeyed(path, caller, plain, asked)).bytes;
|
|
3101
3125
|
}
|
|
3102
|
-
async readKeyed(path, caller, plain) {
|
|
3103
|
-
const
|
|
3104
|
-
if (
|
|
3105
|
-
const
|
|
3126
|
+
async readKeyed(path, caller, plain, asked) {
|
|
3127
|
+
const found = await this.real(path, asked);
|
|
3128
|
+
if (found === void 0) return { bytes: await plain() };
|
|
3129
|
+
const { real, name: name2 } = found;
|
|
3130
|
+
const read = name2 !== real ? { bytes: await plain(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
|
|
3106
3131
|
const { bytes } = read;
|
|
3107
3132
|
const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
|
|
3108
3133
|
const actual = await sha256(bytes);
|
|
3109
|
-
const denial = { pid: caller.pid, uid: caller.uid, path:
|
|
3134
|
+
const denial = { pid: caller.pid, uid: caller.uid, path: name2, actual };
|
|
3110
3135
|
const tagged = caller.tag !== void 0 ? { tag: caller.tag } : {};
|
|
3111
3136
|
let expected;
|
|
3112
3137
|
try {
|
|
3113
|
-
expected = await this.expected(
|
|
3138
|
+
expected = await this.expected(name2);
|
|
3114
3139
|
} catch {
|
|
3115
3140
|
this.say({ ...denial, ...tagged, op: "exec-integrity", errno: "EACCES" });
|
|
3116
|
-
throw fsError("EACCES", `integrity lookup failed: ${
|
|
3141
|
+
throw fsError("EACCES", `integrity lookup failed: ${name2}`);
|
|
3117
3142
|
}
|
|
3118
3143
|
if (expected === void 0) {
|
|
3119
3144
|
if (this.unknown === "allow") {
|
|
3120
|
-
if (!this.unverified.has(
|
|
3121
|
-
this.unverified.add(
|
|
3145
|
+
if (!this.unverified.has(name2)) {
|
|
3146
|
+
this.unverified.add(name2);
|
|
3122
3147
|
this.say({ ...denial, ...tagged, op: "exec-unverified", errno: "ENODATA" });
|
|
3123
3148
|
}
|
|
3124
3149
|
return keyed;
|
|
@@ -3128,7 +3153,12 @@ var Integrity = class {
|
|
|
3128
3153
|
}
|
|
3129
3154
|
const known = expected !== void 0 ? { expected } : {};
|
|
3130
3155
|
this.say({ ...denial, ...tagged, ...known, op: "exec-integrity", errno: "EACCES" });
|
|
3131
|
-
throw fsError("EACCES", `integrity check failed: ${
|
|
3156
|
+
throw fsError("EACCES", `integrity check failed: ${name2}`);
|
|
3157
|
+
}
|
|
3158
|
+
forget(path) {
|
|
3159
|
+
for (const name2 of [...this.unverified]) {
|
|
3160
|
+
if (path === void 0 || isProtected([path], name2)) this.unverified.delete(name2);
|
|
3161
|
+
}
|
|
3132
3162
|
}
|
|
3133
3163
|
async expected(path) {
|
|
3134
3164
|
const answer = await this.lookup(path);
|
|
@@ -3173,10 +3203,10 @@ function missing(err) {
|
|
|
3173
3203
|
const code = err?.code;
|
|
3174
3204
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
3175
3205
|
}
|
|
3176
|
-
async function resolved(fs, path, follow2) {
|
|
3206
|
+
async function resolved(fs, path, follow2, hops = []) {
|
|
3177
3207
|
let done4 = [];
|
|
3178
3208
|
let todo = partsOf(path);
|
|
3179
|
-
for (let
|
|
3209
|
+
for (let links = 0; todo.length > 0; ) {
|
|
3180
3210
|
const part = todo.shift();
|
|
3181
3211
|
if (part === "..") {
|
|
3182
3212
|
done4.pop();
|
|
@@ -3198,13 +3228,20 @@ async function resolved(fs, path, follow2) {
|
|
|
3198
3228
|
done4.push(part);
|
|
3199
3229
|
continue;
|
|
3200
3230
|
}
|
|
3201
|
-
if (++
|
|
3231
|
+
if (++links > MAX_LINKS4) throw fsError("ELOOP", path);
|
|
3232
|
+
hops.push(normalizePath([at, ...todo].join("/")));
|
|
3202
3233
|
const link2 = await fs.readlink(at);
|
|
3203
3234
|
if (link2.startsWith("/")) done4 = [];
|
|
3204
3235
|
todo = [...partsOf(link2), ...todo];
|
|
3205
3236
|
}
|
|
3206
3237
|
return `/${done4.join("/")}`;
|
|
3207
3238
|
}
|
|
3239
|
+
async function namesOf(fs, path) {
|
|
3240
|
+
const lexical2 = normalizePath(path);
|
|
3241
|
+
const hops = [];
|
|
3242
|
+
await resolved(fs, lexical2, true, hops).catch(() => void 0);
|
|
3243
|
+
return [lexical2, ...hops];
|
|
3244
|
+
}
|
|
3208
3245
|
var ProtectedFs = class {
|
|
3209
3246
|
prefixes;
|
|
3210
3247
|
constructor(prefixes2) {
|
|
@@ -3257,8 +3294,8 @@ var ProtectedFs = class {
|
|
|
3257
3294
|
await check(path, true);
|
|
3258
3295
|
return fs.utimes(path, atime, mtime);
|
|
3259
3296
|
},
|
|
3260
|
-
async mayChange(path, follow2) {
|
|
3261
|
-
await check(path, follow2);
|
|
3297
|
+
async mayChange(path, follow2, whole = false) {
|
|
3298
|
+
await check(path, follow2, whole);
|
|
3262
3299
|
},
|
|
3263
3300
|
async stat(path) {
|
|
3264
3301
|
return marked(path, await fs.stat(path));
|
|
@@ -3581,6 +3618,7 @@ var OpfsFs = class {
|
|
|
3581
3618
|
remote;
|
|
3582
3619
|
ranged;
|
|
3583
3620
|
owners = false;
|
|
3621
|
+
mounts = {};
|
|
3584
3622
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
3585
3623
|
this.root = root;
|
|
3586
3624
|
this.meta = sidecar(meta);
|
|
@@ -3654,6 +3692,12 @@ var OpfsFs = class {
|
|
|
3654
3692
|
trackOwners() {
|
|
3655
3693
|
this.owners = true;
|
|
3656
3694
|
}
|
|
3695
|
+
crossings(mounted) {
|
|
3696
|
+
this.mounts.mounted = mounted;
|
|
3697
|
+
}
|
|
3698
|
+
crossing(of, to) {
|
|
3699
|
+
if (this.mounts.mounted?.(to)) throw redirected(of, to);
|
|
3700
|
+
}
|
|
3657
3701
|
async hasOwner(path) {
|
|
3658
3702
|
return ownOf((await this.meta.get([path]))[0]) !== void 0;
|
|
3659
3703
|
}
|
|
@@ -3848,12 +3892,13 @@ var OpfsFs = class {
|
|
|
3848
3892
|
if (!link2) throw err;
|
|
3849
3893
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
3850
3894
|
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
3851
|
-
current = target.split("/").includes("..") ? await this.physical(parentOf4(link2.path), target, hops + 1) : resolvePath(parentOf4(link2.path), target);
|
|
3895
|
+
current = target.split("/").includes("..") ? await this.physical(parentOf4(link2.path), target, hops + 1, path) : resolvePath(parentOf4(link2.path), target);
|
|
3896
|
+
this.crossing(path, current);
|
|
3852
3897
|
}
|
|
3853
3898
|
}
|
|
3854
3899
|
throw fsError("ELOOP", path);
|
|
3855
3900
|
}
|
|
3856
|
-
async physical(base, path, used) {
|
|
3901
|
+
async physical(base, path, used, of) {
|
|
3857
3902
|
let done4 = [];
|
|
3858
3903
|
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
3859
3904
|
for (let hops = used; todo.length > 0; ) {
|
|
@@ -3862,6 +3907,7 @@ var OpfsFs = class {
|
|
|
3862
3907
|
else if (!todo.includes("..")) done4.push(part);
|
|
3863
3908
|
else {
|
|
3864
3909
|
const at = `/${[...done4, part].join("/")}`;
|
|
3910
|
+
this.crossing(of, [at, ...todo].join("/"));
|
|
3865
3911
|
const st = await this.lstat(at);
|
|
3866
3912
|
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
3867
3913
|
if (!st.isSymbolicLink) done4.push(part);
|
|
@@ -5992,14 +6038,14 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5992
6038
|
const own = await userDir(dir);
|
|
5993
6039
|
return own?.has(path.slice(slash + 1)) ? owned4(synthetic(false, path), dir) : void 0;
|
|
5994
6040
|
}
|
|
5995
|
-
async function
|
|
6041
|
+
async function linked2(path) {
|
|
5996
6042
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
5997
6043
|
}
|
|
5998
6044
|
async function stat(path, real) {
|
|
5999
6045
|
try {
|
|
6000
6046
|
return await real(path);
|
|
6001
6047
|
} catch (err) {
|
|
6002
|
-
const found = missing3(err) ? await
|
|
6048
|
+
const found = missing3(err) ? await linked2(path) : void 0;
|
|
6003
6049
|
if (found) return found;
|
|
6004
6050
|
throw err;
|
|
6005
6051
|
}
|
|
@@ -6011,7 +6057,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
6011
6057
|
try {
|
|
6012
6058
|
return await fs.readFileBuffer(path);
|
|
6013
6059
|
} catch (err) {
|
|
6014
|
-
if (missing3(err) && (await
|
|
6060
|
+
if (missing3(err) && (await linked2(path))?.isFile) return new Uint8Array(0);
|
|
6015
6061
|
throw err;
|
|
6016
6062
|
}
|
|
6017
6063
|
},
|
|
@@ -6019,7 +6065,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
6019
6065
|
link: (from, to, follow2) => fs.link(from, to, follow2),
|
|
6020
6066
|
links: (path) => mayLink(fs, path),
|
|
6021
6067
|
async exists(path) {
|
|
6022
|
-
return await fs.exists(path) || await
|
|
6068
|
+
return await fs.exists(path) || await linked2(path) !== void 0;
|
|
6023
6069
|
},
|
|
6024
6070
|
stat: (path) => stat(path, (p) => fs.stat(p)),
|
|
6025
6071
|
lstat: (path) => stat(path, (p) => fs.lstat(p)),
|
|
@@ -6585,12 +6631,12 @@ async function interruptible(work, signal) {
|
|
|
6585
6631
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
6586
6632
|
let stop = () => {
|
|
6587
6633
|
};
|
|
6588
|
-
const
|
|
6634
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
6589
6635
|
stop = () => reject(new KernelError("EINTR"));
|
|
6590
6636
|
signal.addEventListener("abort", stop, { once: true });
|
|
6591
6637
|
});
|
|
6592
6638
|
try {
|
|
6593
|
-
return await Promise.race([work,
|
|
6639
|
+
return await Promise.race([work, interrupted3]);
|
|
6594
6640
|
} finally {
|
|
6595
6641
|
signal.removeEventListener("abort", stop);
|
|
6596
6642
|
}
|
|
@@ -7389,6 +7435,7 @@ var MountTable = class {
|
|
|
7389
7435
|
return { quota: st.blocks * st.bsize, usage: (st.blocks - st.bfree) * st.bsize };
|
|
7390
7436
|
}
|
|
7391
7437
|
wrap(base) {
|
|
7438
|
+
base.crossings?.((path) => this.locate(normalizePath(path)) !== void 0);
|
|
7392
7439
|
return new MountFs(this, base);
|
|
7393
7440
|
}
|
|
7394
7441
|
};
|
|
@@ -7412,6 +7459,37 @@ var MountFs = class {
|
|
|
7412
7459
|
writable(mount, path) {
|
|
7413
7460
|
if (readonly(mount)) throw errnoError("EROFS", path);
|
|
7414
7461
|
}
|
|
7462
|
+
async through(path) {
|
|
7463
|
+
const real = normalizePath(path);
|
|
7464
|
+
if (this.at(real)) return real;
|
|
7465
|
+
try {
|
|
7466
|
+
await this.base.stat(parentOf7(real));
|
|
7467
|
+
return real;
|
|
7468
|
+
} catch (err) {
|
|
7469
|
+
const moved2 = redirectOf(err);
|
|
7470
|
+
return moved2 ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
async across(from, to, redirects) {
|
|
7474
|
+
const moved2 = [await this.through(from), await this.through(to)];
|
|
7475
|
+
const same = moved2[0] === normalizePath(from) && moved2[1] === normalizePath(to);
|
|
7476
|
+
if (same || redirects >= MAX_LINKS7) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
7477
|
+
return moved2;
|
|
7478
|
+
}
|
|
7479
|
+
async based(paths, redirects, run2, again) {
|
|
7480
|
+
try {
|
|
7481
|
+
return await run2();
|
|
7482
|
+
} catch (err) {
|
|
7483
|
+
const moved2 = redirectOf(err);
|
|
7484
|
+
if (!moved2) throw err;
|
|
7485
|
+
if (redirects >= MAX_LINKS7) throw errnoError("ELOOP", paths[0]);
|
|
7486
|
+
const at = paths.map((path) => {
|
|
7487
|
+
const real = normalizePath(path);
|
|
7488
|
+
return within5(real, moved2.of) ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
7489
|
+
});
|
|
7490
|
+
return again(at, redirects + 1);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7415
7493
|
async follow(path, hops = 0, create = false) {
|
|
7416
7494
|
const found = this.at(path);
|
|
7417
7495
|
if (!found) return path;
|
|
@@ -7459,10 +7537,17 @@ var MountFs = class {
|
|
|
7459
7537
|
async readFile(path) {
|
|
7460
7538
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
7461
7539
|
}
|
|
7462
|
-
async readFileBuffer(path) {
|
|
7540
|
+
async readFileBuffer(path, redirects = 0) {
|
|
7463
7541
|
const real = await this.follow(path);
|
|
7464
7542
|
const found = this.at(real);
|
|
7465
|
-
if (!found)
|
|
7543
|
+
if (!found) {
|
|
7544
|
+
return this.based(
|
|
7545
|
+
[real],
|
|
7546
|
+
redirects,
|
|
7547
|
+
() => this.base.readFileBuffer(real),
|
|
7548
|
+
([to], n) => this.readFileBuffer(to, n)
|
|
7549
|
+
);
|
|
7550
|
+
}
|
|
7466
7551
|
for (let attempt = 1; ; attempt++) {
|
|
7467
7552
|
try {
|
|
7468
7553
|
return await this.readWhole(found.mount, real, found.rel);
|
|
@@ -7501,10 +7586,18 @@ var MountFs = class {
|
|
|
7501
7586
|
}
|
|
7502
7587
|
return concat3(chunks2, total);
|
|
7503
7588
|
}
|
|
7504
|
-
async writeFile(path, content, owner) {
|
|
7589
|
+
async writeFile(path, content, owner, redirects = 0) {
|
|
7505
7590
|
const real = await this.follow(path, 0, true);
|
|
7506
7591
|
const found = this.at(real);
|
|
7507
|
-
if (!found)
|
|
7592
|
+
if (!found) {
|
|
7593
|
+
const write = () => this.base.writeFile(real, content, owner);
|
|
7594
|
+
return this.based(
|
|
7595
|
+
[real],
|
|
7596
|
+
redirects,
|
|
7597
|
+
write,
|
|
7598
|
+
([to], n) => this.writeFile(to, content, owner, n)
|
|
7599
|
+
);
|
|
7600
|
+
}
|
|
7508
7601
|
const { mount, rel: rel2 } = found;
|
|
7509
7602
|
this.writable(mount, real);
|
|
7510
7603
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -7538,10 +7631,18 @@ var MountFs = class {
|
|
|
7538
7631
|
this.table.forget(mount, real);
|
|
7539
7632
|
}
|
|
7540
7633
|
}
|
|
7541
|
-
async pread(path, offset, length2, version) {
|
|
7634
|
+
async pread(path, offset, length2, version, redirects = 0) {
|
|
7542
7635
|
const real = await this.follow(path);
|
|
7543
7636
|
const found = this.at(real);
|
|
7544
|
-
|
|
7637
|
+
const { pread } = this.base;
|
|
7638
|
+
if (!found && pread) {
|
|
7639
|
+
return this.based(
|
|
7640
|
+
[real],
|
|
7641
|
+
redirects,
|
|
7642
|
+
() => pread.call(this.base, real, offset, length2),
|
|
7643
|
+
([to], n) => this.pread(to, offset, length2, version, n)
|
|
7644
|
+
);
|
|
7645
|
+
}
|
|
7545
7646
|
if (!found) return (await this.base.readFileBuffer(real)).slice(offset, offset + length2);
|
|
7546
7647
|
const { mount, rel: rel2 } = found;
|
|
7547
7648
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
@@ -7588,10 +7689,18 @@ var MountFs = class {
|
|
|
7588
7689
|
);
|
|
7589
7690
|
}
|
|
7590
7691
|
}
|
|
7591
|
-
async pwrite(path, offset, bytes, transfer = false) {
|
|
7692
|
+
async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
|
|
7592
7693
|
const real = await this.follow(path, 0, true);
|
|
7593
7694
|
const found = this.at(real);
|
|
7594
|
-
|
|
7695
|
+
const { pwrite } = this.base;
|
|
7696
|
+
if (!found && pwrite) {
|
|
7697
|
+
return this.based(
|
|
7698
|
+
[real],
|
|
7699
|
+
redirects,
|
|
7700
|
+
() => pwrite.call(this.base, real, offset, bytes),
|
|
7701
|
+
([to], n) => this.pwrite(to, offset, bytes, transfer, n)
|
|
7702
|
+
);
|
|
7703
|
+
}
|
|
7595
7704
|
if (!found)
|
|
7596
7705
|
return this.base.writeFile(
|
|
7597
7706
|
real,
|
|
@@ -7631,10 +7740,18 @@ var MountFs = class {
|
|
|
7631
7740
|
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
7632
7741
|
}
|
|
7633
7742
|
}
|
|
7634
|
-
async truncate(path, size) {
|
|
7743
|
+
async truncate(path, size, redirects = 0) {
|
|
7635
7744
|
const real = await this.follow(path);
|
|
7636
7745
|
const found = this.at(real);
|
|
7637
|
-
|
|
7746
|
+
const { truncate } = this.base;
|
|
7747
|
+
if (!found && truncate) {
|
|
7748
|
+
return this.based(
|
|
7749
|
+
[real],
|
|
7750
|
+
redirects,
|
|
7751
|
+
() => truncate.call(this.base, real, size),
|
|
7752
|
+
([to], n) => this.truncate(to, size, n)
|
|
7753
|
+
);
|
|
7754
|
+
}
|
|
7638
7755
|
if (!found?.mount.caps.ranges) {
|
|
7639
7756
|
return this.writeFile(real, resized(await this.readFileBuffer(real), size));
|
|
7640
7757
|
}
|
|
@@ -7650,8 +7767,15 @@ var MountFs = class {
|
|
|
7650
7767
|
this.table.forget(mount, real);
|
|
7651
7768
|
}
|
|
7652
7769
|
}
|
|
7653
|
-
async exists(path) {
|
|
7654
|
-
if (!this.at(path))
|
|
7770
|
+
async exists(path, redirects = 0) {
|
|
7771
|
+
if (!this.at(path)) {
|
|
7772
|
+
return this.based(
|
|
7773
|
+
[path],
|
|
7774
|
+
redirects,
|
|
7775
|
+
() => this.base.exists(path),
|
|
7776
|
+
([to], n) => this.exists(to, n)
|
|
7777
|
+
);
|
|
7778
|
+
}
|
|
7655
7779
|
try {
|
|
7656
7780
|
await this.stat(path);
|
|
7657
7781
|
return true;
|
|
@@ -7661,9 +7785,16 @@ var MountFs = class {
|
|
|
7661
7785
|
throw err;
|
|
7662
7786
|
}
|
|
7663
7787
|
}
|
|
7664
|
-
async lstat(path) {
|
|
7788
|
+
async lstat(path, redirects = 0) {
|
|
7665
7789
|
const found = this.at(path);
|
|
7666
|
-
if (!found)
|
|
7790
|
+
if (!found) {
|
|
7791
|
+
return this.based(
|
|
7792
|
+
[path],
|
|
7793
|
+
redirects,
|
|
7794
|
+
() => this.base.lstat(path),
|
|
7795
|
+
([to], n) => this.lstat(to, n)
|
|
7796
|
+
);
|
|
7797
|
+
}
|
|
7667
7798
|
const real = normalizePath(path);
|
|
7668
7799
|
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
7669
7800
|
return this.statWriting(
|
|
@@ -7676,9 +7807,15 @@ var MountFs = class {
|
|
|
7676
7807
|
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
7677
7808
|
return statOf({ ...attr2, size: Math.max(attr2.size, ...ends) }, real, mount);
|
|
7678
7809
|
}
|
|
7679
|
-
async stat(path) {
|
|
7810
|
+
async stat(path, redirects = 0) {
|
|
7680
7811
|
const real = await this.follow(path);
|
|
7681
|
-
|
|
7812
|
+
if (this.at(real)) return this.lstat(real);
|
|
7813
|
+
return this.based(
|
|
7814
|
+
[real],
|
|
7815
|
+
redirects,
|
|
7816
|
+
() => this.base.stat(real),
|
|
7817
|
+
([to], n) => this.stat(to, n)
|
|
7818
|
+
);
|
|
7682
7819
|
}
|
|
7683
7820
|
async entries(path) {
|
|
7684
7821
|
const real = await this.follow(path);
|
|
@@ -7690,12 +7827,26 @@ var MountFs = class {
|
|
|
7690
7827
|
list: await this.table.readdir(found.mount, real, found.rel)
|
|
7691
7828
|
};
|
|
7692
7829
|
}
|
|
7693
|
-
async readdir(path) {
|
|
7694
|
-
if (!this.at(path))
|
|
7830
|
+
async readdir(path, redirects = 0) {
|
|
7831
|
+
if (!this.at(path)) {
|
|
7832
|
+
return this.based(
|
|
7833
|
+
[path],
|
|
7834
|
+
redirects,
|
|
7835
|
+
() => this.base.readdir(path),
|
|
7836
|
+
([to], n) => this.readdir(to, n)
|
|
7837
|
+
);
|
|
7838
|
+
}
|
|
7695
7839
|
return (await this.entries(path)).list.map((e) => e.name);
|
|
7696
7840
|
}
|
|
7697
|
-
async readdirStat(path) {
|
|
7698
|
-
if (!this.at(path))
|
|
7841
|
+
async readdirStat(path, redirects = 0) {
|
|
7842
|
+
if (!this.at(path)) {
|
|
7843
|
+
return this.based(
|
|
7844
|
+
[path],
|
|
7845
|
+
redirects,
|
|
7846
|
+
() => this.base.readdirStat(path),
|
|
7847
|
+
([to], n) => this.readdirStat(to, n)
|
|
7848
|
+
);
|
|
7849
|
+
}
|
|
7699
7850
|
const { real, mount, list } = await this.entries(path);
|
|
7700
7851
|
return Promise.all(
|
|
7701
7852
|
list.map(async (entry) => {
|
|
@@ -7707,9 +7858,16 @@ var MountFs = class {
|
|
|
7707
7858
|
})
|
|
7708
7859
|
);
|
|
7709
7860
|
}
|
|
7710
|
-
async mkdir(path, options = {}) {
|
|
7861
|
+
async mkdir(path, options = {}, redirects = 0) {
|
|
7711
7862
|
const found = this.at(path);
|
|
7712
|
-
if (!found)
|
|
7863
|
+
if (!found) {
|
|
7864
|
+
return this.based(
|
|
7865
|
+
[path],
|
|
7866
|
+
redirects,
|
|
7867
|
+
() => this.base.mkdir(path, options),
|
|
7868
|
+
([to], n) => this.mkdir(to, options, n)
|
|
7869
|
+
);
|
|
7870
|
+
}
|
|
7713
7871
|
const { mount, rel: rel2 } = found;
|
|
7714
7872
|
const real = normalizePath(path);
|
|
7715
7873
|
this.writable(mount, real);
|
|
@@ -7734,11 +7892,18 @@ var MountFs = class {
|
|
|
7734
7892
|
await mount.conn.call({ op: "mkdir", path: sub, ...made2 });
|
|
7735
7893
|
}
|
|
7736
7894
|
}
|
|
7737
|
-
async rm(path, options = {}) {
|
|
7895
|
+
async rm(path, options = {}, redirects = 0) {
|
|
7738
7896
|
const found = this.at(path);
|
|
7739
7897
|
if (!found && options.recursive && this.table.under(normalizePath(path)))
|
|
7740
7898
|
return this.rmAround(normalizePath(path), options);
|
|
7741
|
-
if (!found)
|
|
7899
|
+
if (!found) {
|
|
7900
|
+
return this.based(
|
|
7901
|
+
[path],
|
|
7902
|
+
redirects,
|
|
7903
|
+
() => this.base.rm(path, options),
|
|
7904
|
+
([to], n) => this.rm(to, options, n)
|
|
7905
|
+
);
|
|
7906
|
+
}
|
|
7742
7907
|
const { mount, rel: rel2 } = found;
|
|
7743
7908
|
const real = normalizePath(path);
|
|
7744
7909
|
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
@@ -7779,11 +7944,22 @@ var MountFs = class {
|
|
|
7779
7944
|
}
|
|
7780
7945
|
throw first ?? errnoError("EBUSY", `${path} holds a mount point`);
|
|
7781
7946
|
}
|
|
7782
|
-
async rename(from, to) {
|
|
7947
|
+
async rename(from, to, redirects = 0) {
|
|
7783
7948
|
const a = this.at(from);
|
|
7784
7949
|
const b = this.at(to);
|
|
7785
|
-
if (!a && !b)
|
|
7786
|
-
|
|
7950
|
+
if (!a && !b) {
|
|
7951
|
+
return this.based(
|
|
7952
|
+
[from, to],
|
|
7953
|
+
redirects,
|
|
7954
|
+
() => this.base.rename(from, to),
|
|
7955
|
+
([f, t], n) => this.rename(f, t, n)
|
|
7956
|
+
);
|
|
7957
|
+
}
|
|
7958
|
+
if (!a || !b) {
|
|
7959
|
+
const [f, t] = await this.across(from, to, redirects);
|
|
7960
|
+
return this.rename(f, t, redirects + 1);
|
|
7961
|
+
}
|
|
7962
|
+
if (a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
7787
7963
|
this.writable(a.mount, normalizePath(to));
|
|
7788
7964
|
await this.table.commitUnder(from);
|
|
7789
7965
|
await this.table.commitUnder(to);
|
|
@@ -7824,9 +8000,17 @@ var MountFs = class {
|
|
|
7824
8000
|
this.table.forget(a.mount, normalizePath(to));
|
|
7825
8001
|
}
|
|
7826
8002
|
}
|
|
7827
|
-
async symlink(target, path, owner) {
|
|
8003
|
+
async symlink(target, path, owner, redirects = 0) {
|
|
7828
8004
|
const found = this.at(path);
|
|
7829
|
-
if (!found)
|
|
8005
|
+
if (!found) {
|
|
8006
|
+
const make = () => this.base.symlink(target, path, owner);
|
|
8007
|
+
return this.based(
|
|
8008
|
+
[path],
|
|
8009
|
+
redirects,
|
|
8010
|
+
make,
|
|
8011
|
+
([to], n) => this.symlink(target, to, owner, n)
|
|
8012
|
+
);
|
|
8013
|
+
}
|
|
7830
8014
|
this.writable(found.mount, normalizePath(path));
|
|
7831
8015
|
if (!found.mount.caps.symlinks)
|
|
7832
8016
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -7836,8 +8020,11 @@ var MountFs = class {
|
|
|
7836
8020
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel, ...made2 });
|
|
7837
8021
|
}
|
|
7838
8022
|
async realpath(path, follow2) {
|
|
7839
|
-
|
|
7840
|
-
|
|
8023
|
+
const { realpath: realpath2 } = this.base;
|
|
8024
|
+
if (this.at(path) || !realpath2) throw errnoError("ENOSYS", path);
|
|
8025
|
+
const real = await realpath2.call(this.base, path, follow2).catch((err) => {
|
|
8026
|
+
throw redirectOf(err) ? errnoError("ENOSYS", path) : err;
|
|
8027
|
+
});
|
|
7841
8028
|
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
7842
8029
|
return real;
|
|
7843
8030
|
}
|
|
@@ -7859,17 +8046,30 @@ var MountFs = class {
|
|
|
7859
8046
|
}
|
|
7860
8047
|
return out;
|
|
7861
8048
|
}
|
|
7862
|
-
async readlink(path) {
|
|
8049
|
+
async readlink(path, redirects = 0) {
|
|
7863
8050
|
const found = this.at(path);
|
|
7864
|
-
if (!found)
|
|
8051
|
+
if (!found) {
|
|
8052
|
+
return this.based(
|
|
8053
|
+
[path],
|
|
8054
|
+
redirects,
|
|
8055
|
+
() => this.base.readlink(path),
|
|
8056
|
+
([to], n) => this.readlink(to, n)
|
|
8057
|
+
);
|
|
8058
|
+
}
|
|
7865
8059
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
7866
8060
|
}
|
|
7867
|
-
async chown(path, change) {
|
|
8061
|
+
async chown(path, change, redirects = 0) {
|
|
7868
8062
|
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
7869
8063
|
const found = this.at(real);
|
|
7870
8064
|
if (found) return this.chownMounted(found, normalizePath(real), change);
|
|
7871
|
-
|
|
7872
|
-
|
|
8065
|
+
const { chown: chown2 } = this.base;
|
|
8066
|
+
if (!chown2) throw errnoError("EPERM", path);
|
|
8067
|
+
return this.based(
|
|
8068
|
+
[real],
|
|
8069
|
+
redirects,
|
|
8070
|
+
() => chown2.call(this.base, real, change),
|
|
8071
|
+
([to], n) => this.chown(to, change, n)
|
|
8072
|
+
);
|
|
7873
8073
|
}
|
|
7874
8074
|
async chownMounted(found, real, change) {
|
|
7875
8075
|
const { mount, rel: rel2 } = found;
|
|
@@ -7889,23 +8089,47 @@ var MountFs = class {
|
|
|
7889
8089
|
...Object.fromEntries(attrs.filter(([, value]) => value !== void 0))
|
|
7890
8090
|
});
|
|
7891
8091
|
}
|
|
7892
|
-
async chmod(path, mode) {
|
|
7893
|
-
const
|
|
7894
|
-
|
|
7895
|
-
|
|
8092
|
+
async chmod(path, mode, redirects = 0) {
|
|
8093
|
+
const real = await this.follow(path);
|
|
8094
|
+
const found = this.at(real);
|
|
8095
|
+
if (!found) {
|
|
8096
|
+
return this.based(
|
|
8097
|
+
[real],
|
|
8098
|
+
redirects,
|
|
8099
|
+
() => this.base.chmod(real, mode),
|
|
8100
|
+
([to], n) => this.chmod(to, mode, n)
|
|
8101
|
+
);
|
|
8102
|
+
}
|
|
8103
|
+
this.writable(found.mount, real);
|
|
7896
8104
|
if (!found.mount.caps.chmod) return;
|
|
7897
|
-
this.table.forget(found.mount,
|
|
8105
|
+
this.table.forget(found.mount, real);
|
|
7898
8106
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
7899
8107
|
}
|
|
7900
|
-
async utimes(path, atime, mtime) {
|
|
8108
|
+
async utimes(path, atime, mtime, redirects = 0) {
|
|
7901
8109
|
const real = await this.follow(path);
|
|
7902
8110
|
const found = this.at(real);
|
|
7903
|
-
if (!found)
|
|
8111
|
+
if (!found) {
|
|
8112
|
+
const set2 = () => this.base.utimes(real, atime, mtime);
|
|
8113
|
+
return this.based(
|
|
8114
|
+
[real],
|
|
8115
|
+
redirects,
|
|
8116
|
+
set2,
|
|
8117
|
+
([to], n) => this.utimes(to, atime, mtime, n)
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
7904
8120
|
await this.setMtime(found, real, mtime);
|
|
7905
8121
|
}
|
|
7906
|
-
async lutimes(path, atime, mtime) {
|
|
8122
|
+
async lutimes(path, atime, mtime, redirects = 0) {
|
|
7907
8123
|
const found = this.at(path);
|
|
7908
|
-
if (!found)
|
|
8124
|
+
if (!found) {
|
|
8125
|
+
const set2 = () => lutimesOf(this.base, path, atime, mtime);
|
|
8126
|
+
return this.based(
|
|
8127
|
+
[path],
|
|
8128
|
+
redirects,
|
|
8129
|
+
set2,
|
|
8130
|
+
([to], n) => this.lutimes(to, atime, mtime, n)
|
|
8131
|
+
);
|
|
8132
|
+
}
|
|
7909
8133
|
const real = normalizePath(path);
|
|
7910
8134
|
if (!found.mount.caps.linkTimes && (await this.lstat(real)).isSymbolicLink) {
|
|
7911
8135
|
throw errnoError("EOPNOTSUPP", path);
|
|
@@ -8124,7 +8348,8 @@ async function run(entry, path, req) {
|
|
|
8124
8348
|
function guardOf(entry) {
|
|
8125
8349
|
const cred = entry.dac && entry.cred?.();
|
|
8126
8350
|
if (!cred || !entry.dac) return void 0;
|
|
8127
|
-
|
|
8351
|
+
const links = entry.links === void 0 ? {} : { links: entry.links };
|
|
8352
|
+
return { fs: entry.fs, cred, pid: entry.pid ?? 0, dac: entry.dac, ...links };
|
|
8128
8353
|
}
|
|
8129
8354
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
8130
8355
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
@@ -8185,9 +8410,15 @@ async function holdOp(entry, path, req) {
|
|
|
8185
8410
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
8186
8411
|
return done;
|
|
8187
8412
|
}
|
|
8413
|
+
async function followed(g, path) {
|
|
8414
|
+
const st = await g.fs.lstat(path).catch(() => void 0);
|
|
8415
|
+
if (st?.isSymbolicLink && !trustedLink(permOf(st), g.links)) deny(g, "follow", path);
|
|
8416
|
+
return done;
|
|
8417
|
+
}
|
|
8188
8418
|
async function accessOp(entry, path, req) {
|
|
8189
8419
|
const g = guardOf(entry);
|
|
8190
8420
|
if (!g) return done;
|
|
8421
|
+
if (req.arg2 === "follow") return followed(g, path);
|
|
8191
8422
|
const open = req.arg2 === "open";
|
|
8192
8423
|
const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
|
|
8193
8424
|
const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
|
|
@@ -8210,15 +8441,18 @@ var CHANGING = /* @__PURE__ */ new Set([
|
|
|
8210
8441
|
"lchown"
|
|
8211
8442
|
]);
|
|
8212
8443
|
var CONTENT = /* @__PURE__ */ new Set(["write", "pwrite", "truncate"]);
|
|
8444
|
+
var REMOVING = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm", "rename"]);
|
|
8213
8445
|
async function mayChange(entry, path, req) {
|
|
8214
8446
|
const { mayChange: mayChange2 } = entry.fs;
|
|
8215
8447
|
if (!mayChange2) return;
|
|
8216
8448
|
const { op } = req;
|
|
8217
8449
|
if (CONTENT.has(op) && req.handle === void 0) return mayChange2.call(entry.fs, path, true);
|
|
8218
8450
|
if (!CHANGING.has(op)) return;
|
|
8219
|
-
|
|
8451
|
+
const follow2 = op === "utimes" || op === "chmod" || op === "chown";
|
|
8452
|
+
await mayChange2.call(entry.fs, path, follow2, REMOVING.has(op));
|
|
8220
8453
|
if (op === "rename" || op === "link") {
|
|
8221
|
-
|
|
8454
|
+
const to = entry.fs.resolvePath(entry.cwd, req.arg2 ?? "");
|
|
8455
|
+
await mayChange2.call(entry.fs, to, false, op === "rename");
|
|
8222
8456
|
}
|
|
8223
8457
|
}
|
|
8224
8458
|
async function guarded(entry, path, req) {
|
|
@@ -8938,7 +9172,7 @@ function mountTable(mounts = []) {
|
|
|
8938
9172
|
}
|
|
8939
9173
|
|
|
8940
9174
|
// src/version.ts
|
|
8941
|
-
var KERNEL_VERSION = true ? "1.
|
|
9175
|
+
var KERNEL_VERSION = true ? "1.89.0" : "0.0.0-dev";
|
|
8942
9176
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8943
9177
|
function procVersion() {
|
|
8944
9178
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11826,16 +12060,16 @@ function interruption(signal) {
|
|
|
11826
12060
|
}
|
|
11827
12061
|
async function selectFds(fds, read, write, timeoutMs, interrupt) {
|
|
11828
12062
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
11829
|
-
const
|
|
11830
|
-
|
|
12063
|
+
const interrupted3 = interruption(interrupt);
|
|
12064
|
+
interrupted3.promise.catch(() => {
|
|
11831
12065
|
});
|
|
11832
12066
|
try {
|
|
11833
|
-
return await waitReady(fds, read, write, deadline,
|
|
12067
|
+
return await waitReady(fds, read, write, deadline, interrupted3.promise);
|
|
11834
12068
|
} finally {
|
|
11835
|
-
|
|
12069
|
+
interrupted3.done();
|
|
11836
12070
|
}
|
|
11837
12071
|
}
|
|
11838
|
-
async function waitReady(fds, read, write, deadline,
|
|
12072
|
+
async function waitReady(fds, read, write, deadline, interrupted3) {
|
|
11839
12073
|
for (; ; ) {
|
|
11840
12074
|
const now = ready(fds, read, write);
|
|
11841
12075
|
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
@@ -11847,7 +12081,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
|
11847
12081
|
let timer;
|
|
11848
12082
|
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
11849
12083
|
try {
|
|
11850
|
-
await Promise.race([...changes, ...expiry,
|
|
12084
|
+
await Promise.race([...changes, ...expiry, interrupted3]);
|
|
11851
12085
|
} finally {
|
|
11852
12086
|
round.abort();
|
|
11853
12087
|
clearTimeout(timer);
|
|
@@ -13030,7 +13264,7 @@ var WasmProcess = class {
|
|
|
13030
13264
|
const { guard: guard2 } = this.options;
|
|
13031
13265
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
13032
13266
|
if (!guard2 || inherited2 || req.pin !== void 0) return;
|
|
13033
|
-
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13267
|
+
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13034
13268
|
if (req.exclusive) return inParent(g, "open", req.path);
|
|
13035
13269
|
if (req.created && guard2.created?.take(req.path)) return;
|
|
13036
13270
|
const access2 = req.flags & WRITE_ACCESS;
|
|
@@ -13086,7 +13320,7 @@ var WasmProcess = class {
|
|
|
13086
13320
|
}
|
|
13087
13321
|
guarded() {
|
|
13088
13322
|
const { guard: guard2 } = this.options;
|
|
13089
|
-
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13323
|
+
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13090
13324
|
}
|
|
13091
13325
|
ttyOwner() {
|
|
13092
13326
|
return { uid: this.cred.euid, gid: this.cred.egid, mode: TTY_MODE };
|
|
@@ -13812,6 +14046,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
13812
14046
|
umask,
|
|
13813
14047
|
cred,
|
|
13814
14048
|
...opts.owners ? { owners: true } : {},
|
|
14049
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
13815
14050
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
13816
14051
|
};
|
|
13817
14052
|
if (opts.program.abi === "js") {
|
|
@@ -13839,6 +14074,7 @@ function holdingToken(opts, holds, caller) {
|
|
|
13839
14074
|
return mintSyncFsToken({
|
|
13840
14075
|
...opts.owners ? caller : {},
|
|
13841
14076
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
14077
|
+
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
13842
14078
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
13843
14079
|
fs: opts.fs,
|
|
13844
14080
|
cwd: opts.cwd,
|
|
@@ -13852,6 +14088,9 @@ function holdingToken(opts, holds, caller) {
|
|
|
13852
14088
|
renamed: (from, to) => holds.renamed(from, to)
|
|
13853
14089
|
});
|
|
13854
14090
|
}
|
|
14091
|
+
function linksOf(opts) {
|
|
14092
|
+
return opts.links === void 0 ? {} : { links: opts.links };
|
|
14093
|
+
}
|
|
13855
14094
|
function clipboardName(opts) {
|
|
13856
14095
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
13857
14096
|
}
|
|
@@ -13863,7 +14102,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
13863
14102
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
13864
14103
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
13865
14104
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
13866
|
-
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
14105
|
+
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
13867
14106
|
...opts.identity ? { identity: opts.identity } : {},
|
|
13868
14107
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
13869
14108
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -13909,6 +14148,7 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
13909
14148
|
sab,
|
|
13910
14149
|
cred: copyCred(cred),
|
|
13911
14150
|
owners: opts.owners === true,
|
|
14151
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
13912
14152
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
13913
14153
|
thread,
|
|
13914
14154
|
signals: main
|
|
@@ -14776,63 +15016,137 @@ function compile(secrets, options = {}) {
|
|
|
14776
15016
|
|
|
14777
15017
|
// src/kernel/scrub-file.ts
|
|
14778
15018
|
var SCRUB_IDLE_MS = 50;
|
|
15019
|
+
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
14779
15020
|
var encoder5 = new TextEncoder();
|
|
14780
15021
|
function scrubberOf(secrets) {
|
|
14781
15022
|
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
14782
15023
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
14783
15024
|
}
|
|
14784
|
-
async function writeAll2(file, bytes
|
|
15025
|
+
async function writeAll2(file, bytes) {
|
|
14785
15026
|
const write = file.write;
|
|
14786
|
-
for (let at = 0; at < bytes.length; )
|
|
14787
|
-
at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
|
|
14788
|
-
}
|
|
15027
|
+
for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
|
|
14789
15028
|
}
|
|
14790
15029
|
function bound(file, key) {
|
|
14791
15030
|
const method = file[key];
|
|
14792
15031
|
return typeof method === "function" ? { [key]: method.bind(file) } : {};
|
|
14793
15032
|
}
|
|
15033
|
+
function interrupted2(err) {
|
|
15034
|
+
const code = err?.code;
|
|
15035
|
+
return code === "EINTR" || code === "EAGAIN";
|
|
15036
|
+
}
|
|
14794
15037
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
14795
15038
|
const file = inner.file;
|
|
14796
15039
|
const stream2 = scrubber.stream();
|
|
14797
|
-
let
|
|
15040
|
+
let tail = Promise.resolve();
|
|
15041
|
+
let pending = 0;
|
|
15042
|
+
let busy = false;
|
|
14798
15043
|
let timer;
|
|
14799
15044
|
let failed3;
|
|
15045
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
15046
|
+
const quiet2 = () => !busy && pending === 0;
|
|
15047
|
+
const wake = () => {
|
|
15048
|
+
for (const waiter of [...waiters]) waiter();
|
|
15049
|
+
};
|
|
14800
15050
|
const raise = () => {
|
|
14801
15051
|
if (failed3 === void 0) return;
|
|
14802
15052
|
const err = failed3;
|
|
14803
15053
|
failed3 = void 0;
|
|
14804
15054
|
throw err;
|
|
14805
15055
|
};
|
|
14806
|
-
const
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
15056
|
+
const later = (bytes) => {
|
|
15057
|
+
if (bytes.length === 0) return;
|
|
15058
|
+
pending += 1;
|
|
15059
|
+
tail = tail.then(() => writeAll2(file, bytes)).catch((err) => {
|
|
15060
|
+
if (failed3 === void 0) failed3 = err;
|
|
15061
|
+
}).finally(() => {
|
|
15062
|
+
pending -= 1;
|
|
15063
|
+
if (quiet2()) wake();
|
|
15064
|
+
});
|
|
15065
|
+
};
|
|
15066
|
+
const settling = (signal) => new Promise((resolve2, reject) => {
|
|
15067
|
+
const done4 = () => {
|
|
15068
|
+
waiters.delete(done4);
|
|
15069
|
+
signal?.removeEventListener("abort", stop);
|
|
15070
|
+
resolve2();
|
|
15071
|
+
};
|
|
15072
|
+
const stop = () => {
|
|
15073
|
+
waiters.delete(done4);
|
|
15074
|
+
reject(new KernelError("EINTR"));
|
|
15075
|
+
};
|
|
15076
|
+
if (signal?.aborted) return stop();
|
|
15077
|
+
waiters.add(done4);
|
|
15078
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
15079
|
+
});
|
|
15080
|
+
const settled = async () => {
|
|
15081
|
+
while (!quiet2()) await settling();
|
|
15082
|
+
};
|
|
15083
|
+
const changed = async (signal) => {
|
|
15084
|
+
const round = new AbortController();
|
|
15085
|
+
const stop = signal ? AbortSignal.any([signal, round.signal]) : round.signal;
|
|
15086
|
+
try {
|
|
15087
|
+
const own = settling(stop);
|
|
15088
|
+
await Promise.race(file.changed ? [own, file.changed(stop)] : [own]);
|
|
15089
|
+
} catch (err) {
|
|
15090
|
+
throw signal?.aborted ? new KernelError("EINTR") : err;
|
|
15091
|
+
} finally {
|
|
15092
|
+
round.abort();
|
|
15093
|
+
}
|
|
15094
|
+
};
|
|
15095
|
+
const turn = async (signal) => {
|
|
15096
|
+
for (let waited = false; ; waited = true) {
|
|
15097
|
+
if (quiet2() && (pollFile(file).writable || !file.changed)) {
|
|
15098
|
+
busy = true;
|
|
15099
|
+
return;
|
|
15100
|
+
}
|
|
15101
|
+
if (signal?.aborted) throw new KernelError(waited ? "EINTR" : "EAGAIN");
|
|
15102
|
+
await changed(signal);
|
|
15103
|
+
}
|
|
15104
|
+
};
|
|
15105
|
+
const send = async (out, signal) => {
|
|
15106
|
+
const write = file.write;
|
|
15107
|
+
for (let at = 0; at < out.length; ) {
|
|
15108
|
+
try {
|
|
15109
|
+
at += await write.call(file, out.subarray(at), signal);
|
|
15110
|
+
} catch (err) {
|
|
15111
|
+
if (!signal?.aborted || !interrupted2(err)) throw err;
|
|
15112
|
+
}
|
|
15113
|
+
if (at < out.length && signal?.aborted) return later(out.subarray(at));
|
|
15114
|
+
}
|
|
14810
15115
|
};
|
|
14811
15116
|
const release = () => {
|
|
14812
15117
|
timer = void 0;
|
|
14813
|
-
|
|
14814
|
-
failed3 = err;
|
|
14815
|
-
});
|
|
15118
|
+
later(stream2.idle());
|
|
14816
15119
|
};
|
|
14817
15120
|
return new OpenFile({
|
|
14818
15121
|
...bound(file, "read"),
|
|
14819
15122
|
...bound(file, "peek"),
|
|
14820
|
-
...bound(file, "poll"),
|
|
14821
|
-
...bound(file, "changed"),
|
|
14822
15123
|
...bound(file, "stat"),
|
|
15124
|
+
poll: () => {
|
|
15125
|
+
const state = pollFile(file);
|
|
15126
|
+
return quiet2() ? state : { ...state, writable: false };
|
|
15127
|
+
},
|
|
15128
|
+
changed,
|
|
14823
15129
|
...file.tty ? { tty: file.tty } : {},
|
|
14824
15130
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
14825
15131
|
...file.write ? {
|
|
14826
15132
|
write: async (bytes, signal) => {
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
15133
|
+
await turn(signal);
|
|
15134
|
+
const taken = signal?.aborted && bytes.length > SCRUB_NONBLOCK_MAX ? bytes.subarray(0, SCRUB_NONBLOCK_MAX) : bytes;
|
|
15135
|
+
try {
|
|
15136
|
+
raise();
|
|
15137
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
15138
|
+
timer = void 0;
|
|
15139
|
+
await send(stream2.push(taken), signal);
|
|
15140
|
+
} finally {
|
|
15141
|
+
busy = false;
|
|
15142
|
+
if (quiet2()) wake();
|
|
15143
|
+
}
|
|
14830
15144
|
timer = setTimeout(release, idleMs);
|
|
14831
|
-
return
|
|
15145
|
+
return taken.length;
|
|
14832
15146
|
}
|
|
14833
15147
|
} : {},
|
|
14834
15148
|
flush: async () => {
|
|
14835
|
-
await
|
|
15149
|
+
await settled();
|
|
14836
15150
|
raise();
|
|
14837
15151
|
await file.flush?.();
|
|
14838
15152
|
},
|
|
@@ -14840,7 +15154,9 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
14840
15154
|
if (timer !== void 0) clearTimeout(timer);
|
|
14841
15155
|
let failure;
|
|
14842
15156
|
try {
|
|
14843
|
-
await
|
|
15157
|
+
await settled();
|
|
15158
|
+
later(stream2.end());
|
|
15159
|
+
await settled();
|
|
14844
15160
|
raise();
|
|
14845
15161
|
} catch (err) {
|
|
14846
15162
|
failure = { err };
|
|
@@ -15016,12 +15332,12 @@ var SealedChannel = class {
|
|
|
15016
15332
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
15017
15333
|
let stop = () => {
|
|
15018
15334
|
};
|
|
15019
|
-
const
|
|
15335
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
15020
15336
|
stop = () => reject(new KernelError("EINTR"));
|
|
15021
15337
|
signal.addEventListener("abort", stop, { once: true });
|
|
15022
15338
|
});
|
|
15023
15339
|
try {
|
|
15024
|
-
await Promise.race([flight.done,
|
|
15340
|
+
await Promise.race([flight.done, interrupted3]);
|
|
15025
15341
|
} finally {
|
|
15026
15342
|
signal.removeEventListener("abort", stop);
|
|
15027
15343
|
}
|
|
@@ -17236,6 +17552,9 @@ var SUDO_SOURCE = [
|
|
|
17236
17552
|
].join("\n");
|
|
17237
17553
|
|
|
17238
17554
|
// src/launcher.ts
|
|
17555
|
+
function linksOf2(req) {
|
|
17556
|
+
return req.links === void 0 ? {} : { links: req.links };
|
|
17557
|
+
}
|
|
17239
17558
|
var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
17240
17559
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
17241
17560
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
@@ -17411,6 +17730,7 @@ var Launcher = class {
|
|
|
17411
17730
|
warned = /* @__PURE__ */ new Set();
|
|
17412
17731
|
compiled = /* @__PURE__ */ new Map();
|
|
17413
17732
|
texts = /* @__PURE__ */ new Map();
|
|
17733
|
+
revocations = 0;
|
|
17414
17734
|
integrity;
|
|
17415
17735
|
scannedFs;
|
|
17416
17736
|
get scanned() {
|
|
@@ -17423,6 +17743,7 @@ var Launcher = class {
|
|
|
17423
17743
|
described = /* @__PURE__ */ new Map();
|
|
17424
17744
|
creds = /* @__PURE__ */ new Map();
|
|
17425
17745
|
tags = /* @__PURE__ */ new Map();
|
|
17746
|
+
links = /* @__PURE__ */ new Map();
|
|
17426
17747
|
freshModules = new FreshModules();
|
|
17427
17748
|
granted = /* @__PURE__ */ new Map();
|
|
17428
17749
|
users;
|
|
@@ -17725,14 +18046,16 @@ var Launcher = class {
|
|
|
17725
18046
|
}
|
|
17726
18047
|
const path = this.fs.resolvePath(cwd, file);
|
|
17727
18048
|
const glue = await followLinks(this.base, path);
|
|
17728
|
-
const
|
|
17729
|
-
|
|
17730
|
-
|
|
17731
|
-
const
|
|
18049
|
+
const asked = glue === path ? {} : { asked: path };
|
|
18050
|
+
const linked2 = COMMAND2.exec(glue)?.[1];
|
|
18051
|
+
if (linked2 !== void 0) {
|
|
18052
|
+
const found = await this.resolve(`/bin/${linked2}`, argv0, cwd);
|
|
18053
|
+
const target = found && { ...found, ...asked };
|
|
18054
|
+
const byPath = !COMMAND2.test(path) && (await this.commands()).get(linked2)?.argv0Path === true;
|
|
17732
18055
|
return target && byPath ? { ...target, argv0: path } : target;
|
|
17733
18056
|
}
|
|
17734
18057
|
const own = await this.commandAt(glue, scope);
|
|
17735
|
-
if (own) return own.script ? void 0 : targetOf(own);
|
|
18058
|
+
if (own) return own.script ? void 0 : { ...targetOf(own), ...asked };
|
|
17736
18059
|
const head = await this.head(glue);
|
|
17737
18060
|
if (!head) return void 0;
|
|
17738
18061
|
if (isWasm(head)) {
|
|
@@ -17740,13 +18063,14 @@ var Launcher = class {
|
|
|
17740
18063
|
abi: "wasi",
|
|
17741
18064
|
glue,
|
|
17742
18065
|
wasm: glue,
|
|
17743
|
-
argv0: baseName(argv0 || file).replace(/\.wasm$/, "")
|
|
18066
|
+
argv0: baseName(argv0 || file).replace(/\.wasm$/, ""),
|
|
18067
|
+
...asked
|
|
17744
18068
|
};
|
|
17745
18069
|
}
|
|
17746
18070
|
if (interpreter(head) !== "node") return void 0;
|
|
17747
18071
|
const wasm = modulePath(glue);
|
|
17748
18072
|
if (!await this.base.exists(wasm)) return void 0;
|
|
17749
|
-
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file) };
|
|
18073
|
+
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file), ...asked };
|
|
17750
18074
|
}
|
|
17751
18075
|
async head(path) {
|
|
17752
18076
|
try {
|
|
@@ -17764,6 +18088,8 @@ var Launcher = class {
|
|
|
17764
18088
|
async interpreted(file, argv, cwd, scope, depth = 0) {
|
|
17765
18089
|
const command = await this.scriptCommand(file, cwd, scope);
|
|
17766
18090
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
18091
|
+
const byPath = command && file.includes("/") && !COMMAND2.test(file);
|
|
18092
|
+
const named = byPath ? { [script]: this.fs.resolvePath(cwd, file) } : {};
|
|
17767
18093
|
const head = await this.head(script);
|
|
17768
18094
|
if (!head) return void 0;
|
|
17769
18095
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
@@ -17786,7 +18112,8 @@ var Launcher = class {
|
|
|
17786
18112
|
target: withScriptEnv(inner.target, command),
|
|
17787
18113
|
via,
|
|
17788
18114
|
sources,
|
|
17789
|
-
...bins.length > 0 ? { bins } : {}
|
|
18115
|
+
...bins.length > 0 ? { bins } : {},
|
|
18116
|
+
asked: { ...inner.asked, ...named }
|
|
17790
18117
|
};
|
|
17791
18118
|
}
|
|
17792
18119
|
const target = withScriptEnv(found, command);
|
|
@@ -17795,7 +18122,8 @@ var Launcher = class {
|
|
|
17795
18122
|
args: [...target.prefix ?? [], ...passed],
|
|
17796
18123
|
via: [interp],
|
|
17797
18124
|
sources: [script],
|
|
17798
|
-
...command?.bin ? { bins: [script] } : {}
|
|
18125
|
+
...command?.bin ? { bins: [script] } : {},
|
|
18126
|
+
asked: named
|
|
17799
18127
|
};
|
|
17800
18128
|
}
|
|
17801
18129
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17809,7 +18137,14 @@ var Launcher = class {
|
|
|
17809
18137
|
async mayExec(cred, req, planned) {
|
|
17810
18138
|
const { dac } = this;
|
|
17811
18139
|
if (!dac) return;
|
|
17812
|
-
const g = {
|
|
18140
|
+
const g = {
|
|
18141
|
+
fs: this.fs,
|
|
18142
|
+
cred,
|
|
18143
|
+
pid: req.pid,
|
|
18144
|
+
dac,
|
|
18145
|
+
tag: req.tag,
|
|
18146
|
+
links: this.links.get(req.pid)
|
|
18147
|
+
};
|
|
17813
18148
|
const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
|
|
17814
18149
|
if (byPath(req.file)) {
|
|
17815
18150
|
const path = this.fs.resolvePath(req.cwd, req.file);
|
|
@@ -17966,8 +18301,8 @@ var Launcher = class {
|
|
|
17966
18301
|
readFile: (path) => this.integrity ? this.text(path, KERNEL_CALLER) : fs.readFile(path)
|
|
17967
18302
|
});
|
|
17968
18303
|
}
|
|
17969
|
-
async cacheKey(path) {
|
|
17970
|
-
const verified = await this.integrity?.key(path);
|
|
18304
|
+
async cacheKey(path, asked) {
|
|
18305
|
+
const verified = await this.integrity?.key(path, asked);
|
|
17971
18306
|
if (verified !== void 0) return verified;
|
|
17972
18307
|
const st = await this.base.stat(path);
|
|
17973
18308
|
return `${path}:${st.size}:${st.mtime.getTime()}`;
|
|
@@ -17976,30 +18311,31 @@ var Launcher = class {
|
|
|
17976
18311
|
const plain = () => fs.readFileBuffer(path);
|
|
17977
18312
|
return this.integrity ? this.integrity.read(path, caller, plain) : plain();
|
|
17978
18313
|
}
|
|
17979
|
-
keyed(path, caller) {
|
|
18314
|
+
keyed(path, caller, asked) {
|
|
17980
18315
|
const plain = async () => this.base.readFileBuffer(path);
|
|
17981
|
-
return this.integrity ? this.integrity.readKeyed(path, caller, plain) : plain().then((bytes) => ({ bytes }));
|
|
18316
|
+
return this.integrity ? this.integrity.readKeyed(path, caller, plain, asked) : plain().then((bytes) => ({ bytes }));
|
|
17982
18317
|
}
|
|
17983
18318
|
cached(cache, key, load) {
|
|
17984
18319
|
const hit = cache.get(key);
|
|
17985
18320
|
if (hit !== void 0) return hit;
|
|
18321
|
+
const revocations = this.revocations;
|
|
17986
18322
|
const loading2 = load();
|
|
17987
18323
|
const found = loading2.then(({ value }) => value);
|
|
17988
18324
|
cache.set(key, found);
|
|
17989
|
-
|
|
17990
|
-
(
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
17995
|
-
()
|
|
17996
|
-
);
|
|
18325
|
+
const drop = () => {
|
|
18326
|
+
if (cache.get(key) === found) cache.delete(key);
|
|
18327
|
+
};
|
|
18328
|
+
loading2.then((done4) => {
|
|
18329
|
+
if (done4.key === key || done4.key === void 0 && !key.includes("\0")) return;
|
|
18330
|
+
drop();
|
|
18331
|
+
if (done4.key !== void 0 && revocations === this.revocations) cache.set(done4.key, found);
|
|
18332
|
+
}, drop);
|
|
17997
18333
|
return found;
|
|
17998
18334
|
}
|
|
17999
|
-
async module(path, caller) {
|
|
18000
|
-
const key = await this.cacheKey(path);
|
|
18335
|
+
async module(path, caller, asked) {
|
|
18336
|
+
const key = await this.cacheKey(path, asked);
|
|
18001
18337
|
return this.cached(this.compiled, key, async () => {
|
|
18002
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18338
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18003
18339
|
const memory = importedMemory(bytes);
|
|
18004
18340
|
const foreign = foreignImports(bytes);
|
|
18005
18341
|
const compiled = await WebAssembly.compile(bytes);
|
|
@@ -18008,22 +18344,30 @@ var Launcher = class {
|
|
|
18008
18344
|
}
|
|
18009
18345
|
async checkedSources(planned, caller) {
|
|
18010
18346
|
const { target } = planned;
|
|
18011
|
-
const files = [
|
|
18347
|
+
const files = [
|
|
18348
|
+
target.wasm,
|
|
18349
|
+
target.glue,
|
|
18350
|
+
target.imports,
|
|
18351
|
+
target.asked,
|
|
18352
|
+
...planned.sources ?? []
|
|
18353
|
+
];
|
|
18012
18354
|
const manifests = /* @__PURE__ */ new Set();
|
|
18013
18355
|
for (const file of files) {
|
|
18014
18356
|
const root = file === void 0 ? void 0 : PACKAGE_ROOT.exec(file)?.[1];
|
|
18015
18357
|
if (root !== void 0) manifests.add(`${root}/package.json`);
|
|
18016
18358
|
}
|
|
18017
|
-
for (const source of planned.sources ?? [])
|
|
18359
|
+
for (const source of planned.sources ?? []) {
|
|
18360
|
+
await this.text(source, caller, planned.asked?.[source]);
|
|
18361
|
+
}
|
|
18018
18362
|
for (const manifest of manifests) {
|
|
18019
18363
|
if (await this.base.exists(manifest)) await this.text(manifest, caller);
|
|
18020
18364
|
}
|
|
18021
18365
|
}
|
|
18022
|
-
async text(path, caller) {
|
|
18366
|
+
async text(path, caller, asked) {
|
|
18023
18367
|
if (!this.integrity) return this.base.readFile(path);
|
|
18024
|
-
const key = await this.cacheKey(path);
|
|
18368
|
+
const key = await this.cacheKey(path, asked);
|
|
18025
18369
|
return this.cached(this.texts, key, async () => {
|
|
18026
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18370
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18027
18371
|
return { value: new TextDecoder().decode(bytes), key: read };
|
|
18028
18372
|
});
|
|
18029
18373
|
}
|
|
@@ -18040,17 +18384,18 @@ var Launcher = class {
|
|
|
18040
18384
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
18041
18385
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
18042
18386
|
}
|
|
18387
|
+
const { asked } = target;
|
|
18043
18388
|
if (target.abi === "js") {
|
|
18044
|
-
return { abi: "js", glue: await this.text(target.wasm, caller), path: target.wasm };
|
|
18389
|
+
return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
|
|
18045
18390
|
}
|
|
18046
18391
|
if (target.abi !== "wasi") {
|
|
18047
18392
|
const [glue, { module: module2 }] = await Promise.all([
|
|
18048
|
-
this.text(target.glue, caller),
|
|
18049
|
-
this.module(target.wasm, caller)
|
|
18393
|
+
this.text(target.glue, caller, asked),
|
|
18394
|
+
this.module(target.wasm, caller, asked && modulePath(asked))
|
|
18050
18395
|
]);
|
|
18051
18396
|
return { glue, module: module2 };
|
|
18052
18397
|
}
|
|
18053
|
-
const { module, memory, foreign } = await this.module(target.wasm, caller);
|
|
18398
|
+
const { module, memory, foreign } = await this.module(target.wasm, caller, asked);
|
|
18054
18399
|
const names = env.SLICC_WASM_BACKTRACE === "1" ? await this.names(target.wasm, module) : void 0;
|
|
18055
18400
|
const imports = target.imports ? await this.text(target.imports, caller) : void 0;
|
|
18056
18401
|
return {
|
|
@@ -18087,11 +18432,13 @@ var Launcher = class {
|
|
|
18087
18432
|
groupSession(pgid) {
|
|
18088
18433
|
return this.jobs.sessionOf(pgid);
|
|
18089
18434
|
}
|
|
18090
|
-
treeScrubs(
|
|
18435
|
+
treeScrubs(req) {
|
|
18091
18436
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
|
|
18437
|
+
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
18438
|
+
}
|
|
18439
|
+
marks(pid, req) {
|
|
18440
|
+
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
18441
|
+
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
18095
18442
|
}
|
|
18096
18443
|
start(req) {
|
|
18097
18444
|
this.sampling();
|
|
@@ -18099,7 +18446,7 @@ var Launcher = class {
|
|
|
18099
18446
|
throw new SpawnError("ESRCH");
|
|
18100
18447
|
}
|
|
18101
18448
|
const pid = req.pid ?? this.nextPid++;
|
|
18102
|
-
const scrubs = this.treeScrubs(
|
|
18449
|
+
const scrubs = this.treeScrubs(req);
|
|
18103
18450
|
const stack = this.stackFor(req.tag);
|
|
18104
18451
|
const terminal = req.fds.stdioTerminal();
|
|
18105
18452
|
const decided = req.decided ?? Promise.resolve(true);
|
|
@@ -18125,6 +18472,7 @@ var Launcher = class {
|
|
|
18125
18472
|
cred: req.cred,
|
|
18126
18473
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
18127
18474
|
...this.owners ? { owners: true } : {},
|
|
18475
|
+
...linksOf2(req),
|
|
18128
18476
|
sealed: this.sealed,
|
|
18129
18477
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
18130
18478
|
clipboard: this.clipboard,
|
|
@@ -18169,9 +18517,10 @@ var Launcher = class {
|
|
|
18169
18517
|
...this.shownIds(req)
|
|
18170
18518
|
});
|
|
18171
18519
|
this.processes.set(pid, handle);
|
|
18520
|
+
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18172
18521
|
const { cred } = req;
|
|
18173
18522
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
18174
|
-
|
|
18523
|
+
this.marks(pid, req);
|
|
18175
18524
|
if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
|
|
18176
18525
|
this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
|
|
18177
18526
|
if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
|
|
@@ -18224,6 +18573,7 @@ var Launcher = class {
|
|
|
18224
18573
|
this.childTimes.delete(pid);
|
|
18225
18574
|
this.creds.delete(pid);
|
|
18226
18575
|
this.tags.delete(pid);
|
|
18576
|
+
this.links.delete(pid);
|
|
18227
18577
|
this.granted.delete(pid);
|
|
18228
18578
|
}
|
|
18229
18579
|
reaped(pid, parent) {
|
|
@@ -18399,6 +18749,7 @@ var Launcher = class {
|
|
|
18399
18749
|
umask: this.umaskOf(ppid),
|
|
18400
18750
|
cred,
|
|
18401
18751
|
tag: this.tagOf(ppid),
|
|
18752
|
+
links: grant ? grant.cred.euid : this.links.get(ppid),
|
|
18402
18753
|
...group,
|
|
18403
18754
|
...exec
|
|
18404
18755
|
});
|
|
@@ -18460,7 +18811,8 @@ var Launcher = class {
|
|
|
18460
18811
|
blocked: this.blockedBy(ppid),
|
|
18461
18812
|
umask: this.umaskOf(ppid),
|
|
18462
18813
|
cred: this.credOf(ppid),
|
|
18463
|
-
tag: this.tagOf(ppid)
|
|
18814
|
+
tag: this.tagOf(ppid),
|
|
18815
|
+
links: this.links.get(ppid)
|
|
18464
18816
|
})
|
|
18465
18817
|
);
|
|
18466
18818
|
}
|
|
@@ -18640,6 +18992,23 @@ var Launcher = class {
|
|
|
18640
18992
|
}
|
|
18641
18993
|
};
|
|
18642
18994
|
}
|
|
18995
|
+
async revokeIntegrity(path) {
|
|
18996
|
+
if (path !== void 0 && (typeof path !== "string" || !path.startsWith("/"))) {
|
|
18997
|
+
throw new TypeError("integrity.revoke takes an absolute path");
|
|
18998
|
+
}
|
|
18999
|
+
if (!this.integrity) return;
|
|
19000
|
+
const at = path === void 0 ? void 0 : normalizePath(path);
|
|
19001
|
+
const real = at && await this.base.realpath?.(at, true).catch(() => void 0);
|
|
19002
|
+
const roots = [at, real].filter((p) => p !== void 0);
|
|
19003
|
+
this.revocations++;
|
|
19004
|
+
const hit = (key) => key.includes("\0") && (at === void 0 || key.split("\0").slice(0, 2).some((part) => isProtected(roots, part)));
|
|
19005
|
+
for (const cache of [this.compiled, this.texts]) {
|
|
19006
|
+
for (const key of [...cache.keys()]) if (hit(key)) cache.delete(key);
|
|
19007
|
+
}
|
|
19008
|
+
if (at === void 0) this.integrity.forget();
|
|
19009
|
+
for (const root of roots) this.integrity.forget(root);
|
|
19010
|
+
this.resetCatalogs();
|
|
19011
|
+
}
|
|
18643
19012
|
attest(path) {
|
|
18644
19013
|
return attest(this.rootFs, path, {
|
|
18645
19014
|
users: this.usersMode,
|
|
@@ -19461,7 +19830,7 @@ var RemoteTransport = class {
|
|
|
19461
19830
|
finish();
|
|
19462
19831
|
throw e;
|
|
19463
19832
|
}
|
|
19464
|
-
const { status, statusText, headers, url, redirected, redirects } = head;
|
|
19833
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
19465
19834
|
const read = async () => {
|
|
19466
19835
|
if (finished) return void 0;
|
|
19467
19836
|
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
@@ -19478,7 +19847,7 @@ var RemoteTransport = class {
|
|
|
19478
19847
|
this.cancel(nid);
|
|
19479
19848
|
};
|
|
19480
19849
|
return {
|
|
19481
|
-
...
|
|
19850
|
+
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
19482
19851
|
...redirects ? { redirects } : {},
|
|
19483
19852
|
status,
|
|
19484
19853
|
statusText,
|
|
@@ -20361,6 +20730,7 @@ async function createNodeKernel(options = {}) {
|
|
|
20361
20730
|
await launcher.fs.writeFile(path, data);
|
|
20362
20731
|
},
|
|
20363
20732
|
chmod: async (path, mode) => launcher.fs.chmod(path, modeOption(mode)),
|
|
20733
|
+
integrity: { revoke: (path) => guard2(() => launcher.revokeIntegrity(path)) },
|
|
20364
20734
|
readFile: async (path) => launcher.fs.readFileBuffer(path),
|
|
20365
20735
|
mount: (spec) => guard2(() => launcher.mount(spec)),
|
|
20366
20736
|
umount: (target) => guard2(async () => launcher.umount(target)),
|