@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/kernel-worker.js
CHANGED
|
@@ -383,6 +383,14 @@ function inodeOf(path) {
|
|
|
383
383
|
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
384
384
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
|
|
385
385
|
}
|
|
386
|
+
function redirected(of, to) {
|
|
387
|
+
return Object.assign(fsError("EXDEV", `${of} leads to the mount at ${to}`), {
|
|
388
|
+
redirect: { of: normalizePath(of), to: normalizePath(to) }
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function redirectOf(err) {
|
|
392
|
+
return err?.redirect;
|
|
393
|
+
}
|
|
386
394
|
|
|
387
395
|
// src/fs/owners.ts
|
|
388
396
|
var ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
|
|
@@ -476,39 +484,47 @@ var Integrity = class {
|
|
|
476
484
|
this.unknown = integrityUnknown(options);
|
|
477
485
|
this.report = report;
|
|
478
486
|
}
|
|
479
|
-
async real(path) {
|
|
487
|
+
async real(path, asked) {
|
|
480
488
|
const at = normalizePath(path);
|
|
481
489
|
const real = await this.root.realpath?.(at, true).catch(() => void 0) ?? at;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const
|
|
486
|
-
|
|
490
|
+
if (isProtected(this.prefixes, real)) return { real, name: real };
|
|
491
|
+
const names = asked === void 0 ? [] : await namesOf(this.root, asked);
|
|
492
|
+
if (real !== at) names.push(...await namesOf(this.root, at));
|
|
493
|
+
const name2 = names.findLast((p) => isProtected(this.prefixes, p));
|
|
494
|
+
return name2 === void 0 ? void 0 : { real, name: name2 };
|
|
495
|
+
}
|
|
496
|
+
async key(path, asked) {
|
|
497
|
+
const found = await this.real(path, asked);
|
|
498
|
+
if (found === void 0) return void 0;
|
|
499
|
+
const { real, name: name2 } = found;
|
|
500
|
+
if (name2 !== real) return `${name2}\0${real}\0`;
|
|
501
|
+
if (!this.root.version) return void 0;
|
|
487
502
|
return `${real}\0${await this.root.version(real)}`;
|
|
488
503
|
}
|
|
489
|
-
async read(path, caller, plain) {
|
|
490
|
-
return (await this.readKeyed(path, caller, plain)).bytes;
|
|
504
|
+
async read(path, caller, plain, asked) {
|
|
505
|
+
return (await this.readKeyed(path, caller, plain, asked)).bytes;
|
|
491
506
|
}
|
|
492
|
-
async readKeyed(path, caller, plain) {
|
|
493
|
-
const
|
|
494
|
-
if (
|
|
495
|
-
const
|
|
507
|
+
async readKeyed(path, caller, plain, asked) {
|
|
508
|
+
const found = await this.real(path, asked);
|
|
509
|
+
if (found === void 0) return { bytes: await plain() };
|
|
510
|
+
const { real, name: name2 } = found;
|
|
511
|
+
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 };
|
|
496
512
|
const { bytes } = read;
|
|
497
513
|
const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
|
|
498
514
|
const actual = await sha256(bytes);
|
|
499
|
-
const denial = { pid: caller.pid, uid: caller.uid, path:
|
|
515
|
+
const denial = { pid: caller.pid, uid: caller.uid, path: name2, actual };
|
|
500
516
|
const tagged = caller.tag !== void 0 ? { tag: caller.tag } : {};
|
|
501
517
|
let expected;
|
|
502
518
|
try {
|
|
503
|
-
expected = await this.expected(
|
|
519
|
+
expected = await this.expected(name2);
|
|
504
520
|
} catch {
|
|
505
521
|
this.say({ ...denial, ...tagged, op: "exec-integrity", errno: "EACCES" });
|
|
506
|
-
throw fsError("EACCES", `integrity lookup failed: ${
|
|
522
|
+
throw fsError("EACCES", `integrity lookup failed: ${name2}`);
|
|
507
523
|
}
|
|
508
524
|
if (expected === void 0) {
|
|
509
525
|
if (this.unknown === "allow") {
|
|
510
|
-
if (!this.unverified.has(
|
|
511
|
-
this.unverified.add(
|
|
526
|
+
if (!this.unverified.has(name2)) {
|
|
527
|
+
this.unverified.add(name2);
|
|
512
528
|
this.say({ ...denial, ...tagged, op: "exec-unverified", errno: "ENODATA" });
|
|
513
529
|
}
|
|
514
530
|
return keyed;
|
|
@@ -518,7 +534,12 @@ var Integrity = class {
|
|
|
518
534
|
}
|
|
519
535
|
const known = expected !== void 0 ? { expected } : {};
|
|
520
536
|
this.say({ ...denial, ...tagged, ...known, op: "exec-integrity", errno: "EACCES" });
|
|
521
|
-
throw fsError("EACCES", `integrity check failed: ${
|
|
537
|
+
throw fsError("EACCES", `integrity check failed: ${name2}`);
|
|
538
|
+
}
|
|
539
|
+
forget(path) {
|
|
540
|
+
for (const name2 of [...this.unverified]) {
|
|
541
|
+
if (path === void 0 || isProtected([path], name2)) this.unverified.delete(name2);
|
|
542
|
+
}
|
|
522
543
|
}
|
|
523
544
|
async expected(path) {
|
|
524
545
|
const answer = await this.lookup(path);
|
|
@@ -572,10 +593,10 @@ function missing(err) {
|
|
|
572
593
|
const code = err?.code;
|
|
573
594
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
574
595
|
}
|
|
575
|
-
async function resolved(fs, path, follow2) {
|
|
596
|
+
async function resolved(fs, path, follow2, hops = []) {
|
|
576
597
|
let done4 = [];
|
|
577
598
|
let todo = partsOf(path);
|
|
578
|
-
for (let
|
|
599
|
+
for (let links = 0; todo.length > 0; ) {
|
|
579
600
|
const part = todo.shift();
|
|
580
601
|
if (part === "..") {
|
|
581
602
|
done4.pop();
|
|
@@ -597,13 +618,20 @@ async function resolved(fs, path, follow2) {
|
|
|
597
618
|
done4.push(part);
|
|
598
619
|
continue;
|
|
599
620
|
}
|
|
600
|
-
if (++
|
|
621
|
+
if (++links > MAX_LINKS) throw fsError("ELOOP", path);
|
|
622
|
+
hops.push(normalizePath([at, ...todo].join("/")));
|
|
601
623
|
const link2 = await fs.readlink(at);
|
|
602
624
|
if (link2.startsWith("/")) done4 = [];
|
|
603
625
|
todo = [...partsOf(link2), ...todo];
|
|
604
626
|
}
|
|
605
627
|
return `/${done4.join("/")}`;
|
|
606
628
|
}
|
|
629
|
+
async function namesOf(fs, path) {
|
|
630
|
+
const lexical2 = normalizePath(path);
|
|
631
|
+
const hops = [];
|
|
632
|
+
await resolved(fs, lexical2, true, hops).catch(() => void 0);
|
|
633
|
+
return [lexical2, ...hops];
|
|
634
|
+
}
|
|
607
635
|
var ProtectedFs = class {
|
|
608
636
|
prefixes;
|
|
609
637
|
constructor(prefixes2) {
|
|
@@ -656,8 +684,8 @@ var ProtectedFs = class {
|
|
|
656
684
|
await check(path, true);
|
|
657
685
|
return fs.utimes(path, atime, mtime);
|
|
658
686
|
},
|
|
659
|
-
async mayChange(path, follow2) {
|
|
660
|
-
await check(path, follow2);
|
|
687
|
+
async mayChange(path, follow2, whole = false) {
|
|
688
|
+
await check(path, follow2, whole);
|
|
661
689
|
},
|
|
662
690
|
async stat(path) {
|
|
663
691
|
return marked(path, await fs.stat(path));
|
|
@@ -984,6 +1012,7 @@ var OpfsFs = class {
|
|
|
984
1012
|
remote;
|
|
985
1013
|
ranged;
|
|
986
1014
|
owners = false;
|
|
1015
|
+
mounts = {};
|
|
987
1016
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
988
1017
|
this.root = root;
|
|
989
1018
|
this.meta = sidecar(meta);
|
|
@@ -1057,6 +1086,12 @@ var OpfsFs = class {
|
|
|
1057
1086
|
trackOwners() {
|
|
1058
1087
|
this.owners = true;
|
|
1059
1088
|
}
|
|
1089
|
+
crossings(mounted) {
|
|
1090
|
+
this.mounts.mounted = mounted;
|
|
1091
|
+
}
|
|
1092
|
+
crossing(of, to) {
|
|
1093
|
+
if (this.mounts.mounted?.(to)) throw redirected(of, to);
|
|
1094
|
+
}
|
|
1060
1095
|
async hasOwner(path) {
|
|
1061
1096
|
return ownOf((await this.meta.get([path]))[0]) !== void 0;
|
|
1062
1097
|
}
|
|
@@ -1251,12 +1286,13 @@ var OpfsFs = class {
|
|
|
1251
1286
|
if (!link2) throw err;
|
|
1252
1287
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
1253
1288
|
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
1254
|
-
current = target.split("/").includes("..") ? await this.physical(parentOf3(link2.path), target, hops + 1) : resolvePath(parentOf3(link2.path), target);
|
|
1289
|
+
current = target.split("/").includes("..") ? await this.physical(parentOf3(link2.path), target, hops + 1, path) : resolvePath(parentOf3(link2.path), target);
|
|
1290
|
+
this.crossing(path, current);
|
|
1255
1291
|
}
|
|
1256
1292
|
}
|
|
1257
1293
|
throw fsError("ELOOP", path);
|
|
1258
1294
|
}
|
|
1259
|
-
async physical(base, path, used) {
|
|
1295
|
+
async physical(base, path, used, of) {
|
|
1260
1296
|
let done4 = [];
|
|
1261
1297
|
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
1262
1298
|
for (let hops = used; todo.length > 0; ) {
|
|
@@ -1265,6 +1301,7 @@ var OpfsFs = class {
|
|
|
1265
1301
|
else if (!todo.includes("..")) done4.push(part);
|
|
1266
1302
|
else {
|
|
1267
1303
|
const at = `/${[...done4, part].join("/")}`;
|
|
1304
|
+
this.crossing(of, [at, ...todo].join("/"));
|
|
1268
1305
|
const st = await this.lstat(at);
|
|
1269
1306
|
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
1270
1307
|
if (!st.isSymbolicLink) done4.push(part);
|
|
@@ -2159,7 +2196,10 @@ var Perms = class {
|
|
|
2159
2196
|
function parts(path) {
|
|
2160
2197
|
return path.split("/").filter((part) => part !== "" && part !== ".");
|
|
2161
2198
|
}
|
|
2162
|
-
|
|
2199
|
+
function trustedLink(perm, links) {
|
|
2200
|
+
return links === void 0 || perm.uid === 0 || perm.uid === links;
|
|
2201
|
+
}
|
|
2202
|
+
async function walk(fs, cred, path, follow2, links) {
|
|
2163
2203
|
const perms = new Perms(fs);
|
|
2164
2204
|
await perms.learn(path);
|
|
2165
2205
|
const queue = parts(path);
|
|
@@ -2177,6 +2217,7 @@ async function walk(fs, cred, path, follow2) {
|
|
|
2177
2217
|
const perm = await perms.at(next2);
|
|
2178
2218
|
const last = queue.length === 0;
|
|
2179
2219
|
if (perm?.link !== void 0 && (!last || follow2)) {
|
|
2220
|
+
if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next2, link: true };
|
|
2180
2221
|
if (++hops > MAX_LINKS4) return { path: next2, perm: void 0 };
|
|
2181
2222
|
queue.unshift(...parts(perm.link));
|
|
2182
2223
|
if (perm.link.startsWith("/")) at = "/";
|
|
@@ -2201,9 +2242,9 @@ async function finalOf(fs, walked, want, options) {
|
|
|
2201
2242
|
return st ? [permOf(st), st.isDirectory] : [perm, false];
|
|
2202
2243
|
}
|
|
2203
2244
|
async function access(fs, cred, path, want, options = {}) {
|
|
2204
|
-
const walked = await walk(fs, cred, path, options.follow !== false);
|
|
2245
|
+
const walked = await walk(fs, cred, path, options.follow !== false, options.links);
|
|
2205
2246
|
if (walked.denied !== void 0) {
|
|
2206
|
-
if (await present(fs, walked.denied, true)) return walked;
|
|
2247
|
+
if (walked.link || await present(fs, walked.denied, true)) return walked;
|
|
2207
2248
|
return { path, perm: void 0, missing: true };
|
|
2208
2249
|
}
|
|
2209
2250
|
if (!walked.perm) return { ...walked, missing: true };
|
|
@@ -2270,6 +2311,9 @@ var Created = class {
|
|
|
2270
2311
|
return this.paths.delete(normalizePath(path));
|
|
2271
2312
|
}
|
|
2272
2313
|
};
|
|
2314
|
+
function linked(g, options) {
|
|
2315
|
+
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
2316
|
+
}
|
|
2273
2317
|
function deny(g, op, path, errno = "EACCES") {
|
|
2274
2318
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
2275
2319
|
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno, ...tag });
|
|
@@ -2280,8 +2324,8 @@ function ttyOpenable(g, tty) {
|
|
|
2280
2324
|
deny(g, "open", tty.name ?? "/dev/tty");
|
|
2281
2325
|
}
|
|
2282
2326
|
async function need(g, op, path, want, options = {}, shown = path) {
|
|
2283
|
-
const walked = await access(g.fs, g.cred, path, want, options);
|
|
2284
|
-
if (walked.denied !== void 0) deny(g, op, shown);
|
|
2327
|
+
const walked = await access(g.fs, g.cred, path, want, linked(g, options));
|
|
2328
|
+
if (walked.denied !== void 0) deny(g, op, walked.link ? walked.denied : shown);
|
|
2285
2329
|
return walked;
|
|
2286
2330
|
}
|
|
2287
2331
|
function entryIn(dir, path) {
|
|
@@ -2300,14 +2344,16 @@ async function inParent(g, op, path, old = false) {
|
|
|
2300
2344
|
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
2301
2345
|
}
|
|
2302
2346
|
if (!old) return void await need(g, op, parentOf4(path), W_OK | X_OK, DIR, path);
|
|
2303
|
-
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, DIR);
|
|
2347
|
+
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, linked(g, DIR));
|
|
2304
2348
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
2349
|
+
if (dir.link) return deny(g, op, dir.denied);
|
|
2305
2350
|
const lookup = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
2306
2351
|
if (!lookup || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
2307
2352
|
}
|
|
2308
2353
|
async function makeIn(g, op, path) {
|
|
2309
2354
|
for (let dir = parentOf4(path); ; dir = parentOf4(dir)) {
|
|
2310
|
-
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
|
|
2355
|
+
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
2356
|
+
if (walked.link) return deny(g, op, walked.denied);
|
|
2311
2357
|
if (walked.denied !== void 0) {
|
|
2312
2358
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
2313
2359
|
return;
|
|
@@ -4580,12 +4626,12 @@ async function interruptible(work, signal) {
|
|
|
4580
4626
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
4581
4627
|
let stop = () => {
|
|
4582
4628
|
};
|
|
4583
|
-
const
|
|
4629
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
4584
4630
|
stop = () => reject(new KernelError("EINTR"));
|
|
4585
4631
|
signal.addEventListener("abort", stop, { once: true });
|
|
4586
4632
|
});
|
|
4587
4633
|
try {
|
|
4588
|
-
return await Promise.race([work,
|
|
4634
|
+
return await Promise.race([work, interrupted3]);
|
|
4589
4635
|
} finally {
|
|
4590
4636
|
signal.removeEventListener("abort", stop);
|
|
4591
4637
|
}
|
|
@@ -6599,7 +6645,7 @@ var RemoteTransport = class {
|
|
|
6599
6645
|
finish();
|
|
6600
6646
|
throw e;
|
|
6601
6647
|
}
|
|
6602
|
-
const { status, statusText, headers, url, redirected, redirects } = head;
|
|
6648
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
6603
6649
|
const read = async () => {
|
|
6604
6650
|
if (finished) return void 0;
|
|
6605
6651
|
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
@@ -6616,7 +6662,7 @@ var RemoteTransport = class {
|
|
|
6616
6662
|
this.cancel(nid);
|
|
6617
6663
|
};
|
|
6618
6664
|
return {
|
|
6619
|
-
...
|
|
6665
|
+
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
6620
6666
|
...redirects ? { redirects } : {},
|
|
6621
6667
|
status,
|
|
6622
6668
|
statusText,
|
|
@@ -7641,14 +7687,14 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7641
7687
|
const own = await userDir(dir);
|
|
7642
7688
|
return own?.has(path.slice(slash + 1)) ? owned4(synthetic(false, path), dir) : void 0;
|
|
7643
7689
|
}
|
|
7644
|
-
async function
|
|
7690
|
+
async function linked2(path) {
|
|
7645
7691
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
7646
7692
|
}
|
|
7647
7693
|
async function stat(path, real) {
|
|
7648
7694
|
try {
|
|
7649
7695
|
return await real(path);
|
|
7650
7696
|
} catch (err) {
|
|
7651
|
-
const found = missing3(err) ? await
|
|
7697
|
+
const found = missing3(err) ? await linked2(path) : void 0;
|
|
7652
7698
|
if (found) return found;
|
|
7653
7699
|
throw err;
|
|
7654
7700
|
}
|
|
@@ -7660,7 +7706,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7660
7706
|
try {
|
|
7661
7707
|
return await fs.readFileBuffer(path);
|
|
7662
7708
|
} catch (err) {
|
|
7663
|
-
if (missing3(err) && (await
|
|
7709
|
+
if (missing3(err) && (await linked2(path))?.isFile) return new Uint8Array(0);
|
|
7664
7710
|
throw err;
|
|
7665
7711
|
}
|
|
7666
7712
|
},
|
|
@@ -7668,7 +7714,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7668
7714
|
link: (from, to, follow2) => fs.link(from, to, follow2),
|
|
7669
7715
|
links: (path) => mayLink(fs, path),
|
|
7670
7716
|
async exists(path) {
|
|
7671
|
-
return await fs.exists(path) || await
|
|
7717
|
+
return await fs.exists(path) || await linked2(path) !== void 0;
|
|
7672
7718
|
},
|
|
7673
7719
|
stat: (path) => stat(path, (p) => fs.stat(p)),
|
|
7674
7720
|
lstat: (path) => stat(path, (p) => fs.lstat(p)),
|
|
@@ -9093,6 +9139,7 @@ var MountTable = class {
|
|
|
9093
9139
|
return { quota: st.blocks * st.bsize, usage: (st.blocks - st.bfree) * st.bsize };
|
|
9094
9140
|
}
|
|
9095
9141
|
wrap(base) {
|
|
9142
|
+
base.crossings?.((path) => this.locate(normalizePath(path)) !== void 0);
|
|
9096
9143
|
return new MountFs(this, base);
|
|
9097
9144
|
}
|
|
9098
9145
|
};
|
|
@@ -9116,6 +9163,37 @@ var MountFs = class {
|
|
|
9116
9163
|
writable(mount, path) {
|
|
9117
9164
|
if (readonly(mount)) throw errnoError("EROFS", path);
|
|
9118
9165
|
}
|
|
9166
|
+
async through(path) {
|
|
9167
|
+
const real = normalizePath(path);
|
|
9168
|
+
if (this.at(real)) return real;
|
|
9169
|
+
try {
|
|
9170
|
+
await this.base.stat(parentOf7(real));
|
|
9171
|
+
return real;
|
|
9172
|
+
} catch (err) {
|
|
9173
|
+
const moved2 = redirectOf(err);
|
|
9174
|
+
return moved2 ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
9175
|
+
}
|
|
9176
|
+
}
|
|
9177
|
+
async across(from, to, redirects) {
|
|
9178
|
+
const moved2 = [await this.through(from), await this.through(to)];
|
|
9179
|
+
const same = moved2[0] === normalizePath(from) && moved2[1] === normalizePath(to);
|
|
9180
|
+
if (same || redirects >= MAX_LINKS7) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
9181
|
+
return moved2;
|
|
9182
|
+
}
|
|
9183
|
+
async based(paths, redirects, run2, again) {
|
|
9184
|
+
try {
|
|
9185
|
+
return await run2();
|
|
9186
|
+
} catch (err) {
|
|
9187
|
+
const moved2 = redirectOf(err);
|
|
9188
|
+
if (!moved2) throw err;
|
|
9189
|
+
if (redirects >= MAX_LINKS7) throw errnoError("ELOOP", paths[0]);
|
|
9190
|
+
const at = paths.map((path) => {
|
|
9191
|
+
const real = normalizePath(path);
|
|
9192
|
+
return within6(real, moved2.of) ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
9193
|
+
});
|
|
9194
|
+
return again(at, redirects + 1);
|
|
9195
|
+
}
|
|
9196
|
+
}
|
|
9119
9197
|
async follow(path, hops = 0, create = false) {
|
|
9120
9198
|
const found = this.at(path);
|
|
9121
9199
|
if (!found) return path;
|
|
@@ -9163,10 +9241,17 @@ var MountFs = class {
|
|
|
9163
9241
|
async readFile(path) {
|
|
9164
9242
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
9165
9243
|
}
|
|
9166
|
-
async readFileBuffer(path) {
|
|
9244
|
+
async readFileBuffer(path, redirects = 0) {
|
|
9167
9245
|
const real = await this.follow(path);
|
|
9168
9246
|
const found = this.at(real);
|
|
9169
|
-
if (!found)
|
|
9247
|
+
if (!found) {
|
|
9248
|
+
return this.based(
|
|
9249
|
+
[real],
|
|
9250
|
+
redirects,
|
|
9251
|
+
() => this.base.readFileBuffer(real),
|
|
9252
|
+
([to], n) => this.readFileBuffer(to, n)
|
|
9253
|
+
);
|
|
9254
|
+
}
|
|
9170
9255
|
for (let attempt = 1; ; attempt++) {
|
|
9171
9256
|
try {
|
|
9172
9257
|
return await this.readWhole(found.mount, real, found.rel);
|
|
@@ -9205,10 +9290,18 @@ var MountFs = class {
|
|
|
9205
9290
|
}
|
|
9206
9291
|
return concat4(chunks, total);
|
|
9207
9292
|
}
|
|
9208
|
-
async writeFile(path, content, owner) {
|
|
9293
|
+
async writeFile(path, content, owner, redirects = 0) {
|
|
9209
9294
|
const real = await this.follow(path, 0, true);
|
|
9210
9295
|
const found = this.at(real);
|
|
9211
|
-
if (!found)
|
|
9296
|
+
if (!found) {
|
|
9297
|
+
const write = () => this.base.writeFile(real, content, owner);
|
|
9298
|
+
return this.based(
|
|
9299
|
+
[real],
|
|
9300
|
+
redirects,
|
|
9301
|
+
write,
|
|
9302
|
+
([to], n) => this.writeFile(to, content, owner, n)
|
|
9303
|
+
);
|
|
9304
|
+
}
|
|
9212
9305
|
const { mount, rel: rel2 } = found;
|
|
9213
9306
|
this.writable(mount, real);
|
|
9214
9307
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -9242,10 +9335,18 @@ var MountFs = class {
|
|
|
9242
9335
|
this.table.forget(mount, real);
|
|
9243
9336
|
}
|
|
9244
9337
|
}
|
|
9245
|
-
async pread(path, offset, length2, version) {
|
|
9338
|
+
async pread(path, offset, length2, version, redirects = 0) {
|
|
9246
9339
|
const real = await this.follow(path);
|
|
9247
9340
|
const found = this.at(real);
|
|
9248
|
-
|
|
9341
|
+
const { pread } = this.base;
|
|
9342
|
+
if (!found && pread) {
|
|
9343
|
+
return this.based(
|
|
9344
|
+
[real],
|
|
9345
|
+
redirects,
|
|
9346
|
+
() => pread.call(this.base, real, offset, length2),
|
|
9347
|
+
([to], n) => this.pread(to, offset, length2, version, n)
|
|
9348
|
+
);
|
|
9349
|
+
}
|
|
9249
9350
|
if (!found) return (await this.base.readFileBuffer(real)).slice(offset, offset + length2);
|
|
9250
9351
|
const { mount, rel: rel2 } = found;
|
|
9251
9352
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
@@ -9292,10 +9393,18 @@ var MountFs = class {
|
|
|
9292
9393
|
);
|
|
9293
9394
|
}
|
|
9294
9395
|
}
|
|
9295
|
-
async pwrite(path, offset, bytes, transfer = false) {
|
|
9396
|
+
async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
|
|
9296
9397
|
const real = await this.follow(path, 0, true);
|
|
9297
9398
|
const found = this.at(real);
|
|
9298
|
-
|
|
9399
|
+
const { pwrite } = this.base;
|
|
9400
|
+
if (!found && pwrite) {
|
|
9401
|
+
return this.based(
|
|
9402
|
+
[real],
|
|
9403
|
+
redirects,
|
|
9404
|
+
() => pwrite.call(this.base, real, offset, bytes),
|
|
9405
|
+
([to], n) => this.pwrite(to, offset, bytes, transfer, n)
|
|
9406
|
+
);
|
|
9407
|
+
}
|
|
9299
9408
|
if (!found)
|
|
9300
9409
|
return this.base.writeFile(
|
|
9301
9410
|
real,
|
|
@@ -9335,10 +9444,18 @@ var MountFs = class {
|
|
|
9335
9444
|
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
9336
9445
|
}
|
|
9337
9446
|
}
|
|
9338
|
-
async truncate(path, size) {
|
|
9447
|
+
async truncate(path, size, redirects = 0) {
|
|
9339
9448
|
const real = await this.follow(path);
|
|
9340
9449
|
const found = this.at(real);
|
|
9341
|
-
|
|
9450
|
+
const { truncate } = this.base;
|
|
9451
|
+
if (!found && truncate) {
|
|
9452
|
+
return this.based(
|
|
9453
|
+
[real],
|
|
9454
|
+
redirects,
|
|
9455
|
+
() => truncate.call(this.base, real, size),
|
|
9456
|
+
([to], n) => this.truncate(to, size, n)
|
|
9457
|
+
);
|
|
9458
|
+
}
|
|
9342
9459
|
if (!found?.mount.caps.ranges) {
|
|
9343
9460
|
return this.writeFile(real, resized(await this.readFileBuffer(real), size));
|
|
9344
9461
|
}
|
|
@@ -9354,8 +9471,15 @@ var MountFs = class {
|
|
|
9354
9471
|
this.table.forget(mount, real);
|
|
9355
9472
|
}
|
|
9356
9473
|
}
|
|
9357
|
-
async exists(path) {
|
|
9358
|
-
if (!this.at(path))
|
|
9474
|
+
async exists(path, redirects = 0) {
|
|
9475
|
+
if (!this.at(path)) {
|
|
9476
|
+
return this.based(
|
|
9477
|
+
[path],
|
|
9478
|
+
redirects,
|
|
9479
|
+
() => this.base.exists(path),
|
|
9480
|
+
([to], n) => this.exists(to, n)
|
|
9481
|
+
);
|
|
9482
|
+
}
|
|
9359
9483
|
try {
|
|
9360
9484
|
await this.stat(path);
|
|
9361
9485
|
return true;
|
|
@@ -9365,9 +9489,16 @@ var MountFs = class {
|
|
|
9365
9489
|
throw err;
|
|
9366
9490
|
}
|
|
9367
9491
|
}
|
|
9368
|
-
async lstat(path) {
|
|
9492
|
+
async lstat(path, redirects = 0) {
|
|
9369
9493
|
const found = this.at(path);
|
|
9370
|
-
if (!found)
|
|
9494
|
+
if (!found) {
|
|
9495
|
+
return this.based(
|
|
9496
|
+
[path],
|
|
9497
|
+
redirects,
|
|
9498
|
+
() => this.base.lstat(path),
|
|
9499
|
+
([to], n) => this.lstat(to, n)
|
|
9500
|
+
);
|
|
9501
|
+
}
|
|
9371
9502
|
const real = normalizePath(path);
|
|
9372
9503
|
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
9373
9504
|
return this.statWriting(
|
|
@@ -9380,9 +9511,15 @@ var MountFs = class {
|
|
|
9380
9511
|
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
9381
9512
|
return statOf({ ...attr2, size: Math.max(attr2.size, ...ends) }, real, mount);
|
|
9382
9513
|
}
|
|
9383
|
-
async stat(path) {
|
|
9514
|
+
async stat(path, redirects = 0) {
|
|
9384
9515
|
const real = await this.follow(path);
|
|
9385
|
-
|
|
9516
|
+
if (this.at(real)) return this.lstat(real);
|
|
9517
|
+
return this.based(
|
|
9518
|
+
[real],
|
|
9519
|
+
redirects,
|
|
9520
|
+
() => this.base.stat(real),
|
|
9521
|
+
([to], n) => this.stat(to, n)
|
|
9522
|
+
);
|
|
9386
9523
|
}
|
|
9387
9524
|
async entries(path) {
|
|
9388
9525
|
const real = await this.follow(path);
|
|
@@ -9394,12 +9531,26 @@ var MountFs = class {
|
|
|
9394
9531
|
list: await this.table.readdir(found.mount, real, found.rel)
|
|
9395
9532
|
};
|
|
9396
9533
|
}
|
|
9397
|
-
async readdir(path) {
|
|
9398
|
-
if (!this.at(path))
|
|
9534
|
+
async readdir(path, redirects = 0) {
|
|
9535
|
+
if (!this.at(path)) {
|
|
9536
|
+
return this.based(
|
|
9537
|
+
[path],
|
|
9538
|
+
redirects,
|
|
9539
|
+
() => this.base.readdir(path),
|
|
9540
|
+
([to], n) => this.readdir(to, n)
|
|
9541
|
+
);
|
|
9542
|
+
}
|
|
9399
9543
|
return (await this.entries(path)).list.map((e) => e.name);
|
|
9400
9544
|
}
|
|
9401
|
-
async readdirStat(path) {
|
|
9402
|
-
if (!this.at(path))
|
|
9545
|
+
async readdirStat(path, redirects = 0) {
|
|
9546
|
+
if (!this.at(path)) {
|
|
9547
|
+
return this.based(
|
|
9548
|
+
[path],
|
|
9549
|
+
redirects,
|
|
9550
|
+
() => this.base.readdirStat(path),
|
|
9551
|
+
([to], n) => this.readdirStat(to, n)
|
|
9552
|
+
);
|
|
9553
|
+
}
|
|
9403
9554
|
const { real, mount, list } = await this.entries(path);
|
|
9404
9555
|
return Promise.all(
|
|
9405
9556
|
list.map(async (entry) => {
|
|
@@ -9411,9 +9562,16 @@ var MountFs = class {
|
|
|
9411
9562
|
})
|
|
9412
9563
|
);
|
|
9413
9564
|
}
|
|
9414
|
-
async mkdir(path, options = {}) {
|
|
9565
|
+
async mkdir(path, options = {}, redirects = 0) {
|
|
9415
9566
|
const found = this.at(path);
|
|
9416
|
-
if (!found)
|
|
9567
|
+
if (!found) {
|
|
9568
|
+
return this.based(
|
|
9569
|
+
[path],
|
|
9570
|
+
redirects,
|
|
9571
|
+
() => this.base.mkdir(path, options),
|
|
9572
|
+
([to], n) => this.mkdir(to, options, n)
|
|
9573
|
+
);
|
|
9574
|
+
}
|
|
9417
9575
|
const { mount, rel: rel2 } = found;
|
|
9418
9576
|
const real = normalizePath(path);
|
|
9419
9577
|
this.writable(mount, real);
|
|
@@ -9438,11 +9596,18 @@ var MountFs = class {
|
|
|
9438
9596
|
await mount.conn.call({ op: "mkdir", path: sub, ...made2 });
|
|
9439
9597
|
}
|
|
9440
9598
|
}
|
|
9441
|
-
async rm(path, options = {}) {
|
|
9599
|
+
async rm(path, options = {}, redirects = 0) {
|
|
9442
9600
|
const found = this.at(path);
|
|
9443
9601
|
if (!found && options.recursive && this.table.under(normalizePath(path)))
|
|
9444
9602
|
return this.rmAround(normalizePath(path), options);
|
|
9445
|
-
if (!found)
|
|
9603
|
+
if (!found) {
|
|
9604
|
+
return this.based(
|
|
9605
|
+
[path],
|
|
9606
|
+
redirects,
|
|
9607
|
+
() => this.base.rm(path, options),
|
|
9608
|
+
([to], n) => this.rm(to, options, n)
|
|
9609
|
+
);
|
|
9610
|
+
}
|
|
9446
9611
|
const { mount, rel: rel2 } = found;
|
|
9447
9612
|
const real = normalizePath(path);
|
|
9448
9613
|
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
@@ -9483,11 +9648,22 @@ var MountFs = class {
|
|
|
9483
9648
|
}
|
|
9484
9649
|
throw first ?? errnoError("EBUSY", `${path} holds a mount point`);
|
|
9485
9650
|
}
|
|
9486
|
-
async rename(from, to) {
|
|
9651
|
+
async rename(from, to, redirects = 0) {
|
|
9487
9652
|
const a = this.at(from);
|
|
9488
9653
|
const b = this.at(to);
|
|
9489
|
-
if (!a && !b)
|
|
9490
|
-
|
|
9654
|
+
if (!a && !b) {
|
|
9655
|
+
return this.based(
|
|
9656
|
+
[from, to],
|
|
9657
|
+
redirects,
|
|
9658
|
+
() => this.base.rename(from, to),
|
|
9659
|
+
([f, t], n) => this.rename(f, t, n)
|
|
9660
|
+
);
|
|
9661
|
+
}
|
|
9662
|
+
if (!a || !b) {
|
|
9663
|
+
const [f, t] = await this.across(from, to, redirects);
|
|
9664
|
+
return this.rename(f, t, redirects + 1);
|
|
9665
|
+
}
|
|
9666
|
+
if (a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
9491
9667
|
this.writable(a.mount, normalizePath(to));
|
|
9492
9668
|
await this.table.commitUnder(from);
|
|
9493
9669
|
await this.table.commitUnder(to);
|
|
@@ -9528,9 +9704,17 @@ var MountFs = class {
|
|
|
9528
9704
|
this.table.forget(a.mount, normalizePath(to));
|
|
9529
9705
|
}
|
|
9530
9706
|
}
|
|
9531
|
-
async symlink(target, path, owner) {
|
|
9707
|
+
async symlink(target, path, owner, redirects = 0) {
|
|
9532
9708
|
const found = this.at(path);
|
|
9533
|
-
if (!found)
|
|
9709
|
+
if (!found) {
|
|
9710
|
+
const make = () => this.base.symlink(target, path, owner);
|
|
9711
|
+
return this.based(
|
|
9712
|
+
[path],
|
|
9713
|
+
redirects,
|
|
9714
|
+
make,
|
|
9715
|
+
([to], n) => this.symlink(target, to, owner, n)
|
|
9716
|
+
);
|
|
9717
|
+
}
|
|
9534
9718
|
this.writable(found.mount, normalizePath(path));
|
|
9535
9719
|
if (!found.mount.caps.symlinks)
|
|
9536
9720
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -9540,8 +9724,11 @@ var MountFs = class {
|
|
|
9540
9724
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel, ...made2 });
|
|
9541
9725
|
}
|
|
9542
9726
|
async realpath(path, follow2) {
|
|
9543
|
-
|
|
9544
|
-
|
|
9727
|
+
const { realpath: realpath2 } = this.base;
|
|
9728
|
+
if (this.at(path) || !realpath2) throw errnoError("ENOSYS", path);
|
|
9729
|
+
const real = await realpath2.call(this.base, path, follow2).catch((err) => {
|
|
9730
|
+
throw redirectOf(err) ? errnoError("ENOSYS", path) : err;
|
|
9731
|
+
});
|
|
9545
9732
|
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
9546
9733
|
return real;
|
|
9547
9734
|
}
|
|
@@ -9563,17 +9750,30 @@ var MountFs = class {
|
|
|
9563
9750
|
}
|
|
9564
9751
|
return out;
|
|
9565
9752
|
}
|
|
9566
|
-
async readlink(path) {
|
|
9753
|
+
async readlink(path, redirects = 0) {
|
|
9567
9754
|
const found = this.at(path);
|
|
9568
|
-
if (!found)
|
|
9755
|
+
if (!found) {
|
|
9756
|
+
return this.based(
|
|
9757
|
+
[path],
|
|
9758
|
+
redirects,
|
|
9759
|
+
() => this.base.readlink(path),
|
|
9760
|
+
([to], n) => this.readlink(to, n)
|
|
9761
|
+
);
|
|
9762
|
+
}
|
|
9569
9763
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
9570
9764
|
}
|
|
9571
|
-
async chown(path, change) {
|
|
9765
|
+
async chown(path, change, redirects = 0) {
|
|
9572
9766
|
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
9573
9767
|
const found = this.at(real);
|
|
9574
9768
|
if (found) return this.chownMounted(found, normalizePath(real), change);
|
|
9575
|
-
|
|
9576
|
-
|
|
9769
|
+
const { chown: chown2 } = this.base;
|
|
9770
|
+
if (!chown2) throw errnoError("EPERM", path);
|
|
9771
|
+
return this.based(
|
|
9772
|
+
[real],
|
|
9773
|
+
redirects,
|
|
9774
|
+
() => chown2.call(this.base, real, change),
|
|
9775
|
+
([to], n) => this.chown(to, change, n)
|
|
9776
|
+
);
|
|
9577
9777
|
}
|
|
9578
9778
|
async chownMounted(found, real, change) {
|
|
9579
9779
|
const { mount, rel: rel2 } = found;
|
|
@@ -9593,23 +9793,47 @@ var MountFs = class {
|
|
|
9593
9793
|
...Object.fromEntries(attrs.filter(([, value]) => value !== void 0))
|
|
9594
9794
|
});
|
|
9595
9795
|
}
|
|
9596
|
-
async chmod(path, mode) {
|
|
9597
|
-
const
|
|
9598
|
-
|
|
9599
|
-
|
|
9796
|
+
async chmod(path, mode, redirects = 0) {
|
|
9797
|
+
const real = await this.follow(path);
|
|
9798
|
+
const found = this.at(real);
|
|
9799
|
+
if (!found) {
|
|
9800
|
+
return this.based(
|
|
9801
|
+
[real],
|
|
9802
|
+
redirects,
|
|
9803
|
+
() => this.base.chmod(real, mode),
|
|
9804
|
+
([to], n) => this.chmod(to, mode, n)
|
|
9805
|
+
);
|
|
9806
|
+
}
|
|
9807
|
+
this.writable(found.mount, real);
|
|
9600
9808
|
if (!found.mount.caps.chmod) return;
|
|
9601
|
-
this.table.forget(found.mount,
|
|
9809
|
+
this.table.forget(found.mount, real);
|
|
9602
9810
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
9603
9811
|
}
|
|
9604
|
-
async utimes(path, atime, mtime) {
|
|
9812
|
+
async utimes(path, atime, mtime, redirects = 0) {
|
|
9605
9813
|
const real = await this.follow(path);
|
|
9606
9814
|
const found = this.at(real);
|
|
9607
|
-
if (!found)
|
|
9815
|
+
if (!found) {
|
|
9816
|
+
const set2 = () => this.base.utimes(real, atime, mtime);
|
|
9817
|
+
return this.based(
|
|
9818
|
+
[real],
|
|
9819
|
+
redirects,
|
|
9820
|
+
set2,
|
|
9821
|
+
([to], n) => this.utimes(to, atime, mtime, n)
|
|
9822
|
+
);
|
|
9823
|
+
}
|
|
9608
9824
|
await this.setMtime(found, real, mtime);
|
|
9609
9825
|
}
|
|
9610
|
-
async lutimes(path, atime, mtime) {
|
|
9826
|
+
async lutimes(path, atime, mtime, redirects = 0) {
|
|
9611
9827
|
const found = this.at(path);
|
|
9612
|
-
if (!found)
|
|
9828
|
+
if (!found) {
|
|
9829
|
+
const set2 = () => lutimesOf(this.base, path, atime, mtime);
|
|
9830
|
+
return this.based(
|
|
9831
|
+
[path],
|
|
9832
|
+
redirects,
|
|
9833
|
+
set2,
|
|
9834
|
+
([to], n) => this.lutimes(to, atime, mtime, n)
|
|
9835
|
+
);
|
|
9836
|
+
}
|
|
9613
9837
|
const real = normalizePath(path);
|
|
9614
9838
|
if (!found.mount.caps.linkTimes && (await this.lstat(real)).isSymbolicLink) {
|
|
9615
9839
|
throw errnoError("EOPNOTSUPP", path);
|
|
@@ -9828,7 +10052,8 @@ async function run(entry, path, req) {
|
|
|
9828
10052
|
function guardOf(entry) {
|
|
9829
10053
|
const cred = entry.dac && entry.cred?.();
|
|
9830
10054
|
if (!cred || !entry.dac) return void 0;
|
|
9831
|
-
|
|
10055
|
+
const links = entry.links === void 0 ? {} : { links: entry.links };
|
|
10056
|
+
return { fs: entry.fs, cred, pid: entry.pid ?? 0, dac: entry.dac, ...links };
|
|
9832
10057
|
}
|
|
9833
10058
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
9834
10059
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
@@ -9889,9 +10114,15 @@ async function holdOp(entry, path, req) {
|
|
|
9889
10114
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
9890
10115
|
return done;
|
|
9891
10116
|
}
|
|
10117
|
+
async function followed(g, path) {
|
|
10118
|
+
const st = await g.fs.lstat(path).catch(() => void 0);
|
|
10119
|
+
if (st?.isSymbolicLink && !trustedLink(permOf(st), g.links)) deny(g, "follow", path);
|
|
10120
|
+
return done;
|
|
10121
|
+
}
|
|
9892
10122
|
async function accessOp(entry, path, req) {
|
|
9893
10123
|
const g = guardOf(entry);
|
|
9894
10124
|
if (!g) return done;
|
|
10125
|
+
if (req.arg2 === "follow") return followed(g, path);
|
|
9895
10126
|
const open = req.arg2 === "open";
|
|
9896
10127
|
const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
|
|
9897
10128
|
const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
|
|
@@ -9914,15 +10145,18 @@ var CHANGING = /* @__PURE__ */ new Set([
|
|
|
9914
10145
|
"lchown"
|
|
9915
10146
|
]);
|
|
9916
10147
|
var CONTENT = /* @__PURE__ */ new Set(["write", "pwrite", "truncate"]);
|
|
10148
|
+
var REMOVING = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm", "rename"]);
|
|
9917
10149
|
async function mayChange(entry, path, req) {
|
|
9918
10150
|
const { mayChange: mayChange2 } = entry.fs;
|
|
9919
10151
|
if (!mayChange2) return;
|
|
9920
10152
|
const { op } = req;
|
|
9921
10153
|
if (CONTENT.has(op) && req.handle === void 0) return mayChange2.call(entry.fs, path, true);
|
|
9922
10154
|
if (!CHANGING.has(op)) return;
|
|
9923
|
-
|
|
10155
|
+
const follow2 = op === "utimes" || op === "chmod" || op === "chown";
|
|
10156
|
+
await mayChange2.call(entry.fs, path, follow2, REMOVING.has(op));
|
|
9924
10157
|
if (op === "rename" || op === "link") {
|
|
9925
|
-
|
|
10158
|
+
const to = entry.fs.resolvePath(entry.cwd, req.arg2 ?? "");
|
|
10159
|
+
await mayChange2.call(entry.fs, to, false, op === "rename");
|
|
9926
10160
|
}
|
|
9927
10161
|
}
|
|
9928
10162
|
async function guarded(entry, path, req) {
|
|
@@ -10615,7 +10849,7 @@ function mountTable(mounts = []) {
|
|
|
10615
10849
|
}
|
|
10616
10850
|
|
|
10617
10851
|
// src/version.ts
|
|
10618
|
-
var KERNEL_VERSION = true ? "1.
|
|
10852
|
+
var KERNEL_VERSION = true ? "1.89.0" : "0.0.0-dev";
|
|
10619
10853
|
var OS_RELEASE = "6.0.0-slicc";
|
|
10620
10854
|
function procVersion() {
|
|
10621
10855
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -12182,16 +12416,16 @@ function interruption(signal) {
|
|
|
12182
12416
|
}
|
|
12183
12417
|
async function selectFds(fds, read, write, timeoutMs, interrupt) {
|
|
12184
12418
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
12185
|
-
const
|
|
12186
|
-
|
|
12419
|
+
const interrupted3 = interruption(interrupt);
|
|
12420
|
+
interrupted3.promise.catch(() => {
|
|
12187
12421
|
});
|
|
12188
12422
|
try {
|
|
12189
|
-
return await waitReady(fds, read, write, deadline,
|
|
12423
|
+
return await waitReady(fds, read, write, deadline, interrupted3.promise);
|
|
12190
12424
|
} finally {
|
|
12191
|
-
|
|
12425
|
+
interrupted3.done();
|
|
12192
12426
|
}
|
|
12193
12427
|
}
|
|
12194
|
-
async function waitReady(fds, read, write, deadline,
|
|
12428
|
+
async function waitReady(fds, read, write, deadline, interrupted3) {
|
|
12195
12429
|
for (; ; ) {
|
|
12196
12430
|
const now = ready(fds, read, write);
|
|
12197
12431
|
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
@@ -12203,7 +12437,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
|
12203
12437
|
let timer;
|
|
12204
12438
|
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
12205
12439
|
try {
|
|
12206
|
-
await Promise.race([...changes, ...expiry,
|
|
12440
|
+
await Promise.race([...changes, ...expiry, interrupted3]);
|
|
12207
12441
|
} finally {
|
|
12208
12442
|
round.abort();
|
|
12209
12443
|
clearTimeout(timer);
|
|
@@ -13386,7 +13620,7 @@ var WasmProcess = class {
|
|
|
13386
13620
|
const { guard: guard2 } = this.options;
|
|
13387
13621
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
13388
13622
|
if (!guard2 || inherited2 || req.pin !== void 0) return;
|
|
13389
|
-
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13623
|
+
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13390
13624
|
if (req.exclusive) return inParent(g, "open", req.path);
|
|
13391
13625
|
if (req.created && guard2.created?.take(req.path)) return;
|
|
13392
13626
|
const access2 = req.flags & WRITE_ACCESS;
|
|
@@ -13442,7 +13676,7 @@ var WasmProcess = class {
|
|
|
13442
13676
|
}
|
|
13443
13677
|
guarded() {
|
|
13444
13678
|
const { guard: guard2 } = this.options;
|
|
13445
|
-
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13679
|
+
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13446
13680
|
}
|
|
13447
13681
|
ttyOwner() {
|
|
13448
13682
|
return { uid: this.cred.euid, gid: this.cred.egid, mode: TTY_MODE };
|
|
@@ -14168,6 +14402,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
14168
14402
|
umask,
|
|
14169
14403
|
cred,
|
|
14170
14404
|
...opts.owners ? { owners: true } : {},
|
|
14405
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
14171
14406
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
14172
14407
|
};
|
|
14173
14408
|
if (opts.program.abi === "js") {
|
|
@@ -14195,6 +14430,7 @@ function holdingToken(opts, holds, caller) {
|
|
|
14195
14430
|
return mintSyncFsToken({
|
|
14196
14431
|
...opts.owners ? caller : {},
|
|
14197
14432
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
14433
|
+
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
14198
14434
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
14199
14435
|
fs: opts.fs,
|
|
14200
14436
|
cwd: opts.cwd,
|
|
@@ -14208,6 +14444,9 @@ function holdingToken(opts, holds, caller) {
|
|
|
14208
14444
|
renamed: (from, to) => holds.renamed(from, to)
|
|
14209
14445
|
});
|
|
14210
14446
|
}
|
|
14447
|
+
function linksOf(opts) {
|
|
14448
|
+
return opts.links === void 0 ? {} : { links: opts.links };
|
|
14449
|
+
}
|
|
14211
14450
|
function clipboardName(opts) {
|
|
14212
14451
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
14213
14452
|
}
|
|
@@ -14219,7 +14458,7 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
14219
14458
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
14220
14459
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
14221
14460
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
14222
|
-
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
14461
|
+
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
14223
14462
|
...opts.identity ? { identity: opts.identity } : {},
|
|
14224
14463
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
14225
14464
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -14265,6 +14504,7 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
14265
14504
|
sab,
|
|
14266
14505
|
cred: copyCred(cred),
|
|
14267
14506
|
owners: opts.owners === true,
|
|
14507
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
14268
14508
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
14269
14509
|
thread,
|
|
14270
14510
|
signals: main
|
|
@@ -15132,63 +15372,137 @@ function compile(secrets, options = {}) {
|
|
|
15132
15372
|
|
|
15133
15373
|
// src/kernel/scrub-file.ts
|
|
15134
15374
|
var SCRUB_IDLE_MS = 50;
|
|
15375
|
+
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
15135
15376
|
var encoder5 = new TextEncoder();
|
|
15136
15377
|
function scrubberOf(secrets) {
|
|
15137
15378
|
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
15138
15379
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
15139
15380
|
}
|
|
15140
|
-
async function writeAll2(file, bytes
|
|
15381
|
+
async function writeAll2(file, bytes) {
|
|
15141
15382
|
const write = file.write;
|
|
15142
|
-
for (let at = 0; at < bytes.length; )
|
|
15143
|
-
at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
|
|
15144
|
-
}
|
|
15383
|
+
for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
|
|
15145
15384
|
}
|
|
15146
15385
|
function bound(file, key) {
|
|
15147
15386
|
const method = file[key];
|
|
15148
15387
|
return typeof method === "function" ? { [key]: method.bind(file) } : {};
|
|
15149
15388
|
}
|
|
15389
|
+
function interrupted2(err) {
|
|
15390
|
+
const code = err?.code;
|
|
15391
|
+
return code === "EINTR" || code === "EAGAIN";
|
|
15392
|
+
}
|
|
15150
15393
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
15151
15394
|
const file = inner.file;
|
|
15152
15395
|
const stream = scrubber.stream();
|
|
15153
|
-
let
|
|
15396
|
+
let tail = Promise.resolve();
|
|
15397
|
+
let pending = 0;
|
|
15398
|
+
let busy = false;
|
|
15154
15399
|
let timer;
|
|
15155
15400
|
let failed3;
|
|
15401
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
15402
|
+
const quiet = () => !busy && pending === 0;
|
|
15403
|
+
const wake = () => {
|
|
15404
|
+
for (const waiter of [...waiters]) waiter();
|
|
15405
|
+
};
|
|
15156
15406
|
const raise = () => {
|
|
15157
15407
|
if (failed3 === void 0) return;
|
|
15158
15408
|
const err = failed3;
|
|
15159
15409
|
failed3 = void 0;
|
|
15160
15410
|
throw err;
|
|
15161
15411
|
};
|
|
15162
|
-
const
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15412
|
+
const later = (bytes) => {
|
|
15413
|
+
if (bytes.length === 0) return;
|
|
15414
|
+
pending += 1;
|
|
15415
|
+
tail = tail.then(() => writeAll2(file, bytes)).catch((err) => {
|
|
15416
|
+
if (failed3 === void 0) failed3 = err;
|
|
15417
|
+
}).finally(() => {
|
|
15418
|
+
pending -= 1;
|
|
15419
|
+
if (quiet()) wake();
|
|
15420
|
+
});
|
|
15421
|
+
};
|
|
15422
|
+
const settling = (signal) => new Promise((resolve2, reject) => {
|
|
15423
|
+
const done4 = () => {
|
|
15424
|
+
waiters.delete(done4);
|
|
15425
|
+
signal?.removeEventListener("abort", stop);
|
|
15426
|
+
resolve2();
|
|
15427
|
+
};
|
|
15428
|
+
const stop = () => {
|
|
15429
|
+
waiters.delete(done4);
|
|
15430
|
+
reject(new KernelError("EINTR"));
|
|
15431
|
+
};
|
|
15432
|
+
if (signal?.aborted) return stop();
|
|
15433
|
+
waiters.add(done4);
|
|
15434
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
15435
|
+
});
|
|
15436
|
+
const settled = async () => {
|
|
15437
|
+
while (!quiet()) await settling();
|
|
15438
|
+
};
|
|
15439
|
+
const changed = async (signal) => {
|
|
15440
|
+
const round = new AbortController();
|
|
15441
|
+
const stop = signal ? AbortSignal.any([signal, round.signal]) : round.signal;
|
|
15442
|
+
try {
|
|
15443
|
+
const own = settling(stop);
|
|
15444
|
+
await Promise.race(file.changed ? [own, file.changed(stop)] : [own]);
|
|
15445
|
+
} catch (err) {
|
|
15446
|
+
throw signal?.aborted ? new KernelError("EINTR") : err;
|
|
15447
|
+
} finally {
|
|
15448
|
+
round.abort();
|
|
15449
|
+
}
|
|
15450
|
+
};
|
|
15451
|
+
const turn = async (signal) => {
|
|
15452
|
+
for (let waited = false; ; waited = true) {
|
|
15453
|
+
if (quiet() && (pollFile(file).writable || !file.changed)) {
|
|
15454
|
+
busy = true;
|
|
15455
|
+
return;
|
|
15456
|
+
}
|
|
15457
|
+
if (signal?.aborted) throw new KernelError(waited ? "EINTR" : "EAGAIN");
|
|
15458
|
+
await changed(signal);
|
|
15459
|
+
}
|
|
15460
|
+
};
|
|
15461
|
+
const send = async (out, signal) => {
|
|
15462
|
+
const write = file.write;
|
|
15463
|
+
for (let at = 0; at < out.length; ) {
|
|
15464
|
+
try {
|
|
15465
|
+
at += await write.call(file, out.subarray(at), signal);
|
|
15466
|
+
} catch (err) {
|
|
15467
|
+
if (!signal?.aborted || !interrupted2(err)) throw err;
|
|
15468
|
+
}
|
|
15469
|
+
if (at < out.length && signal?.aborted) return later(out.subarray(at));
|
|
15470
|
+
}
|
|
15166
15471
|
};
|
|
15167
15472
|
const release = () => {
|
|
15168
15473
|
timer = void 0;
|
|
15169
|
-
|
|
15170
|
-
failed3 = err;
|
|
15171
|
-
});
|
|
15474
|
+
later(stream.idle());
|
|
15172
15475
|
};
|
|
15173
15476
|
return new OpenFile({
|
|
15174
15477
|
...bound(file, "read"),
|
|
15175
15478
|
...bound(file, "peek"),
|
|
15176
|
-
...bound(file, "poll"),
|
|
15177
|
-
...bound(file, "changed"),
|
|
15178
15479
|
...bound(file, "stat"),
|
|
15480
|
+
poll: () => {
|
|
15481
|
+
const state = pollFile(file);
|
|
15482
|
+
return quiet() ? state : { ...state, writable: false };
|
|
15483
|
+
},
|
|
15484
|
+
changed,
|
|
15179
15485
|
...file.tty ? { tty: file.tty } : {},
|
|
15180
15486
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
15181
15487
|
...file.write ? {
|
|
15182
15488
|
write: async (bytes, signal) => {
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15489
|
+
await turn(signal);
|
|
15490
|
+
const taken = signal?.aborted && bytes.length > SCRUB_NONBLOCK_MAX ? bytes.subarray(0, SCRUB_NONBLOCK_MAX) : bytes;
|
|
15491
|
+
try {
|
|
15492
|
+
raise();
|
|
15493
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
15494
|
+
timer = void 0;
|
|
15495
|
+
await send(stream.push(taken), signal);
|
|
15496
|
+
} finally {
|
|
15497
|
+
busy = false;
|
|
15498
|
+
if (quiet()) wake();
|
|
15499
|
+
}
|
|
15186
15500
|
timer = setTimeout(release, idleMs);
|
|
15187
|
-
return
|
|
15501
|
+
return taken.length;
|
|
15188
15502
|
}
|
|
15189
15503
|
} : {},
|
|
15190
15504
|
flush: async () => {
|
|
15191
|
-
await
|
|
15505
|
+
await settled();
|
|
15192
15506
|
raise();
|
|
15193
15507
|
await file.flush?.();
|
|
15194
15508
|
},
|
|
@@ -15196,7 +15510,9 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15196
15510
|
if (timer !== void 0) clearTimeout(timer);
|
|
15197
15511
|
let failure2;
|
|
15198
15512
|
try {
|
|
15199
|
-
await
|
|
15513
|
+
await settled();
|
|
15514
|
+
later(stream.end());
|
|
15515
|
+
await settled();
|
|
15200
15516
|
raise();
|
|
15201
15517
|
} catch (err) {
|
|
15202
15518
|
failure2 = { err };
|
|
@@ -15372,12 +15688,12 @@ var SealedChannel = class {
|
|
|
15372
15688
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
15373
15689
|
let stop = () => {
|
|
15374
15690
|
};
|
|
15375
|
-
const
|
|
15691
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
15376
15692
|
stop = () => reject(new KernelError("EINTR"));
|
|
15377
15693
|
signal.addEventListener("abort", stop, { once: true });
|
|
15378
15694
|
});
|
|
15379
15695
|
try {
|
|
15380
|
-
await Promise.race([flight.done,
|
|
15696
|
+
await Promise.race([flight.done, interrupted3]);
|
|
15381
15697
|
} finally {
|
|
15382
15698
|
signal.removeEventListener("abort", stop);
|
|
15383
15699
|
}
|
|
@@ -17489,6 +17805,9 @@ var SUDO_SOURCE = [
|
|
|
17489
17805
|
].join("\n");
|
|
17490
17806
|
|
|
17491
17807
|
// src/launcher.ts
|
|
17808
|
+
function linksOf2(req) {
|
|
17809
|
+
return req.links === void 0 ? {} : { links: req.links };
|
|
17810
|
+
}
|
|
17492
17811
|
var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
17493
17812
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
17494
17813
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
@@ -17664,6 +17983,7 @@ var Launcher = class {
|
|
|
17664
17983
|
warned = /* @__PURE__ */ new Set();
|
|
17665
17984
|
compiled = /* @__PURE__ */ new Map();
|
|
17666
17985
|
texts = /* @__PURE__ */ new Map();
|
|
17986
|
+
revocations = 0;
|
|
17667
17987
|
integrity;
|
|
17668
17988
|
scannedFs;
|
|
17669
17989
|
get scanned() {
|
|
@@ -17676,6 +17996,7 @@ var Launcher = class {
|
|
|
17676
17996
|
described = /* @__PURE__ */ new Map();
|
|
17677
17997
|
creds = /* @__PURE__ */ new Map();
|
|
17678
17998
|
tags = /* @__PURE__ */ new Map();
|
|
17999
|
+
links = /* @__PURE__ */ new Map();
|
|
17679
18000
|
freshModules = new FreshModules();
|
|
17680
18001
|
granted = /* @__PURE__ */ new Map();
|
|
17681
18002
|
users;
|
|
@@ -17978,14 +18299,16 @@ var Launcher = class {
|
|
|
17978
18299
|
}
|
|
17979
18300
|
const path = this.fs.resolvePath(cwd, file);
|
|
17980
18301
|
const glue = await followLinks(this.base, path);
|
|
17981
|
-
const
|
|
17982
|
-
|
|
17983
|
-
|
|
17984
|
-
const
|
|
18302
|
+
const asked = glue === path ? {} : { asked: path };
|
|
18303
|
+
const linked2 = COMMAND2.exec(glue)?.[1];
|
|
18304
|
+
if (linked2 !== void 0) {
|
|
18305
|
+
const found = await this.resolve(`/bin/${linked2}`, argv0, cwd);
|
|
18306
|
+
const target = found && { ...found, ...asked };
|
|
18307
|
+
const byPath = !COMMAND2.test(path) && (await this.commands()).get(linked2)?.argv0Path === true;
|
|
17985
18308
|
return target && byPath ? { ...target, argv0: path } : target;
|
|
17986
18309
|
}
|
|
17987
18310
|
const own = await this.commandAt(glue, scope);
|
|
17988
|
-
if (own) return own.script ? void 0 : targetOf(own);
|
|
18311
|
+
if (own) return own.script ? void 0 : { ...targetOf(own), ...asked };
|
|
17989
18312
|
const head = await this.head(glue);
|
|
17990
18313
|
if (!head) return void 0;
|
|
17991
18314
|
if (isWasm(head)) {
|
|
@@ -17993,13 +18316,14 @@ var Launcher = class {
|
|
|
17993
18316
|
abi: "wasi",
|
|
17994
18317
|
glue,
|
|
17995
18318
|
wasm: glue,
|
|
17996
|
-
argv0: baseName(argv0 || file).replace(/\.wasm$/, "")
|
|
18319
|
+
argv0: baseName(argv0 || file).replace(/\.wasm$/, ""),
|
|
18320
|
+
...asked
|
|
17997
18321
|
};
|
|
17998
18322
|
}
|
|
17999
18323
|
if (interpreter(head) !== "node") return void 0;
|
|
18000
18324
|
const wasm = modulePath(glue);
|
|
18001
18325
|
if (!await this.base.exists(wasm)) return void 0;
|
|
18002
|
-
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file) };
|
|
18326
|
+
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file), ...asked };
|
|
18003
18327
|
}
|
|
18004
18328
|
async head(path) {
|
|
18005
18329
|
try {
|
|
@@ -18017,6 +18341,8 @@ var Launcher = class {
|
|
|
18017
18341
|
async interpreted(file, argv, cwd, scope, depth = 0) {
|
|
18018
18342
|
const command = await this.scriptCommand(file, cwd, scope);
|
|
18019
18343
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
18344
|
+
const byPath = command && file.includes("/") && !COMMAND2.test(file);
|
|
18345
|
+
const named = byPath ? { [script]: this.fs.resolvePath(cwd, file) } : {};
|
|
18020
18346
|
const head = await this.head(script);
|
|
18021
18347
|
if (!head) return void 0;
|
|
18022
18348
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
@@ -18039,7 +18365,8 @@ var Launcher = class {
|
|
|
18039
18365
|
target: withScriptEnv(inner.target, command),
|
|
18040
18366
|
via,
|
|
18041
18367
|
sources,
|
|
18042
|
-
...bins.length > 0 ? { bins } : {}
|
|
18368
|
+
...bins.length > 0 ? { bins } : {},
|
|
18369
|
+
asked: { ...inner.asked, ...named }
|
|
18043
18370
|
};
|
|
18044
18371
|
}
|
|
18045
18372
|
const target = withScriptEnv(found, command);
|
|
@@ -18048,7 +18375,8 @@ var Launcher = class {
|
|
|
18048
18375
|
args: [...target.prefix ?? [], ...passed],
|
|
18049
18376
|
via: [interp],
|
|
18050
18377
|
sources: [script],
|
|
18051
|
-
...command?.bin ? { bins: [script] } : {}
|
|
18378
|
+
...command?.bin ? { bins: [script] } : {},
|
|
18379
|
+
asked: named
|
|
18052
18380
|
};
|
|
18053
18381
|
}
|
|
18054
18382
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -18062,7 +18390,14 @@ var Launcher = class {
|
|
|
18062
18390
|
async mayExec(cred, req, planned) {
|
|
18063
18391
|
const { dac } = this;
|
|
18064
18392
|
if (!dac) return;
|
|
18065
|
-
const g = {
|
|
18393
|
+
const g = {
|
|
18394
|
+
fs: this.fs,
|
|
18395
|
+
cred,
|
|
18396
|
+
pid: req.pid,
|
|
18397
|
+
dac,
|
|
18398
|
+
tag: req.tag,
|
|
18399
|
+
links: this.links.get(req.pid)
|
|
18400
|
+
};
|
|
18066
18401
|
const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
|
|
18067
18402
|
if (byPath(req.file)) {
|
|
18068
18403
|
const path = this.fs.resolvePath(req.cwd, req.file);
|
|
@@ -18219,8 +18554,8 @@ var Launcher = class {
|
|
|
18219
18554
|
readFile: (path) => this.integrity ? this.text(path, KERNEL_CALLER) : fs.readFile(path)
|
|
18220
18555
|
});
|
|
18221
18556
|
}
|
|
18222
|
-
async cacheKey(path) {
|
|
18223
|
-
const verified = await this.integrity?.key(path);
|
|
18557
|
+
async cacheKey(path, asked) {
|
|
18558
|
+
const verified = await this.integrity?.key(path, asked);
|
|
18224
18559
|
if (verified !== void 0) return verified;
|
|
18225
18560
|
const st = await this.base.stat(path);
|
|
18226
18561
|
return `${path}:${st.size}:${st.mtime.getTime()}`;
|
|
@@ -18229,30 +18564,31 @@ var Launcher = class {
|
|
|
18229
18564
|
const plain = () => fs.readFileBuffer(path);
|
|
18230
18565
|
return this.integrity ? this.integrity.read(path, caller, plain) : plain();
|
|
18231
18566
|
}
|
|
18232
|
-
keyed(path, caller) {
|
|
18567
|
+
keyed(path, caller, asked) {
|
|
18233
18568
|
const plain = async () => this.base.readFileBuffer(path);
|
|
18234
|
-
return this.integrity ? this.integrity.readKeyed(path, caller, plain) : plain().then((bytes) => ({ bytes }));
|
|
18569
|
+
return this.integrity ? this.integrity.readKeyed(path, caller, plain, asked) : plain().then((bytes) => ({ bytes }));
|
|
18235
18570
|
}
|
|
18236
18571
|
cached(cache, key, load) {
|
|
18237
18572
|
const hit = cache.get(key);
|
|
18238
18573
|
if (hit !== void 0) return hit;
|
|
18574
|
+
const revocations = this.revocations;
|
|
18239
18575
|
const loading2 = load();
|
|
18240
18576
|
const found = loading2.then(({ value }) => value);
|
|
18241
18577
|
cache.set(key, found);
|
|
18242
|
-
|
|
18243
|
-
(
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
()
|
|
18249
|
-
);
|
|
18578
|
+
const drop = () => {
|
|
18579
|
+
if (cache.get(key) === found) cache.delete(key);
|
|
18580
|
+
};
|
|
18581
|
+
loading2.then((done4) => {
|
|
18582
|
+
if (done4.key === key || done4.key === void 0 && !key.includes("\0")) return;
|
|
18583
|
+
drop();
|
|
18584
|
+
if (done4.key !== void 0 && revocations === this.revocations) cache.set(done4.key, found);
|
|
18585
|
+
}, drop);
|
|
18250
18586
|
return found;
|
|
18251
18587
|
}
|
|
18252
|
-
async module(path, caller) {
|
|
18253
|
-
const key = await this.cacheKey(path);
|
|
18588
|
+
async module(path, caller, asked) {
|
|
18589
|
+
const key = await this.cacheKey(path, asked);
|
|
18254
18590
|
return this.cached(this.compiled, key, async () => {
|
|
18255
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18591
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18256
18592
|
const memory = importedMemory(bytes);
|
|
18257
18593
|
const foreign = foreignImports(bytes);
|
|
18258
18594
|
const compiled = await WebAssembly.compile(bytes);
|
|
@@ -18261,22 +18597,30 @@ var Launcher = class {
|
|
|
18261
18597
|
}
|
|
18262
18598
|
async checkedSources(planned, caller) {
|
|
18263
18599
|
const { target } = planned;
|
|
18264
|
-
const files = [
|
|
18600
|
+
const files = [
|
|
18601
|
+
target.wasm,
|
|
18602
|
+
target.glue,
|
|
18603
|
+
target.imports,
|
|
18604
|
+
target.asked,
|
|
18605
|
+
...planned.sources ?? []
|
|
18606
|
+
];
|
|
18265
18607
|
const manifests = /* @__PURE__ */ new Set();
|
|
18266
18608
|
for (const file of files) {
|
|
18267
18609
|
const root = file === void 0 ? void 0 : PACKAGE_ROOT.exec(file)?.[1];
|
|
18268
18610
|
if (root !== void 0) manifests.add(`${root}/package.json`);
|
|
18269
18611
|
}
|
|
18270
|
-
for (const source of planned.sources ?? [])
|
|
18612
|
+
for (const source of planned.sources ?? []) {
|
|
18613
|
+
await this.text(source, caller, planned.asked?.[source]);
|
|
18614
|
+
}
|
|
18271
18615
|
for (const manifest of manifests) {
|
|
18272
18616
|
if (await this.base.exists(manifest)) await this.text(manifest, caller);
|
|
18273
18617
|
}
|
|
18274
18618
|
}
|
|
18275
|
-
async text(path, caller) {
|
|
18619
|
+
async text(path, caller, asked) {
|
|
18276
18620
|
if (!this.integrity) return this.base.readFile(path);
|
|
18277
|
-
const key = await this.cacheKey(path);
|
|
18621
|
+
const key = await this.cacheKey(path, asked);
|
|
18278
18622
|
return this.cached(this.texts, key, async () => {
|
|
18279
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18623
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18280
18624
|
return { value: new TextDecoder().decode(bytes), key: read };
|
|
18281
18625
|
});
|
|
18282
18626
|
}
|
|
@@ -18293,17 +18637,18 @@ var Launcher = class {
|
|
|
18293
18637
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
18294
18638
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
18295
18639
|
}
|
|
18640
|
+
const { asked } = target;
|
|
18296
18641
|
if (target.abi === "js") {
|
|
18297
|
-
return { abi: "js", glue: await this.text(target.wasm, caller), path: target.wasm };
|
|
18642
|
+
return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
|
|
18298
18643
|
}
|
|
18299
18644
|
if (target.abi !== "wasi") {
|
|
18300
18645
|
const [glue, { module: module2 }] = await Promise.all([
|
|
18301
|
-
this.text(target.glue, caller),
|
|
18302
|
-
this.module(target.wasm, caller)
|
|
18646
|
+
this.text(target.glue, caller, asked),
|
|
18647
|
+
this.module(target.wasm, caller, asked && modulePath(asked))
|
|
18303
18648
|
]);
|
|
18304
18649
|
return { glue, module: module2 };
|
|
18305
18650
|
}
|
|
18306
|
-
const { module, memory, foreign } = await this.module(target.wasm, caller);
|
|
18651
|
+
const { module, memory, foreign } = await this.module(target.wasm, caller, asked);
|
|
18307
18652
|
const names = env.SLICC_WASM_BACKTRACE === "1" ? await this.names(target.wasm, module) : void 0;
|
|
18308
18653
|
const imports = target.imports ? await this.text(target.imports, caller) : void 0;
|
|
18309
18654
|
return {
|
|
@@ -18340,11 +18685,13 @@ var Launcher = class {
|
|
|
18340
18685
|
groupSession(pgid) {
|
|
18341
18686
|
return this.jobs.sessionOf(pgid);
|
|
18342
18687
|
}
|
|
18343
|
-
treeScrubs(
|
|
18688
|
+
treeScrubs(req) {
|
|
18344
18689
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18345
|
-
|
|
18346
|
-
|
|
18347
|
-
|
|
18690
|
+
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
18691
|
+
}
|
|
18692
|
+
marks(pid, req) {
|
|
18693
|
+
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
18694
|
+
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
18348
18695
|
}
|
|
18349
18696
|
start(req) {
|
|
18350
18697
|
this.sampling();
|
|
@@ -18352,7 +18699,7 @@ var Launcher = class {
|
|
|
18352
18699
|
throw new SpawnError("ESRCH");
|
|
18353
18700
|
}
|
|
18354
18701
|
const pid = req.pid ?? this.nextPid++;
|
|
18355
|
-
const scrubs = this.treeScrubs(
|
|
18702
|
+
const scrubs = this.treeScrubs(req);
|
|
18356
18703
|
const stack = this.stackFor(req.tag);
|
|
18357
18704
|
const terminal = req.fds.stdioTerminal();
|
|
18358
18705
|
const decided = req.decided ?? Promise.resolve(true);
|
|
@@ -18378,6 +18725,7 @@ var Launcher = class {
|
|
|
18378
18725
|
cred: req.cred,
|
|
18379
18726
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
18380
18727
|
...this.owners ? { owners: true } : {},
|
|
18728
|
+
...linksOf2(req),
|
|
18381
18729
|
sealed: this.sealed,
|
|
18382
18730
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
18383
18731
|
clipboard: this.clipboard,
|
|
@@ -18422,9 +18770,10 @@ var Launcher = class {
|
|
|
18422
18770
|
...this.shownIds(req)
|
|
18423
18771
|
});
|
|
18424
18772
|
this.processes.set(pid, handle);
|
|
18773
|
+
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18425
18774
|
const { cred } = req;
|
|
18426
18775
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
18427
|
-
|
|
18776
|
+
this.marks(pid, req);
|
|
18428
18777
|
if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
|
|
18429
18778
|
this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
|
|
18430
18779
|
if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
|
|
@@ -18477,6 +18826,7 @@ var Launcher = class {
|
|
|
18477
18826
|
this.childTimes.delete(pid);
|
|
18478
18827
|
this.creds.delete(pid);
|
|
18479
18828
|
this.tags.delete(pid);
|
|
18829
|
+
this.links.delete(pid);
|
|
18480
18830
|
this.granted.delete(pid);
|
|
18481
18831
|
}
|
|
18482
18832
|
reaped(pid, parent) {
|
|
@@ -18652,6 +19002,7 @@ var Launcher = class {
|
|
|
18652
19002
|
umask: this.umaskOf(ppid),
|
|
18653
19003
|
cred,
|
|
18654
19004
|
tag: this.tagOf(ppid),
|
|
19005
|
+
links: grant ? grant.cred.euid : this.links.get(ppid),
|
|
18655
19006
|
...group,
|
|
18656
19007
|
...exec
|
|
18657
19008
|
});
|
|
@@ -18713,7 +19064,8 @@ var Launcher = class {
|
|
|
18713
19064
|
blocked: this.blockedBy(ppid),
|
|
18714
19065
|
umask: this.umaskOf(ppid),
|
|
18715
19066
|
cred: this.credOf(ppid),
|
|
18716
|
-
tag: this.tagOf(ppid)
|
|
19067
|
+
tag: this.tagOf(ppid),
|
|
19068
|
+
links: this.links.get(ppid)
|
|
18717
19069
|
})
|
|
18718
19070
|
);
|
|
18719
19071
|
}
|
|
@@ -18893,6 +19245,23 @@ var Launcher = class {
|
|
|
18893
19245
|
}
|
|
18894
19246
|
};
|
|
18895
19247
|
}
|
|
19248
|
+
async revokeIntegrity(path) {
|
|
19249
|
+
if (path !== void 0 && (typeof path !== "string" || !path.startsWith("/"))) {
|
|
19250
|
+
throw new TypeError("integrity.revoke takes an absolute path");
|
|
19251
|
+
}
|
|
19252
|
+
if (!this.integrity) return;
|
|
19253
|
+
const at = path === void 0 ? void 0 : normalizePath(path);
|
|
19254
|
+
const real = at && await this.base.realpath?.(at, true).catch(() => void 0);
|
|
19255
|
+
const roots = [at, real].filter((p) => p !== void 0);
|
|
19256
|
+
this.revocations++;
|
|
19257
|
+
const hit = (key) => key.includes("\0") && (at === void 0 || key.split("\0").slice(0, 2).some((part) => isProtected(roots, part)));
|
|
19258
|
+
for (const cache of [this.compiled, this.texts]) {
|
|
19259
|
+
for (const key of [...cache.keys()]) if (hit(key)) cache.delete(key);
|
|
19260
|
+
}
|
|
19261
|
+
if (at === void 0) this.integrity.forget();
|
|
19262
|
+
for (const root of roots) this.integrity.forget(root);
|
|
19263
|
+
this.resetCatalogs();
|
|
19264
|
+
}
|
|
18896
19265
|
attest(path) {
|
|
18897
19266
|
return attest(this.rootFs, path, {
|
|
18898
19267
|
users: this.usersMode,
|
|
@@ -19390,7 +19759,8 @@ var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
|
19390
19759
|
"attest",
|
|
19391
19760
|
"watch-files",
|
|
19392
19761
|
"unwatch-files",
|
|
19393
|
-
"chmod"
|
|
19762
|
+
"chmod",
|
|
19763
|
+
"integrity-revoke"
|
|
19394
19764
|
]);
|
|
19395
19765
|
function isAttestRequest(req) {
|
|
19396
19766
|
return ATTEST_OPS.has(req.op);
|
|
@@ -19408,6 +19778,7 @@ function attestOps(port) {
|
|
|
19408
19778
|
return async (l, req) => {
|
|
19409
19779
|
if (req.op === "attest") return l.attest(req.path);
|
|
19410
19780
|
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
19781
|
+
if (req.op === "integrity-revoke") return l.revokeIntegrity(req.path).then(() => true);
|
|
19411
19782
|
if (req.op === "unwatch-files") {
|
|
19412
19783
|
watches.get(req.watch)?.();
|
|
19413
19784
|
return watches.delete(req.watch);
|