@ai-ecoverse/slicc-kernel 1.88.1 → 1.90.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 +47 -11
- package/dist/driver-worker.js +89 -1
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +138 -5
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +705 -149
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js.map +2 -2
- package/dist/node-driver-worker.js +89 -1
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.js +5584 -5259
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +4604 -3976
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +377 -52
- 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);
|
|
@@ -2015,7 +2052,7 @@ function portCdpHook(ask, gone) {
|
|
|
2015
2052
|
}
|
|
2016
2053
|
|
|
2017
2054
|
// src/client/protocol.ts
|
|
2018
|
-
var PROTOCOL = [1,
|
|
2055
|
+
var PROTOCOL = [1, 11];
|
|
2019
2056
|
var FS_METHODS = [
|
|
2020
2057
|
"readFile",
|
|
2021
2058
|
"writeFile",
|
|
@@ -2046,6 +2083,52 @@ function fresh(bytes, start2 = 0, end = bytes.length) {
|
|
|
2046
2083
|
return new Uint8Array(bytes.subarray(start2, end));
|
|
2047
2084
|
}
|
|
2048
2085
|
|
|
2086
|
+
// src/facade/port.ts
|
|
2087
|
+
var FACADE_GONE = "the facade host is gone";
|
|
2088
|
+
function portFacadeHook(ask, gone) {
|
|
2089
|
+
return (stamp, { name: name2 }) => new Promise((resolve2, reject) => {
|
|
2090
|
+
const { port1, port2 } = new MessageChannel();
|
|
2091
|
+
let closed = false;
|
|
2092
|
+
const shut = () => {
|
|
2093
|
+
closed = true;
|
|
2094
|
+
port1.close();
|
|
2095
|
+
};
|
|
2096
|
+
const conn = {
|
|
2097
|
+
send: (bytes) => {
|
|
2098
|
+
if (closed) return;
|
|
2099
|
+
const copy = bytes.slice();
|
|
2100
|
+
port1.postMessage({ b: copy }, [copy.buffer]);
|
|
2101
|
+
},
|
|
2102
|
+
onmessage: null,
|
|
2103
|
+
onclose: null,
|
|
2104
|
+
close: (reason) => {
|
|
2105
|
+
if (closed) return;
|
|
2106
|
+
port1.postMessage({ close: reason ?? true });
|
|
2107
|
+
shut();
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
port1.addEventListener("message", ({ data }) => {
|
|
2111
|
+
if ("b" in data) conn.onmessage?.(data.b);
|
|
2112
|
+
else if ("open" in data) resolve2(conn);
|
|
2113
|
+
else if ("error" in data) {
|
|
2114
|
+
shut();
|
|
2115
|
+
reject(new Error(data.error));
|
|
2116
|
+
} else if (!closed) {
|
|
2117
|
+
shut();
|
|
2118
|
+
conn.onclose?.();
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
port1.start();
|
|
2122
|
+
void gone?.then(() => {
|
|
2123
|
+
if (closed) return;
|
|
2124
|
+
shut();
|
|
2125
|
+
reject(new Error(FACADE_GONE));
|
|
2126
|
+
conn.onclose?.(FACADE_GONE);
|
|
2127
|
+
});
|
|
2128
|
+
ask({ name: name2, stamp }, port2);
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2049
2132
|
// src/fs/walk.ts
|
|
2050
2133
|
var MAX_LINKS3 = 40;
|
|
2051
2134
|
function parentOf4(path) {
|
|
@@ -2159,7 +2242,10 @@ var Perms = class {
|
|
|
2159
2242
|
function parts(path) {
|
|
2160
2243
|
return path.split("/").filter((part) => part !== "" && part !== ".");
|
|
2161
2244
|
}
|
|
2162
|
-
|
|
2245
|
+
function trustedLink(perm, links) {
|
|
2246
|
+
return links === void 0 || perm.uid === 0 || perm.uid === links;
|
|
2247
|
+
}
|
|
2248
|
+
async function walk(fs, cred, path, follow2, links) {
|
|
2163
2249
|
const perms = new Perms(fs);
|
|
2164
2250
|
await perms.learn(path);
|
|
2165
2251
|
const queue = parts(path);
|
|
@@ -2177,6 +2263,7 @@ async function walk(fs, cred, path, follow2) {
|
|
|
2177
2263
|
const perm = await perms.at(next2);
|
|
2178
2264
|
const last = queue.length === 0;
|
|
2179
2265
|
if (perm?.link !== void 0 && (!last || follow2)) {
|
|
2266
|
+
if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next2, link: true };
|
|
2180
2267
|
if (++hops > MAX_LINKS4) return { path: next2, perm: void 0 };
|
|
2181
2268
|
queue.unshift(...parts(perm.link));
|
|
2182
2269
|
if (perm.link.startsWith("/")) at = "/";
|
|
@@ -2201,9 +2288,9 @@ async function finalOf(fs, walked, want, options) {
|
|
|
2201
2288
|
return st ? [permOf(st), st.isDirectory] : [perm, false];
|
|
2202
2289
|
}
|
|
2203
2290
|
async function access(fs, cred, path, want, options = {}) {
|
|
2204
|
-
const walked = await walk(fs, cred, path, options.follow !== false);
|
|
2291
|
+
const walked = await walk(fs, cred, path, options.follow !== false, options.links);
|
|
2205
2292
|
if (walked.denied !== void 0) {
|
|
2206
|
-
if (await present(fs, walked.denied, true)) return walked;
|
|
2293
|
+
if (walked.link || await present(fs, walked.denied, true)) return walked;
|
|
2207
2294
|
return { path, perm: void 0, missing: true };
|
|
2208
2295
|
}
|
|
2209
2296
|
if (!walked.perm) return { ...walked, missing: true };
|
|
@@ -2270,6 +2357,9 @@ var Created = class {
|
|
|
2270
2357
|
return this.paths.delete(normalizePath(path));
|
|
2271
2358
|
}
|
|
2272
2359
|
};
|
|
2360
|
+
function linked(g, options) {
|
|
2361
|
+
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
2362
|
+
}
|
|
2273
2363
|
function deny(g, op, path, errno = "EACCES") {
|
|
2274
2364
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
2275
2365
|
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno, ...tag });
|
|
@@ -2280,8 +2370,8 @@ function ttyOpenable(g, tty) {
|
|
|
2280
2370
|
deny(g, "open", tty.name ?? "/dev/tty");
|
|
2281
2371
|
}
|
|
2282
2372
|
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);
|
|
2373
|
+
const walked = await access(g.fs, g.cred, path, want, linked(g, options));
|
|
2374
|
+
if (walked.denied !== void 0) deny(g, op, walked.link ? walked.denied : shown);
|
|
2285
2375
|
return walked;
|
|
2286
2376
|
}
|
|
2287
2377
|
function entryIn(dir, path) {
|
|
@@ -2300,14 +2390,16 @@ async function inParent(g, op, path, old = false) {
|
|
|
2300
2390
|
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
2301
2391
|
}
|
|
2302
2392
|
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);
|
|
2393
|
+
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, linked(g, DIR));
|
|
2304
2394
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
2395
|
+
if (dir.link) return deny(g, op, dir.denied);
|
|
2305
2396
|
const lookup = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
2306
2397
|
if (!lookup || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
2307
2398
|
}
|
|
2308
2399
|
async function makeIn(g, op, path) {
|
|
2309
2400
|
for (let dir = parentOf4(path); ; dir = parentOf4(dir)) {
|
|
2310
|
-
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
|
|
2401
|
+
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
2402
|
+
if (walked.link) return deny(g, op, walked.denied);
|
|
2311
2403
|
if (walked.denied !== void 0) {
|
|
2312
2404
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
2313
2405
|
return;
|
|
@@ -3091,6 +3183,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
3091
3183
|
local;
|
|
3092
3184
|
peer;
|
|
3093
3185
|
peerCred;
|
|
3186
|
+
peerStamp;
|
|
3094
3187
|
listenerCred;
|
|
3095
3188
|
link;
|
|
3096
3189
|
readShut = false;
|
|
@@ -3161,10 +3254,10 @@ var KernelSocket = class _KernelSocket {
|
|
|
3161
3254
|
for (const wait2 of waits) wait2.catch(() => void 0);
|
|
3162
3255
|
return pipeCall(() => Promise.race(waits));
|
|
3163
3256
|
}
|
|
3164
|
-
bind(addr) {
|
|
3257
|
+
bind(addr, kernel = false) {
|
|
3165
3258
|
if (this.state !== "open" || this.local) throw new KernelError("EINVAL");
|
|
3166
3259
|
if (addr.family !== this.domain) throw new KernelError("EAFNOSUPPORT");
|
|
3167
|
-
this.local = this.net.bind(this, addr);
|
|
3260
|
+
this.local = this.net.bind(this, addr, kernel);
|
|
3168
3261
|
this.boundAt = this.local;
|
|
3169
3262
|
}
|
|
3170
3263
|
listen(backlog, cred) {
|
|
@@ -3193,7 +3286,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
3193
3286
|
this.changes.wake();
|
|
3194
3287
|
return true;
|
|
3195
3288
|
}
|
|
3196
|
-
connect(addr, viaUplink = true, cred) {
|
|
3289
|
+
connect(addr, viaUplink = true, cred, stamp) {
|
|
3197
3290
|
if (this.state === "connected") throw new KernelError("EISCONN");
|
|
3198
3291
|
if (this.state === "connecting") throw new KernelError("EALREADY");
|
|
3199
3292
|
if (this.state !== "open") throw new KernelError("EINVAL");
|
|
@@ -3212,6 +3305,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
3212
3305
|
server.local = addr.family === "inet" ? { ...addr, host: canonicalHost(addr.host) } : addr;
|
|
3213
3306
|
server.peer = this.local;
|
|
3214
3307
|
server.peerCred = cred;
|
|
3308
|
+
server.peerStamp = stamp;
|
|
3215
3309
|
this.peer = server.local;
|
|
3216
3310
|
this.peerCred = target.listenerCred;
|
|
3217
3311
|
link(this, server);
|
|
@@ -3352,6 +3446,8 @@ var LoopbackNet = class {
|
|
|
3352
3446
|
bound = /* @__PURE__ */ new Map();
|
|
3353
3447
|
activators = /* @__PURE__ */ new Map();
|
|
3354
3448
|
internal = /* @__PURE__ */ new Set();
|
|
3449
|
+
reserved = /* @__PURE__ */ new Set();
|
|
3450
|
+
facades = /* @__PURE__ */ new Map();
|
|
3355
3451
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
3356
3452
|
route;
|
|
3357
3453
|
useUplink(route) {
|
|
@@ -3366,6 +3462,18 @@ var LoopbackNet = class {
|
|
|
3366
3462
|
if (reserve) this.internal.add(port);
|
|
3367
3463
|
return this.internal.has(port);
|
|
3368
3464
|
}
|
|
3465
|
+
reserve(port) {
|
|
3466
|
+
this.reserved.add(port);
|
|
3467
|
+
}
|
|
3468
|
+
facade(port, name2) {
|
|
3469
|
+
this.reserve(port);
|
|
3470
|
+
this.kernelOnly(port, true);
|
|
3471
|
+
this.facades.set(port, name2);
|
|
3472
|
+
}
|
|
3473
|
+
facadeAt(addr) {
|
|
3474
|
+
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return void 0;
|
|
3475
|
+
return this.facades.get(addr.port);
|
|
3476
|
+
}
|
|
3369
3477
|
activate(addr, start2) {
|
|
3370
3478
|
this.activators.set(keyOf(addr), start2);
|
|
3371
3479
|
}
|
|
@@ -3374,7 +3482,7 @@ var LoopbackNet = class {
|
|
|
3374
3482
|
}
|
|
3375
3483
|
listen(addr, backlog = 128) {
|
|
3376
3484
|
const socket = this.socket(addr.family);
|
|
3377
|
-
socket.bind(addr);
|
|
3485
|
+
socket.bind(addr, true);
|
|
3378
3486
|
socket.listen(backlog);
|
|
3379
3487
|
return socket;
|
|
3380
3488
|
}
|
|
@@ -3383,11 +3491,13 @@ var LoopbackNet = class {
|
|
|
3383
3491
|
void socket.connect(addr, false);
|
|
3384
3492
|
return socket;
|
|
3385
3493
|
}
|
|
3386
|
-
bind(socket, addr) {
|
|
3494
|
+
bind(socket, addr, kernel = false) {
|
|
3387
3495
|
if (addr.family === "unix") {
|
|
3388
3496
|
if (addr.path === "") throw new KernelError("EINVAL");
|
|
3389
3497
|
} else if (addr.host !== "0.0.0.0" && !isLoopback(addr.host)) {
|
|
3390
3498
|
throw new KernelError("EADDRNOTAVAIL");
|
|
3499
|
+
} else if (!kernel && this.reserved.has(addr.port)) {
|
|
3500
|
+
throw new KernelError("EADDRINUSE");
|
|
3391
3501
|
}
|
|
3392
3502
|
const named = addr.family === "inet" && addr.port === 0 ? { ...addr, port: this.ephemeral() } : addr;
|
|
3393
3503
|
const key = keyOf(named);
|
|
@@ -3414,7 +3524,7 @@ var LoopbackNet = class {
|
|
|
3414
3524
|
for (let i = 0; i < span; i++) {
|
|
3415
3525
|
const port = this.nextEphemeral;
|
|
3416
3526
|
this.nextEphemeral = port === EPHEMERAL_LAST ? EPHEMERAL_FIRST : port + 1;
|
|
3417
|
-
if (!this.bound.has(`inet:${port}`)) return port;
|
|
3527
|
+
if (!this.bound.has(`inet:${port}`) && !this.reserved.has(port)) return port;
|
|
3418
3528
|
}
|
|
3419
3529
|
throw new KernelError("EADDRINUSE");
|
|
3420
3530
|
}
|
|
@@ -3710,12 +3820,12 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
3710
3820
|
}
|
|
3711
3821
|
sockets.set(call.nid, socket);
|
|
3712
3822
|
peer.postMessage({ net: "ws-opened", nid: call.nid, protocol: socket.protocol });
|
|
3713
|
-
void
|
|
3823
|
+
void relay2(call.nid, socket);
|
|
3714
3824
|
} catch (e) {
|
|
3715
3825
|
fail2(call.nid, e);
|
|
3716
3826
|
}
|
|
3717
3827
|
};
|
|
3718
|
-
const
|
|
3828
|
+
const relay2 = async (nid, socket) => {
|
|
3719
3829
|
let ending;
|
|
3720
3830
|
let late;
|
|
3721
3831
|
const unanswered = new Promise((resolve2) => {
|
|
@@ -4349,6 +4459,45 @@ function cdpRegistry(send, gone) {
|
|
|
4349
4459
|
}
|
|
4350
4460
|
};
|
|
4351
4461
|
}
|
|
4462
|
+
function facadeRegistry(send, gone) {
|
|
4463
|
+
const registered = /* @__PURE__ */ new Map();
|
|
4464
|
+
const drop = (id2) => {
|
|
4465
|
+
registered.get(id2)?.();
|
|
4466
|
+
return registered.delete(id2);
|
|
4467
|
+
};
|
|
4468
|
+
return {
|
|
4469
|
+
serve(l, req) {
|
|
4470
|
+
const hook = portFacadeHook(
|
|
4471
|
+
(request2, facade) => send({ facadeOpen: { ...request2, registration: req.id }, port: facade }, [
|
|
4472
|
+
facade
|
|
4473
|
+
]),
|
|
4474
|
+
gone
|
|
4475
|
+
);
|
|
4476
|
+
registered.set(req.id, l.facades.register(req.name, hook));
|
|
4477
|
+
return req.id;
|
|
4478
|
+
},
|
|
4479
|
+
drop,
|
|
4480
|
+
close: () => {
|
|
4481
|
+
for (const id2 of [...registered.keys()]) drop(id2);
|
|
4482
|
+
}
|
|
4483
|
+
};
|
|
4484
|
+
}
|
|
4485
|
+
function hostRegistries(send, gone) {
|
|
4486
|
+
const cdps = cdpRegistry(send, gone);
|
|
4487
|
+
const facades = facadeRegistry(send, gone);
|
|
4488
|
+
return {
|
|
4489
|
+
answer(l, req) {
|
|
4490
|
+
if (req.op === "serve-cdp") return cdps.serve(l, req);
|
|
4491
|
+
if (req.op === "unserve-cdp") return cdps.drop(req.registration);
|
|
4492
|
+
if (req.op === "serve-facade") return facades.serve(l, req);
|
|
4493
|
+
return facades.drop(req.registration);
|
|
4494
|
+
},
|
|
4495
|
+
close() {
|
|
4496
|
+
cdps.close();
|
|
4497
|
+
facades.close();
|
|
4498
|
+
}
|
|
4499
|
+
};
|
|
4500
|
+
}
|
|
4352
4501
|
function visibleTo(g, notify) {
|
|
4353
4502
|
if (!g?.dac.enforcing) return notify;
|
|
4354
4503
|
let queue = Promise.resolve();
|
|
@@ -4392,7 +4541,7 @@ function serveClient(port, host) {
|
|
|
4392
4541
|
if (state !== "closed") port.postMessage(message3, transfer);
|
|
4393
4542
|
};
|
|
4394
4543
|
const reply = (id2, body, transfer) => send({ id: id2, ...body }, transfer);
|
|
4395
|
-
const
|
|
4544
|
+
const hosts = hostRegistries(send, ended.promise);
|
|
4396
4545
|
function detach(kill = false, bye = "the slicc-kernel detached this client") {
|
|
4397
4546
|
if (state === "closed") return;
|
|
4398
4547
|
send({ bye });
|
|
@@ -4400,7 +4549,7 @@ function serveClient(port, host) {
|
|
|
4400
4549
|
net?.close();
|
|
4401
4550
|
for (const unwatch of watches.values()) unwatch();
|
|
4402
4551
|
watches.clear();
|
|
4403
|
-
|
|
4552
|
+
hosts.close();
|
|
4404
4553
|
for (const session of terminals.values()) session.close();
|
|
4405
4554
|
terminals.clear();
|
|
4406
4555
|
if (kill) killGroups(host, [...groups]);
|
|
@@ -4497,16 +4646,16 @@ function serveClient(port, host) {
|
|
|
4497
4646
|
case "mount":
|
|
4498
4647
|
return { result: await l.mountAs(clientCred(self), req.spec) };
|
|
4499
4648
|
case "umount":
|
|
4500
|
-
await l.umountAs(clientCred(self), req.target);
|
|
4501
|
-
return { result: true };
|
|
4649
|
+
return { result: await l.umountAs(clientCred(self), req.target).then(() => true) };
|
|
4502
4650
|
case "mounts":
|
|
4503
4651
|
return { result: l.mounts.list() };
|
|
4504
4652
|
case "dial":
|
|
4505
4653
|
return dialFor(l, req, watches);
|
|
4506
4654
|
case "serve-cdp":
|
|
4507
|
-
return { result: cdps.serve(l, req) };
|
|
4508
4655
|
case "unserve-cdp":
|
|
4509
|
-
|
|
4656
|
+
case "serve-facade":
|
|
4657
|
+
case "unserve-facade":
|
|
4658
|
+
return { result: hosts.answer(l, req) };
|
|
4510
4659
|
case "detach":
|
|
4511
4660
|
return { result: true };
|
|
4512
4661
|
default:
|
|
@@ -6599,7 +6748,7 @@ var RemoteTransport = class {
|
|
|
6599
6748
|
finish();
|
|
6600
6749
|
throw e;
|
|
6601
6750
|
}
|
|
6602
|
-
const { status, statusText, headers, url, redirected, redirects } = head;
|
|
6751
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
6603
6752
|
const read = async () => {
|
|
6604
6753
|
if (finished) return void 0;
|
|
6605
6754
|
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
@@ -6616,7 +6765,7 @@ var RemoteTransport = class {
|
|
|
6616
6765
|
this.cancel(nid);
|
|
6617
6766
|
};
|
|
6618
6767
|
return {
|
|
6619
|
-
...
|
|
6768
|
+
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
6620
6769
|
...redirects ? { redirects } : {},
|
|
6621
6770
|
status,
|
|
6622
6771
|
statusText,
|
|
@@ -7081,6 +7230,7 @@ var Relay = class {
|
|
|
7081
7230
|
function enableCdp(net, hosts) {
|
|
7082
7231
|
let facade;
|
|
7083
7232
|
net.kernelOnly(CDP_PORT, true);
|
|
7233
|
+
net.reserve(CDP_PORT);
|
|
7084
7234
|
net.activate({ family: "inet", host: "127.0.0.1", port: CDP_PORT }, () => {
|
|
7085
7235
|
const started = new CdpFacade({ net, hosts });
|
|
7086
7236
|
facade = started;
|
|
@@ -7395,9 +7545,9 @@ async function scanFilesystems(fs, modules) {
|
|
|
7395
7545
|
} catch {
|
|
7396
7546
|
continue;
|
|
7397
7547
|
}
|
|
7398
|
-
const
|
|
7399
|
-
if (!
|
|
7400
|
-
for (const [type, entry] of Object.entries(
|
|
7548
|
+
const declared2 = manifest.slicc?.filesystems;
|
|
7549
|
+
if (!declared2 || typeof declared2 !== "object") continue;
|
|
7550
|
+
for (const [type, entry] of Object.entries(declared2)) {
|
|
7401
7551
|
const module = inside(pkg, entry?.module);
|
|
7402
7552
|
if (NAME2.test(type) && module && !found.has(type)) found.set(type, module);
|
|
7403
7553
|
}
|
|
@@ -7415,9 +7565,9 @@ async function scanBinfmts(fs, modules, warn = () => {
|
|
|
7415
7565
|
} catch {
|
|
7416
7566
|
continue;
|
|
7417
7567
|
}
|
|
7418
|
-
const
|
|
7419
|
-
if (!
|
|
7420
|
-
for (const [suffix, command] of Object.entries(
|
|
7568
|
+
const declared2 = manifest.slicc?.binfmt;
|
|
7569
|
+
if (!declared2 || typeof declared2 !== "object") continue;
|
|
7570
|
+
for (const [suffix, command] of Object.entries(declared2)) {
|
|
7421
7571
|
if (!SUFFIX.test(suffix) || typeof command !== "string" || !NAME2.test(command)) continue;
|
|
7422
7572
|
const owner = owners.get(suffix);
|
|
7423
7573
|
if (owner === void 0) {
|
|
@@ -7447,6 +7597,132 @@ function binfmtOf(binfmts, path) {
|
|
|
7447
7597
|
return best === void 0 ? void 0 : binfmts.get(best);
|
|
7448
7598
|
}
|
|
7449
7599
|
|
|
7600
|
+
// src/facade/types.ts
|
|
7601
|
+
var FACADE_NAME = /^[a-z][a-z0-9-]*$/;
|
|
7602
|
+
function facadeEnvName(name2) {
|
|
7603
|
+
return `SLICC_${name2.toUpperCase().replaceAll("-", "_")}_URL`;
|
|
7604
|
+
}
|
|
7605
|
+
function facadeUrl(port) {
|
|
7606
|
+
return `tcp://127.0.0.1:${port}`;
|
|
7607
|
+
}
|
|
7608
|
+
|
|
7609
|
+
// src/facade/hosts.ts
|
|
7610
|
+
var TAKEN_PORTS = /* @__PURE__ */ new Set([CDP_PORT, REALM_PROXY_PORT]);
|
|
7611
|
+
var READ_CHUNK = 64 * 1024;
|
|
7612
|
+
var FACADE_MAX_PENDING = 16 * 1024 * 1024;
|
|
7613
|
+
var FACADE_FLOODED = `slicc-kernel: more than ${FACADE_MAX_PENDING} bytes are waiting for the program to read`;
|
|
7614
|
+
function declared(specs) {
|
|
7615
|
+
const out = /* @__PURE__ */ new Map();
|
|
7616
|
+
const ports = /* @__PURE__ */ new Set();
|
|
7617
|
+
for (const [name2, spec] of Object.entries(specs ?? {})) {
|
|
7618
|
+
if (!FACADE_NAME.test(name2)) throw new TypeError(`facades: not a facade name: ${name2}`);
|
|
7619
|
+
const port = spec?.port;
|
|
7620
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535 || TAKEN_PORTS.has(port)) {
|
|
7621
|
+
throw new TypeError(`facades.${name2}: not a free port: ${String(port)}`);
|
|
7622
|
+
}
|
|
7623
|
+
if (ports.has(port)) throw new TypeError(`facades.${name2}: port ${port} is taken twice`);
|
|
7624
|
+
if (spec.hook !== void 0 && typeof spec.hook !== "function") {
|
|
7625
|
+
throw new TypeError(`facades.${name2}: hook must be a function`);
|
|
7626
|
+
}
|
|
7627
|
+
ports.add(port);
|
|
7628
|
+
out.set(name2, { port, embedder: spec.hook, clients: [] });
|
|
7629
|
+
}
|
|
7630
|
+
return out;
|
|
7631
|
+
}
|
|
7632
|
+
var FacadeHosts = class {
|
|
7633
|
+
facades;
|
|
7634
|
+
constructor(specs) {
|
|
7635
|
+
this.facades = declared(specs);
|
|
7636
|
+
}
|
|
7637
|
+
env() {
|
|
7638
|
+
const env = {};
|
|
7639
|
+
for (const [name2, { port }] of this.facades) env[facadeEnvName(name2)] = facadeUrl(port);
|
|
7640
|
+
return env;
|
|
7641
|
+
}
|
|
7642
|
+
enable(net) {
|
|
7643
|
+
for (const [name2, { port }] of this.facades) {
|
|
7644
|
+
net.facade(port, name2);
|
|
7645
|
+
net.activate({ family: "inet", host: "127.0.0.1", port }, () => {
|
|
7646
|
+
const listener = net.listen({ family: "inet", host: "127.0.0.1", port });
|
|
7647
|
+
void acceptAll(listener, (socket) => this.serve(name2, socket));
|
|
7648
|
+
});
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
register(name2, hook) {
|
|
7652
|
+
const entry = this.facades.get(name2);
|
|
7653
|
+
if (!entry || typeof hook !== "function") throw new KernelError("EINVAL");
|
|
7654
|
+
entry.clients.push(hook);
|
|
7655
|
+
return () => {
|
|
7656
|
+
const at = entry.clients.indexOf(hook);
|
|
7657
|
+
if (at >= 0) entry.clients.splice(at, 1);
|
|
7658
|
+
};
|
|
7659
|
+
}
|
|
7660
|
+
async serve(name2, socket) {
|
|
7661
|
+
const entry = this.facades.get(name2);
|
|
7662
|
+
const hook = entry.clients.at(-1) ?? entry.embedder;
|
|
7663
|
+
const stamp = socket.peerStamp;
|
|
7664
|
+
if (!hook || !stamp) return socket.close();
|
|
7665
|
+
let conn;
|
|
7666
|
+
try {
|
|
7667
|
+
conn = await hook(structuredClone(stamp), { name: name2 });
|
|
7668
|
+
} catch {
|
|
7669
|
+
return socket.close();
|
|
7670
|
+
}
|
|
7671
|
+
await relay(socket, conn);
|
|
7672
|
+
}
|
|
7673
|
+
};
|
|
7674
|
+
async function acceptAll(listener, serve) {
|
|
7675
|
+
for (; ; ) {
|
|
7676
|
+
const socket = await listener.accept();
|
|
7677
|
+
void serve(socket);
|
|
7678
|
+
}
|
|
7679
|
+
}
|
|
7680
|
+
async function relay(socket, conn) {
|
|
7681
|
+
let ended = false;
|
|
7682
|
+
let pending = 0;
|
|
7683
|
+
let writes = Promise.resolve();
|
|
7684
|
+
const end = () => {
|
|
7685
|
+
if (ended) return;
|
|
7686
|
+
ended = true;
|
|
7687
|
+
socket.close();
|
|
7688
|
+
};
|
|
7689
|
+
conn.onmessage = (bytes) => {
|
|
7690
|
+
if (ended) return;
|
|
7691
|
+
const chunk2 = bytes.slice();
|
|
7692
|
+
pending += chunk2.length;
|
|
7693
|
+
if (pending > FACADE_MAX_PENDING) {
|
|
7694
|
+
end();
|
|
7695
|
+
conn.close(FACADE_FLOODED);
|
|
7696
|
+
return;
|
|
7697
|
+
}
|
|
7698
|
+
writes = writes.then(async () => {
|
|
7699
|
+
if (ended) return;
|
|
7700
|
+
let at = 0;
|
|
7701
|
+
while (at < chunk2.length) at += await socket.write(chunk2.subarray(at));
|
|
7702
|
+
pending -= chunk2.length;
|
|
7703
|
+
});
|
|
7704
|
+
writes.catch(() => {
|
|
7705
|
+
end();
|
|
7706
|
+
conn.close();
|
|
7707
|
+
});
|
|
7708
|
+
};
|
|
7709
|
+
conn.onclose = () => {
|
|
7710
|
+
writes.then(end, end);
|
|
7711
|
+
};
|
|
7712
|
+
try {
|
|
7713
|
+
for (; ; ) {
|
|
7714
|
+
const bytes = await socket.read(READ_CHUNK);
|
|
7715
|
+
if (bytes.length === 0 || ended) break;
|
|
7716
|
+
conn.send(bytes);
|
|
7717
|
+
}
|
|
7718
|
+
} catch {
|
|
7719
|
+
}
|
|
7720
|
+
if (!ended) {
|
|
7721
|
+
end();
|
|
7722
|
+
conn.close();
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
|
|
7450
7726
|
// src/fs/attest.ts
|
|
7451
7727
|
var ATTEST_MAX = 1024 * 1024;
|
|
7452
7728
|
var UNOWNED = 1e3;
|
|
@@ -7641,14 +7917,14 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7641
7917
|
const own = await userDir(dir);
|
|
7642
7918
|
return own?.has(path.slice(slash + 1)) ? owned4(synthetic(false, path), dir) : void 0;
|
|
7643
7919
|
}
|
|
7644
|
-
async function
|
|
7920
|
+
async function linked2(path) {
|
|
7645
7921
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
7646
7922
|
}
|
|
7647
7923
|
async function stat(path, real) {
|
|
7648
7924
|
try {
|
|
7649
7925
|
return await real(path);
|
|
7650
7926
|
} catch (err) {
|
|
7651
|
-
const found = missing3(err) ? await
|
|
7927
|
+
const found = missing3(err) ? await linked2(path) : void 0;
|
|
7652
7928
|
if (found) return found;
|
|
7653
7929
|
throw err;
|
|
7654
7930
|
}
|
|
@@ -7660,7 +7936,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7660
7936
|
try {
|
|
7661
7937
|
return await fs.readFileBuffer(path);
|
|
7662
7938
|
} catch (err) {
|
|
7663
|
-
if (missing3(err) && (await
|
|
7939
|
+
if (missing3(err) && (await linked2(path))?.isFile) return new Uint8Array(0);
|
|
7664
7940
|
throw err;
|
|
7665
7941
|
}
|
|
7666
7942
|
},
|
|
@@ -7668,7 +7944,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7668
7944
|
link: (from, to, follow2) => fs.link(from, to, follow2),
|
|
7669
7945
|
links: (path) => mayLink(fs, path),
|
|
7670
7946
|
async exists(path) {
|
|
7671
|
-
return await fs.exists(path) || await
|
|
7947
|
+
return await fs.exists(path) || await linked2(path) !== void 0;
|
|
7672
7948
|
},
|
|
7673
7949
|
stat: (path) => stat(path, (p) => fs.stat(p)),
|
|
7674
7950
|
lstat: (path) => stat(path, (p) => fs.lstat(p)),
|
|
@@ -9093,6 +9369,7 @@ var MountTable = class {
|
|
|
9093
9369
|
return { quota: st.blocks * st.bsize, usage: (st.blocks - st.bfree) * st.bsize };
|
|
9094
9370
|
}
|
|
9095
9371
|
wrap(base) {
|
|
9372
|
+
base.crossings?.((path) => this.locate(normalizePath(path)) !== void 0);
|
|
9096
9373
|
return new MountFs(this, base);
|
|
9097
9374
|
}
|
|
9098
9375
|
};
|
|
@@ -9116,6 +9393,37 @@ var MountFs = class {
|
|
|
9116
9393
|
writable(mount, path) {
|
|
9117
9394
|
if (readonly(mount)) throw errnoError("EROFS", path);
|
|
9118
9395
|
}
|
|
9396
|
+
async through(path) {
|
|
9397
|
+
const real = normalizePath(path);
|
|
9398
|
+
if (this.at(real)) return real;
|
|
9399
|
+
try {
|
|
9400
|
+
await this.base.stat(parentOf7(real));
|
|
9401
|
+
return real;
|
|
9402
|
+
} catch (err) {
|
|
9403
|
+
const moved2 = redirectOf(err);
|
|
9404
|
+
return moved2 ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
9405
|
+
}
|
|
9406
|
+
}
|
|
9407
|
+
async across(from, to, redirects) {
|
|
9408
|
+
const moved2 = [await this.through(from), await this.through(to)];
|
|
9409
|
+
const same = moved2[0] === normalizePath(from) && moved2[1] === normalizePath(to);
|
|
9410
|
+
if (same || redirects >= MAX_LINKS7) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
9411
|
+
return moved2;
|
|
9412
|
+
}
|
|
9413
|
+
async based(paths, redirects, run2, again) {
|
|
9414
|
+
try {
|
|
9415
|
+
return await run2();
|
|
9416
|
+
} catch (err) {
|
|
9417
|
+
const moved2 = redirectOf(err);
|
|
9418
|
+
if (!moved2) throw err;
|
|
9419
|
+
if (redirects >= MAX_LINKS7) throw errnoError("ELOOP", paths[0]);
|
|
9420
|
+
const at = paths.map((path) => {
|
|
9421
|
+
const real = normalizePath(path);
|
|
9422
|
+
return within6(real, moved2.of) ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
9423
|
+
});
|
|
9424
|
+
return again(at, redirects + 1);
|
|
9425
|
+
}
|
|
9426
|
+
}
|
|
9119
9427
|
async follow(path, hops = 0, create = false) {
|
|
9120
9428
|
const found = this.at(path);
|
|
9121
9429
|
if (!found) return path;
|
|
@@ -9163,10 +9471,17 @@ var MountFs = class {
|
|
|
9163
9471
|
async readFile(path) {
|
|
9164
9472
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
9165
9473
|
}
|
|
9166
|
-
async readFileBuffer(path) {
|
|
9474
|
+
async readFileBuffer(path, redirects = 0) {
|
|
9167
9475
|
const real = await this.follow(path);
|
|
9168
9476
|
const found = this.at(real);
|
|
9169
|
-
if (!found)
|
|
9477
|
+
if (!found) {
|
|
9478
|
+
return this.based(
|
|
9479
|
+
[real],
|
|
9480
|
+
redirects,
|
|
9481
|
+
() => this.base.readFileBuffer(real),
|
|
9482
|
+
([to], n) => this.readFileBuffer(to, n)
|
|
9483
|
+
);
|
|
9484
|
+
}
|
|
9170
9485
|
for (let attempt = 1; ; attempt++) {
|
|
9171
9486
|
try {
|
|
9172
9487
|
return await this.readWhole(found.mount, real, found.rel);
|
|
@@ -9205,10 +9520,18 @@ var MountFs = class {
|
|
|
9205
9520
|
}
|
|
9206
9521
|
return concat4(chunks, total);
|
|
9207
9522
|
}
|
|
9208
|
-
async writeFile(path, content, owner) {
|
|
9523
|
+
async writeFile(path, content, owner, redirects = 0) {
|
|
9209
9524
|
const real = await this.follow(path, 0, true);
|
|
9210
9525
|
const found = this.at(real);
|
|
9211
|
-
if (!found)
|
|
9526
|
+
if (!found) {
|
|
9527
|
+
const write = () => this.base.writeFile(real, content, owner);
|
|
9528
|
+
return this.based(
|
|
9529
|
+
[real],
|
|
9530
|
+
redirects,
|
|
9531
|
+
write,
|
|
9532
|
+
([to], n) => this.writeFile(to, content, owner, n)
|
|
9533
|
+
);
|
|
9534
|
+
}
|
|
9212
9535
|
const { mount, rel: rel2 } = found;
|
|
9213
9536
|
this.writable(mount, real);
|
|
9214
9537
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -9242,10 +9565,18 @@ var MountFs = class {
|
|
|
9242
9565
|
this.table.forget(mount, real);
|
|
9243
9566
|
}
|
|
9244
9567
|
}
|
|
9245
|
-
async pread(path, offset, length2, version) {
|
|
9568
|
+
async pread(path, offset, length2, version, redirects = 0) {
|
|
9246
9569
|
const real = await this.follow(path);
|
|
9247
9570
|
const found = this.at(real);
|
|
9248
|
-
|
|
9571
|
+
const { pread } = this.base;
|
|
9572
|
+
if (!found && pread) {
|
|
9573
|
+
return this.based(
|
|
9574
|
+
[real],
|
|
9575
|
+
redirects,
|
|
9576
|
+
() => pread.call(this.base, real, offset, length2),
|
|
9577
|
+
([to], n) => this.pread(to, offset, length2, version, n)
|
|
9578
|
+
);
|
|
9579
|
+
}
|
|
9249
9580
|
if (!found) return (await this.base.readFileBuffer(real)).slice(offset, offset + length2);
|
|
9250
9581
|
const { mount, rel: rel2 } = found;
|
|
9251
9582
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
@@ -9292,10 +9623,18 @@ var MountFs = class {
|
|
|
9292
9623
|
);
|
|
9293
9624
|
}
|
|
9294
9625
|
}
|
|
9295
|
-
async pwrite(path, offset, bytes, transfer = false) {
|
|
9626
|
+
async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
|
|
9296
9627
|
const real = await this.follow(path, 0, true);
|
|
9297
9628
|
const found = this.at(real);
|
|
9298
|
-
|
|
9629
|
+
const { pwrite } = this.base;
|
|
9630
|
+
if (!found && pwrite) {
|
|
9631
|
+
return this.based(
|
|
9632
|
+
[real],
|
|
9633
|
+
redirects,
|
|
9634
|
+
() => pwrite.call(this.base, real, offset, bytes),
|
|
9635
|
+
([to], n) => this.pwrite(to, offset, bytes, transfer, n)
|
|
9636
|
+
);
|
|
9637
|
+
}
|
|
9299
9638
|
if (!found)
|
|
9300
9639
|
return this.base.writeFile(
|
|
9301
9640
|
real,
|
|
@@ -9335,10 +9674,18 @@ var MountFs = class {
|
|
|
9335
9674
|
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
9336
9675
|
}
|
|
9337
9676
|
}
|
|
9338
|
-
async truncate(path, size) {
|
|
9677
|
+
async truncate(path, size, redirects = 0) {
|
|
9339
9678
|
const real = await this.follow(path);
|
|
9340
9679
|
const found = this.at(real);
|
|
9341
|
-
|
|
9680
|
+
const { truncate } = this.base;
|
|
9681
|
+
if (!found && truncate) {
|
|
9682
|
+
return this.based(
|
|
9683
|
+
[real],
|
|
9684
|
+
redirects,
|
|
9685
|
+
() => truncate.call(this.base, real, size),
|
|
9686
|
+
([to], n) => this.truncate(to, size, n)
|
|
9687
|
+
);
|
|
9688
|
+
}
|
|
9342
9689
|
if (!found?.mount.caps.ranges) {
|
|
9343
9690
|
return this.writeFile(real, resized(await this.readFileBuffer(real), size));
|
|
9344
9691
|
}
|
|
@@ -9354,8 +9701,15 @@ var MountFs = class {
|
|
|
9354
9701
|
this.table.forget(mount, real);
|
|
9355
9702
|
}
|
|
9356
9703
|
}
|
|
9357
|
-
async exists(path) {
|
|
9358
|
-
if (!this.at(path))
|
|
9704
|
+
async exists(path, redirects = 0) {
|
|
9705
|
+
if (!this.at(path)) {
|
|
9706
|
+
return this.based(
|
|
9707
|
+
[path],
|
|
9708
|
+
redirects,
|
|
9709
|
+
() => this.base.exists(path),
|
|
9710
|
+
([to], n) => this.exists(to, n)
|
|
9711
|
+
);
|
|
9712
|
+
}
|
|
9359
9713
|
try {
|
|
9360
9714
|
await this.stat(path);
|
|
9361
9715
|
return true;
|
|
@@ -9365,9 +9719,16 @@ var MountFs = class {
|
|
|
9365
9719
|
throw err;
|
|
9366
9720
|
}
|
|
9367
9721
|
}
|
|
9368
|
-
async lstat(path) {
|
|
9722
|
+
async lstat(path, redirects = 0) {
|
|
9369
9723
|
const found = this.at(path);
|
|
9370
|
-
if (!found)
|
|
9724
|
+
if (!found) {
|
|
9725
|
+
return this.based(
|
|
9726
|
+
[path],
|
|
9727
|
+
redirects,
|
|
9728
|
+
() => this.base.lstat(path),
|
|
9729
|
+
([to], n) => this.lstat(to, n)
|
|
9730
|
+
);
|
|
9731
|
+
}
|
|
9371
9732
|
const real = normalizePath(path);
|
|
9372
9733
|
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
9373
9734
|
return this.statWriting(
|
|
@@ -9380,9 +9741,15 @@ var MountFs = class {
|
|
|
9380
9741
|
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
9381
9742
|
return statOf({ ...attr2, size: Math.max(attr2.size, ...ends) }, real, mount);
|
|
9382
9743
|
}
|
|
9383
|
-
async stat(path) {
|
|
9744
|
+
async stat(path, redirects = 0) {
|
|
9384
9745
|
const real = await this.follow(path);
|
|
9385
|
-
|
|
9746
|
+
if (this.at(real)) return this.lstat(real);
|
|
9747
|
+
return this.based(
|
|
9748
|
+
[real],
|
|
9749
|
+
redirects,
|
|
9750
|
+
() => this.base.stat(real),
|
|
9751
|
+
([to], n) => this.stat(to, n)
|
|
9752
|
+
);
|
|
9386
9753
|
}
|
|
9387
9754
|
async entries(path) {
|
|
9388
9755
|
const real = await this.follow(path);
|
|
@@ -9394,12 +9761,26 @@ var MountFs = class {
|
|
|
9394
9761
|
list: await this.table.readdir(found.mount, real, found.rel)
|
|
9395
9762
|
};
|
|
9396
9763
|
}
|
|
9397
|
-
async readdir(path) {
|
|
9398
|
-
if (!this.at(path))
|
|
9764
|
+
async readdir(path, redirects = 0) {
|
|
9765
|
+
if (!this.at(path)) {
|
|
9766
|
+
return this.based(
|
|
9767
|
+
[path],
|
|
9768
|
+
redirects,
|
|
9769
|
+
() => this.base.readdir(path),
|
|
9770
|
+
([to], n) => this.readdir(to, n)
|
|
9771
|
+
);
|
|
9772
|
+
}
|
|
9399
9773
|
return (await this.entries(path)).list.map((e) => e.name);
|
|
9400
9774
|
}
|
|
9401
|
-
async readdirStat(path) {
|
|
9402
|
-
if (!this.at(path))
|
|
9775
|
+
async readdirStat(path, redirects = 0) {
|
|
9776
|
+
if (!this.at(path)) {
|
|
9777
|
+
return this.based(
|
|
9778
|
+
[path],
|
|
9779
|
+
redirects,
|
|
9780
|
+
() => this.base.readdirStat(path),
|
|
9781
|
+
([to], n) => this.readdirStat(to, n)
|
|
9782
|
+
);
|
|
9783
|
+
}
|
|
9403
9784
|
const { real, mount, list } = await this.entries(path);
|
|
9404
9785
|
return Promise.all(
|
|
9405
9786
|
list.map(async (entry) => {
|
|
@@ -9411,9 +9792,16 @@ var MountFs = class {
|
|
|
9411
9792
|
})
|
|
9412
9793
|
);
|
|
9413
9794
|
}
|
|
9414
|
-
async mkdir(path, options = {}) {
|
|
9795
|
+
async mkdir(path, options = {}, redirects = 0) {
|
|
9415
9796
|
const found = this.at(path);
|
|
9416
|
-
if (!found)
|
|
9797
|
+
if (!found) {
|
|
9798
|
+
return this.based(
|
|
9799
|
+
[path],
|
|
9800
|
+
redirects,
|
|
9801
|
+
() => this.base.mkdir(path, options),
|
|
9802
|
+
([to], n) => this.mkdir(to, options, n)
|
|
9803
|
+
);
|
|
9804
|
+
}
|
|
9417
9805
|
const { mount, rel: rel2 } = found;
|
|
9418
9806
|
const real = normalizePath(path);
|
|
9419
9807
|
this.writable(mount, real);
|
|
@@ -9438,11 +9826,18 @@ var MountFs = class {
|
|
|
9438
9826
|
await mount.conn.call({ op: "mkdir", path: sub, ...made2 });
|
|
9439
9827
|
}
|
|
9440
9828
|
}
|
|
9441
|
-
async rm(path, options = {}) {
|
|
9829
|
+
async rm(path, options = {}, redirects = 0) {
|
|
9442
9830
|
const found = this.at(path);
|
|
9443
9831
|
if (!found && options.recursive && this.table.under(normalizePath(path)))
|
|
9444
9832
|
return this.rmAround(normalizePath(path), options);
|
|
9445
|
-
if (!found)
|
|
9833
|
+
if (!found) {
|
|
9834
|
+
return this.based(
|
|
9835
|
+
[path],
|
|
9836
|
+
redirects,
|
|
9837
|
+
() => this.base.rm(path, options),
|
|
9838
|
+
([to], n) => this.rm(to, options, n)
|
|
9839
|
+
);
|
|
9840
|
+
}
|
|
9446
9841
|
const { mount, rel: rel2 } = found;
|
|
9447
9842
|
const real = normalizePath(path);
|
|
9448
9843
|
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
@@ -9483,11 +9878,22 @@ var MountFs = class {
|
|
|
9483
9878
|
}
|
|
9484
9879
|
throw first ?? errnoError("EBUSY", `${path} holds a mount point`);
|
|
9485
9880
|
}
|
|
9486
|
-
async rename(from, to) {
|
|
9881
|
+
async rename(from, to, redirects = 0) {
|
|
9487
9882
|
const a = this.at(from);
|
|
9488
9883
|
const b = this.at(to);
|
|
9489
|
-
if (!a && !b)
|
|
9490
|
-
|
|
9884
|
+
if (!a && !b) {
|
|
9885
|
+
return this.based(
|
|
9886
|
+
[from, to],
|
|
9887
|
+
redirects,
|
|
9888
|
+
() => this.base.rename(from, to),
|
|
9889
|
+
([f, t], n) => this.rename(f, t, n)
|
|
9890
|
+
);
|
|
9891
|
+
}
|
|
9892
|
+
if (!a || !b) {
|
|
9893
|
+
const [f, t] = await this.across(from, to, redirects);
|
|
9894
|
+
return this.rename(f, t, redirects + 1);
|
|
9895
|
+
}
|
|
9896
|
+
if (a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
9491
9897
|
this.writable(a.mount, normalizePath(to));
|
|
9492
9898
|
await this.table.commitUnder(from);
|
|
9493
9899
|
await this.table.commitUnder(to);
|
|
@@ -9528,9 +9934,17 @@ var MountFs = class {
|
|
|
9528
9934
|
this.table.forget(a.mount, normalizePath(to));
|
|
9529
9935
|
}
|
|
9530
9936
|
}
|
|
9531
|
-
async symlink(target, path, owner) {
|
|
9937
|
+
async symlink(target, path, owner, redirects = 0) {
|
|
9532
9938
|
const found = this.at(path);
|
|
9533
|
-
if (!found)
|
|
9939
|
+
if (!found) {
|
|
9940
|
+
const make = () => this.base.symlink(target, path, owner);
|
|
9941
|
+
return this.based(
|
|
9942
|
+
[path],
|
|
9943
|
+
redirects,
|
|
9944
|
+
make,
|
|
9945
|
+
([to], n) => this.symlink(target, to, owner, n)
|
|
9946
|
+
);
|
|
9947
|
+
}
|
|
9534
9948
|
this.writable(found.mount, normalizePath(path));
|
|
9535
9949
|
if (!found.mount.caps.symlinks)
|
|
9536
9950
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -9540,8 +9954,11 @@ var MountFs = class {
|
|
|
9540
9954
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel, ...made2 });
|
|
9541
9955
|
}
|
|
9542
9956
|
async realpath(path, follow2) {
|
|
9543
|
-
|
|
9544
|
-
|
|
9957
|
+
const { realpath: realpath2 } = this.base;
|
|
9958
|
+
if (this.at(path) || !realpath2) throw errnoError("ENOSYS", path);
|
|
9959
|
+
const real = await realpath2.call(this.base, path, follow2).catch((err) => {
|
|
9960
|
+
throw redirectOf(err) ? errnoError("ENOSYS", path) : err;
|
|
9961
|
+
});
|
|
9545
9962
|
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
9546
9963
|
return real;
|
|
9547
9964
|
}
|
|
@@ -9563,17 +9980,30 @@ var MountFs = class {
|
|
|
9563
9980
|
}
|
|
9564
9981
|
return out;
|
|
9565
9982
|
}
|
|
9566
|
-
async readlink(path) {
|
|
9983
|
+
async readlink(path, redirects = 0) {
|
|
9567
9984
|
const found = this.at(path);
|
|
9568
|
-
if (!found)
|
|
9985
|
+
if (!found) {
|
|
9986
|
+
return this.based(
|
|
9987
|
+
[path],
|
|
9988
|
+
redirects,
|
|
9989
|
+
() => this.base.readlink(path),
|
|
9990
|
+
([to], n) => this.readlink(to, n)
|
|
9991
|
+
);
|
|
9992
|
+
}
|
|
9569
9993
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
9570
9994
|
}
|
|
9571
|
-
async chown(path, change) {
|
|
9995
|
+
async chown(path, change, redirects = 0) {
|
|
9572
9996
|
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
9573
9997
|
const found = this.at(real);
|
|
9574
9998
|
if (found) return this.chownMounted(found, normalizePath(real), change);
|
|
9575
|
-
|
|
9576
|
-
|
|
9999
|
+
const { chown: chown2 } = this.base;
|
|
10000
|
+
if (!chown2) throw errnoError("EPERM", path);
|
|
10001
|
+
return this.based(
|
|
10002
|
+
[real],
|
|
10003
|
+
redirects,
|
|
10004
|
+
() => chown2.call(this.base, real, change),
|
|
10005
|
+
([to], n) => this.chown(to, change, n)
|
|
10006
|
+
);
|
|
9577
10007
|
}
|
|
9578
10008
|
async chownMounted(found, real, change) {
|
|
9579
10009
|
const { mount, rel: rel2 } = found;
|
|
@@ -9593,24 +10023,47 @@ var MountFs = class {
|
|
|
9593
10023
|
...Object.fromEntries(attrs.filter(([, value]) => value !== void 0))
|
|
9594
10024
|
});
|
|
9595
10025
|
}
|
|
9596
|
-
async chmod(path, mode) {
|
|
10026
|
+
async chmod(path, mode, redirects = 0) {
|
|
9597
10027
|
const real = await this.follow(path);
|
|
9598
10028
|
const found = this.at(real);
|
|
9599
|
-
if (!found)
|
|
10029
|
+
if (!found) {
|
|
10030
|
+
return this.based(
|
|
10031
|
+
[real],
|
|
10032
|
+
redirects,
|
|
10033
|
+
() => this.base.chmod(real, mode),
|
|
10034
|
+
([to], n) => this.chmod(to, mode, n)
|
|
10035
|
+
);
|
|
10036
|
+
}
|
|
9600
10037
|
this.writable(found.mount, real);
|
|
9601
10038
|
if (!found.mount.caps.chmod) return;
|
|
9602
10039
|
this.table.forget(found.mount, real);
|
|
9603
10040
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
9604
10041
|
}
|
|
9605
|
-
async utimes(path, atime, mtime) {
|
|
10042
|
+
async utimes(path, atime, mtime, redirects = 0) {
|
|
9606
10043
|
const real = await this.follow(path);
|
|
9607
10044
|
const found = this.at(real);
|
|
9608
|
-
if (!found)
|
|
10045
|
+
if (!found) {
|
|
10046
|
+
const set2 = () => this.base.utimes(real, atime, mtime);
|
|
10047
|
+
return this.based(
|
|
10048
|
+
[real],
|
|
10049
|
+
redirects,
|
|
10050
|
+
set2,
|
|
10051
|
+
([to], n) => this.utimes(to, atime, mtime, n)
|
|
10052
|
+
);
|
|
10053
|
+
}
|
|
9609
10054
|
await this.setMtime(found, real, mtime);
|
|
9610
10055
|
}
|
|
9611
|
-
async lutimes(path, atime, mtime) {
|
|
10056
|
+
async lutimes(path, atime, mtime, redirects = 0) {
|
|
9612
10057
|
const found = this.at(path);
|
|
9613
|
-
if (!found)
|
|
10058
|
+
if (!found) {
|
|
10059
|
+
const set2 = () => lutimesOf(this.base, path, atime, mtime);
|
|
10060
|
+
return this.based(
|
|
10061
|
+
[path],
|
|
10062
|
+
redirects,
|
|
10063
|
+
set2,
|
|
10064
|
+
([to], n) => this.lutimes(to, atime, mtime, n)
|
|
10065
|
+
);
|
|
10066
|
+
}
|
|
9614
10067
|
const real = normalizePath(path);
|
|
9615
10068
|
if (!found.mount.caps.linkTimes && (await this.lstat(real)).isSymbolicLink) {
|
|
9616
10069
|
throw errnoError("EOPNOTSUPP", path);
|
|
@@ -9829,7 +10282,8 @@ async function run(entry, path, req) {
|
|
|
9829
10282
|
function guardOf(entry) {
|
|
9830
10283
|
const cred = entry.dac && entry.cred?.();
|
|
9831
10284
|
if (!cred || !entry.dac) return void 0;
|
|
9832
|
-
|
|
10285
|
+
const links = entry.links === void 0 ? {} : { links: entry.links };
|
|
10286
|
+
return { fs: entry.fs, cred, pid: entry.pid ?? 0, dac: entry.dac, ...links };
|
|
9833
10287
|
}
|
|
9834
10288
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
9835
10289
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
@@ -9890,9 +10344,15 @@ async function holdOp(entry, path, req) {
|
|
|
9890
10344
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
9891
10345
|
return done;
|
|
9892
10346
|
}
|
|
10347
|
+
async function followed(g, path) {
|
|
10348
|
+
const st = await g.fs.lstat(path).catch(() => void 0);
|
|
10349
|
+
if (st?.isSymbolicLink && !trustedLink(permOf(st), g.links)) deny(g, "follow", path);
|
|
10350
|
+
return done;
|
|
10351
|
+
}
|
|
9893
10352
|
async function accessOp(entry, path, req) {
|
|
9894
10353
|
const g = guardOf(entry);
|
|
9895
10354
|
if (!g) return done;
|
|
10355
|
+
if (req.arg2 === "follow") return followed(g, path);
|
|
9896
10356
|
const open = req.arg2 === "open";
|
|
9897
10357
|
const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
|
|
9898
10358
|
const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
|
|
@@ -9915,15 +10375,18 @@ var CHANGING = /* @__PURE__ */ new Set([
|
|
|
9915
10375
|
"lchown"
|
|
9916
10376
|
]);
|
|
9917
10377
|
var CONTENT = /* @__PURE__ */ new Set(["write", "pwrite", "truncate"]);
|
|
10378
|
+
var REMOVING = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm", "rename"]);
|
|
9918
10379
|
async function mayChange(entry, path, req) {
|
|
9919
10380
|
const { mayChange: mayChange2 } = entry.fs;
|
|
9920
10381
|
if (!mayChange2) return;
|
|
9921
10382
|
const { op } = req;
|
|
9922
10383
|
if (CONTENT.has(op) && req.handle === void 0) return mayChange2.call(entry.fs, path, true);
|
|
9923
10384
|
if (!CHANGING.has(op)) return;
|
|
9924
|
-
|
|
10385
|
+
const follow2 = op === "utimes" || op === "chmod" || op === "chown";
|
|
10386
|
+
await mayChange2.call(entry.fs, path, follow2, REMOVING.has(op));
|
|
9925
10387
|
if (op === "rename" || op === "link") {
|
|
9926
|
-
|
|
10388
|
+
const to = entry.fs.resolvePath(entry.cwd, req.arg2 ?? "");
|
|
10389
|
+
await mayChange2.call(entry.fs, to, false, op === "rename");
|
|
9927
10390
|
}
|
|
9928
10391
|
}
|
|
9929
10392
|
async function guarded(entry, path, req) {
|
|
@@ -10616,7 +11079,7 @@ function mountTable(mounts = []) {
|
|
|
10616
11079
|
}
|
|
10617
11080
|
|
|
10618
11081
|
// src/version.ts
|
|
10619
|
-
var KERNEL_VERSION = true ? "1.
|
|
11082
|
+
var KERNEL_VERSION = true ? "1.90.0" : "0.0.0-dev";
|
|
10620
11083
|
var OS_RELEASE = "6.0.0-slicc";
|
|
10621
11084
|
function procVersion() {
|
|
10622
11085
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -12256,7 +12719,9 @@ async function socketSyscall(req, proc) {
|
|
|
12256
12719
|
case "sock-accept":
|
|
12257
12720
|
return ok(await accept(proc, req.fd, req.nonblock));
|
|
12258
12721
|
case "sock-connect": {
|
|
12259
|
-
const
|
|
12722
|
+
const socket = socketAt(fds, req.fd);
|
|
12723
|
+
const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
|
|
12724
|
+
const dialing = socket.connect(req.addr, true, proc.cred?.(), stamp || void 0);
|
|
12260
12725
|
if (req.nonblock) {
|
|
12261
12726
|
dialing?.catch(() => void 0);
|
|
12262
12727
|
throw new KernelError("EINPROGRESS");
|
|
@@ -13387,7 +13852,7 @@ var WasmProcess = class {
|
|
|
13387
13852
|
const { guard: guard2 } = this.options;
|
|
13388
13853
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
13389
13854
|
if (!guard2 || inherited2 || req.pin !== void 0) return;
|
|
13390
|
-
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13855
|
+
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13391
13856
|
if (req.exclusive) return inParent(g, "open", req.path);
|
|
13392
13857
|
if (req.created && guard2.created?.take(req.path)) return;
|
|
13393
13858
|
const access2 = req.flags & WRITE_ACCESS;
|
|
@@ -13435,6 +13900,9 @@ var WasmProcess = class {
|
|
|
13435
13900
|
if (channel) channel.stamp = stamp;
|
|
13436
13901
|
}
|
|
13437
13902
|
}
|
|
13903
|
+
connectorStamp() {
|
|
13904
|
+
return this.sealedCaller();
|
|
13905
|
+
}
|
|
13438
13906
|
async sealedCaller() {
|
|
13439
13907
|
const shown = await this.options.identity?.();
|
|
13440
13908
|
const broker = this.options.sealed;
|
|
@@ -13443,7 +13911,7 @@ var WasmProcess = class {
|
|
|
13443
13911
|
}
|
|
13444
13912
|
guarded() {
|
|
13445
13913
|
const { guard: guard2 } = this.options;
|
|
13446
|
-
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13914
|
+
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13447
13915
|
}
|
|
13448
13916
|
ttyOwner() {
|
|
13449
13917
|
return { uid: this.cred.euid, gid: this.cred.egid, mode: TTY_MODE };
|
|
@@ -13773,7 +14241,8 @@ var WasmProcess = class {
|
|
|
13773
14241
|
net: this.net,
|
|
13774
14242
|
blocking: () => this.blockingSignal(cancelled),
|
|
13775
14243
|
resolve: (name2, family, blocking) => resolver.resolve(name2, family, blocking),
|
|
13776
|
-
cred: () => ({ pid: this.pid, uid: this.cred.euid, gid: this.cred.egid })
|
|
14244
|
+
cred: () => ({ pid: this.pid, uid: this.cred.euid, gid: this.cred.egid }),
|
|
14245
|
+
stamp: () => this.connectorStamp()
|
|
13777
14246
|
});
|
|
13778
14247
|
}
|
|
13779
14248
|
tty(fd) {
|
|
@@ -14169,6 +14638,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
14169
14638
|
umask,
|
|
14170
14639
|
cred,
|
|
14171
14640
|
...opts.owners ? { owners: true } : {},
|
|
14641
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
14172
14642
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
14173
14643
|
};
|
|
14174
14644
|
if (opts.program.abi === "js") {
|
|
@@ -14196,6 +14666,7 @@ function holdingToken(opts, holds, caller) {
|
|
|
14196
14666
|
return mintSyncFsToken({
|
|
14197
14667
|
...opts.owners ? caller : {},
|
|
14198
14668
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
14669
|
+
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
14199
14670
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
14200
14671
|
fs: opts.fs,
|
|
14201
14672
|
cwd: opts.cwd,
|
|
@@ -14209,6 +14680,9 @@ function holdingToken(opts, holds, caller) {
|
|
|
14209
14680
|
renamed: (from, to) => holds.renamed(from, to)
|
|
14210
14681
|
});
|
|
14211
14682
|
}
|
|
14683
|
+
function linksOf(opts) {
|
|
14684
|
+
return opts.links === void 0 ? {} : { links: opts.links };
|
|
14685
|
+
}
|
|
14212
14686
|
function clipboardName(opts) {
|
|
14213
14687
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
14214
14688
|
}
|
|
@@ -14220,7 +14694,7 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
14220
14694
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
14221
14695
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
14222
14696
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
14223
|
-
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
14697
|
+
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
14224
14698
|
...opts.identity ? { identity: opts.identity } : {},
|
|
14225
14699
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
14226
14700
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -14266,6 +14740,7 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
14266
14740
|
sab,
|
|
14267
14741
|
cred: copyCred(cred),
|
|
14268
14742
|
owners: opts.owners === true,
|
|
14743
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
14269
14744
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
14270
14745
|
thread,
|
|
14271
14746
|
signals: main
|
|
@@ -17566,6 +18041,9 @@ var SUDO_SOURCE = [
|
|
|
17566
18041
|
].join("\n");
|
|
17567
18042
|
|
|
17568
18043
|
// src/launcher.ts
|
|
18044
|
+
function linksOf2(req) {
|
|
18045
|
+
return req.links === void 0 ? {} : { links: req.links };
|
|
18046
|
+
}
|
|
17569
18047
|
var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
17570
18048
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
17571
18049
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
@@ -17741,6 +18219,7 @@ var Launcher = class {
|
|
|
17741
18219
|
warned = /* @__PURE__ */ new Set();
|
|
17742
18220
|
compiled = /* @__PURE__ */ new Map();
|
|
17743
18221
|
texts = /* @__PURE__ */ new Map();
|
|
18222
|
+
revocations = 0;
|
|
17744
18223
|
integrity;
|
|
17745
18224
|
scannedFs;
|
|
17746
18225
|
get scanned() {
|
|
@@ -17753,6 +18232,7 @@ var Launcher = class {
|
|
|
17753
18232
|
described = /* @__PURE__ */ new Map();
|
|
17754
18233
|
creds = /* @__PURE__ */ new Map();
|
|
17755
18234
|
tags = /* @__PURE__ */ new Map();
|
|
18235
|
+
links = /* @__PURE__ */ new Map();
|
|
17756
18236
|
freshModules = new FreshModules();
|
|
17757
18237
|
granted = /* @__PURE__ */ new Map();
|
|
17758
18238
|
users;
|
|
@@ -17766,6 +18246,7 @@ var Launcher = class {
|
|
|
17766
18246
|
);
|
|
17767
18247
|
net = new LoopbackNet();
|
|
17768
18248
|
cdp;
|
|
18249
|
+
facades;
|
|
17769
18250
|
ca;
|
|
17770
18251
|
transport;
|
|
17771
18252
|
uplink;
|
|
@@ -17840,10 +18321,16 @@ var Launcher = class {
|
|
|
17840
18321
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17841
18322
|
this.appended = appendedRoots(options.commands);
|
|
17842
18323
|
this.cdp = new CdpHosts(options.cdp);
|
|
18324
|
+
this.facades = new FacadeHosts(options.facades);
|
|
17843
18325
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17844
18326
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
17845
18327
|
this.hostname = hostname;
|
|
17846
|
-
this.env = {
|
|
18328
|
+
this.env = {
|
|
18329
|
+
...networkEnv(hostname),
|
|
18330
|
+
SLICC_CDP_URL: this.cdp.url,
|
|
18331
|
+
...this.facades.env(),
|
|
18332
|
+
...options.env
|
|
18333
|
+
};
|
|
17847
18334
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
17848
18335
|
this.transport = replayingHops(options.transport ?? missingTransport());
|
|
17849
18336
|
this.announcedTraits = JSON.stringify(this.transport.traits);
|
|
@@ -17858,6 +18345,7 @@ var Launcher = class {
|
|
|
17858
18345
|
ca: this.ca
|
|
17859
18346
|
});
|
|
17860
18347
|
enableCdp(this.net, this.cdp);
|
|
18348
|
+
this.facades.enable(this.net);
|
|
17861
18349
|
const fs = withCommandDirs(
|
|
17862
18350
|
this.base,
|
|
17863
18351
|
async () => new Set((await this.commands()).keys()),
|
|
@@ -18055,14 +18543,16 @@ var Launcher = class {
|
|
|
18055
18543
|
}
|
|
18056
18544
|
const path = this.fs.resolvePath(cwd, file);
|
|
18057
18545
|
const glue = await followLinks(this.base, path);
|
|
18058
|
-
const
|
|
18059
|
-
|
|
18060
|
-
|
|
18061
|
-
const
|
|
18546
|
+
const asked = glue === path ? {} : { asked: path };
|
|
18547
|
+
const linked2 = COMMAND2.exec(glue)?.[1];
|
|
18548
|
+
if (linked2 !== void 0) {
|
|
18549
|
+
const found = await this.resolve(`/bin/${linked2}`, argv0, cwd);
|
|
18550
|
+
const target = found && { ...found, ...asked };
|
|
18551
|
+
const byPath = !COMMAND2.test(path) && (await this.commands()).get(linked2)?.argv0Path === true;
|
|
18062
18552
|
return target && byPath ? { ...target, argv0: path } : target;
|
|
18063
18553
|
}
|
|
18064
18554
|
const own = await this.commandAt(glue, scope);
|
|
18065
|
-
if (own) return own.script ? void 0 : targetOf(own);
|
|
18555
|
+
if (own) return own.script ? void 0 : { ...targetOf(own), ...asked };
|
|
18066
18556
|
const head = await this.head(glue);
|
|
18067
18557
|
if (!head) return void 0;
|
|
18068
18558
|
if (isWasm(head)) {
|
|
@@ -18070,13 +18560,14 @@ var Launcher = class {
|
|
|
18070
18560
|
abi: "wasi",
|
|
18071
18561
|
glue,
|
|
18072
18562
|
wasm: glue,
|
|
18073
|
-
argv0: baseName(argv0 || file).replace(/\.wasm$/, "")
|
|
18563
|
+
argv0: baseName(argv0 || file).replace(/\.wasm$/, ""),
|
|
18564
|
+
...asked
|
|
18074
18565
|
};
|
|
18075
18566
|
}
|
|
18076
18567
|
if (interpreter(head) !== "node") return void 0;
|
|
18077
18568
|
const wasm = modulePath(glue);
|
|
18078
18569
|
if (!await this.base.exists(wasm)) return void 0;
|
|
18079
|
-
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file) };
|
|
18570
|
+
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file), ...asked };
|
|
18080
18571
|
}
|
|
18081
18572
|
async head(path) {
|
|
18082
18573
|
try {
|
|
@@ -18094,6 +18585,8 @@ var Launcher = class {
|
|
|
18094
18585
|
async interpreted(file, argv, cwd, scope, depth = 0) {
|
|
18095
18586
|
const command = await this.scriptCommand(file, cwd, scope);
|
|
18096
18587
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
18588
|
+
const byPath = command && file.includes("/") && !COMMAND2.test(file);
|
|
18589
|
+
const named = byPath ? { [script]: this.fs.resolvePath(cwd, file) } : {};
|
|
18097
18590
|
const head = await this.head(script);
|
|
18098
18591
|
if (!head) return void 0;
|
|
18099
18592
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
@@ -18116,7 +18609,8 @@ var Launcher = class {
|
|
|
18116
18609
|
target: withScriptEnv(inner.target, command),
|
|
18117
18610
|
via,
|
|
18118
18611
|
sources,
|
|
18119
|
-
...bins.length > 0 ? { bins } : {}
|
|
18612
|
+
...bins.length > 0 ? { bins } : {},
|
|
18613
|
+
asked: { ...inner.asked, ...named }
|
|
18120
18614
|
};
|
|
18121
18615
|
}
|
|
18122
18616
|
const target = withScriptEnv(found, command);
|
|
@@ -18125,7 +18619,8 @@ var Launcher = class {
|
|
|
18125
18619
|
args: [...target.prefix ?? [], ...passed],
|
|
18126
18620
|
via: [interp],
|
|
18127
18621
|
sources: [script],
|
|
18128
|
-
...command?.bin ? { bins: [script] } : {}
|
|
18622
|
+
...command?.bin ? { bins: [script] } : {},
|
|
18623
|
+
asked: named
|
|
18129
18624
|
};
|
|
18130
18625
|
}
|
|
18131
18626
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -18139,7 +18634,14 @@ var Launcher = class {
|
|
|
18139
18634
|
async mayExec(cred, req, planned) {
|
|
18140
18635
|
const { dac } = this;
|
|
18141
18636
|
if (!dac) return;
|
|
18142
|
-
const g = {
|
|
18637
|
+
const g = {
|
|
18638
|
+
fs: this.fs,
|
|
18639
|
+
cred,
|
|
18640
|
+
pid: req.pid,
|
|
18641
|
+
dac,
|
|
18642
|
+
tag: req.tag,
|
|
18643
|
+
links: this.links.get(req.pid)
|
|
18644
|
+
};
|
|
18143
18645
|
const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
|
|
18144
18646
|
if (byPath(req.file)) {
|
|
18145
18647
|
const path = this.fs.resolvePath(req.cwd, req.file);
|
|
@@ -18296,8 +18798,8 @@ var Launcher = class {
|
|
|
18296
18798
|
readFile: (path) => this.integrity ? this.text(path, KERNEL_CALLER) : fs.readFile(path)
|
|
18297
18799
|
});
|
|
18298
18800
|
}
|
|
18299
|
-
async cacheKey(path) {
|
|
18300
|
-
const verified = await this.integrity?.key(path);
|
|
18801
|
+
async cacheKey(path, asked) {
|
|
18802
|
+
const verified = await this.integrity?.key(path, asked);
|
|
18301
18803
|
if (verified !== void 0) return verified;
|
|
18302
18804
|
const st = await this.base.stat(path);
|
|
18303
18805
|
return `${path}:${st.size}:${st.mtime.getTime()}`;
|
|
@@ -18306,30 +18808,31 @@ var Launcher = class {
|
|
|
18306
18808
|
const plain = () => fs.readFileBuffer(path);
|
|
18307
18809
|
return this.integrity ? this.integrity.read(path, caller, plain) : plain();
|
|
18308
18810
|
}
|
|
18309
|
-
keyed(path, caller) {
|
|
18811
|
+
keyed(path, caller, asked) {
|
|
18310
18812
|
const plain = async () => this.base.readFileBuffer(path);
|
|
18311
|
-
return this.integrity ? this.integrity.readKeyed(path, caller, plain) : plain().then((bytes) => ({ bytes }));
|
|
18813
|
+
return this.integrity ? this.integrity.readKeyed(path, caller, plain, asked) : plain().then((bytes) => ({ bytes }));
|
|
18312
18814
|
}
|
|
18313
18815
|
cached(cache, key, load) {
|
|
18314
18816
|
const hit = cache.get(key);
|
|
18315
18817
|
if (hit !== void 0) return hit;
|
|
18818
|
+
const revocations = this.revocations;
|
|
18316
18819
|
const loading2 = load();
|
|
18317
18820
|
const found = loading2.then(({ value }) => value);
|
|
18318
18821
|
cache.set(key, found);
|
|
18319
|
-
|
|
18320
|
-
(
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
()
|
|
18326
|
-
);
|
|
18822
|
+
const drop = () => {
|
|
18823
|
+
if (cache.get(key) === found) cache.delete(key);
|
|
18824
|
+
};
|
|
18825
|
+
loading2.then((done4) => {
|
|
18826
|
+
if (done4.key === key || done4.key === void 0 && !key.includes("\0")) return;
|
|
18827
|
+
drop();
|
|
18828
|
+
if (done4.key !== void 0 && revocations === this.revocations) cache.set(done4.key, found);
|
|
18829
|
+
}, drop);
|
|
18327
18830
|
return found;
|
|
18328
18831
|
}
|
|
18329
|
-
async module(path, caller) {
|
|
18330
|
-
const key = await this.cacheKey(path);
|
|
18832
|
+
async module(path, caller, asked) {
|
|
18833
|
+
const key = await this.cacheKey(path, asked);
|
|
18331
18834
|
return this.cached(this.compiled, key, async () => {
|
|
18332
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18835
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18333
18836
|
const memory = importedMemory(bytes);
|
|
18334
18837
|
const foreign = foreignImports(bytes);
|
|
18335
18838
|
const compiled = await WebAssembly.compile(bytes);
|
|
@@ -18338,22 +18841,30 @@ var Launcher = class {
|
|
|
18338
18841
|
}
|
|
18339
18842
|
async checkedSources(planned, caller) {
|
|
18340
18843
|
const { target } = planned;
|
|
18341
|
-
const files = [
|
|
18844
|
+
const files = [
|
|
18845
|
+
target.wasm,
|
|
18846
|
+
target.glue,
|
|
18847
|
+
target.imports,
|
|
18848
|
+
target.asked,
|
|
18849
|
+
...planned.sources ?? []
|
|
18850
|
+
];
|
|
18342
18851
|
const manifests = /* @__PURE__ */ new Set();
|
|
18343
18852
|
for (const file of files) {
|
|
18344
18853
|
const root = file === void 0 ? void 0 : PACKAGE_ROOT.exec(file)?.[1];
|
|
18345
18854
|
if (root !== void 0) manifests.add(`${root}/package.json`);
|
|
18346
18855
|
}
|
|
18347
|
-
for (const source of planned.sources ?? [])
|
|
18856
|
+
for (const source of planned.sources ?? []) {
|
|
18857
|
+
await this.text(source, caller, planned.asked?.[source]);
|
|
18858
|
+
}
|
|
18348
18859
|
for (const manifest of manifests) {
|
|
18349
18860
|
if (await this.base.exists(manifest)) await this.text(manifest, caller);
|
|
18350
18861
|
}
|
|
18351
18862
|
}
|
|
18352
|
-
async text(path, caller) {
|
|
18863
|
+
async text(path, caller, asked) {
|
|
18353
18864
|
if (!this.integrity) return this.base.readFile(path);
|
|
18354
|
-
const key = await this.cacheKey(path);
|
|
18865
|
+
const key = await this.cacheKey(path, asked);
|
|
18355
18866
|
return this.cached(this.texts, key, async () => {
|
|
18356
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18867
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18357
18868
|
return { value: new TextDecoder().decode(bytes), key: read };
|
|
18358
18869
|
});
|
|
18359
18870
|
}
|
|
@@ -18370,17 +18881,18 @@ var Launcher = class {
|
|
|
18370
18881
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
18371
18882
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
18372
18883
|
}
|
|
18884
|
+
const { asked } = target;
|
|
18373
18885
|
if (target.abi === "js") {
|
|
18374
|
-
return { abi: "js", glue: await this.text(target.wasm, caller), path: target.wasm };
|
|
18886
|
+
return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
|
|
18375
18887
|
}
|
|
18376
18888
|
if (target.abi !== "wasi") {
|
|
18377
18889
|
const [glue, { module: module2 }] = await Promise.all([
|
|
18378
|
-
this.text(target.glue, caller),
|
|
18379
|
-
this.module(target.wasm, caller)
|
|
18890
|
+
this.text(target.glue, caller, asked),
|
|
18891
|
+
this.module(target.wasm, caller, asked && modulePath(asked))
|
|
18380
18892
|
]);
|
|
18381
18893
|
return { glue, module: module2 };
|
|
18382
18894
|
}
|
|
18383
|
-
const { module, memory, foreign } = await this.module(target.wasm, caller);
|
|
18895
|
+
const { module, memory, foreign } = await this.module(target.wasm, caller, asked);
|
|
18384
18896
|
const names = env.SLICC_WASM_BACKTRACE === "1" ? await this.names(target.wasm, module) : void 0;
|
|
18385
18897
|
const imports = target.imports ? await this.text(target.imports, caller) : void 0;
|
|
18386
18898
|
return {
|
|
@@ -18421,6 +18933,10 @@ var Launcher = class {
|
|
|
18421
18933
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18422
18934
|
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
18423
18935
|
}
|
|
18936
|
+
marks(pid, req) {
|
|
18937
|
+
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
18938
|
+
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
18939
|
+
}
|
|
18424
18940
|
start(req) {
|
|
18425
18941
|
this.sampling();
|
|
18426
18942
|
if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
|
|
@@ -18453,6 +18969,7 @@ var Launcher = class {
|
|
|
18453
18969
|
cred: req.cred,
|
|
18454
18970
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
18455
18971
|
...this.owners ? { owners: true } : {},
|
|
18972
|
+
...linksOf2(req),
|
|
18456
18973
|
sealed: this.sealed,
|
|
18457
18974
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
18458
18975
|
clipboard: this.clipboard,
|
|
@@ -18500,7 +19017,7 @@ var Launcher = class {
|
|
|
18500
19017
|
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18501
19018
|
const { cred } = req;
|
|
18502
19019
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
18503
|
-
|
|
19020
|
+
this.marks(pid, req);
|
|
18504
19021
|
if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
|
|
18505
19022
|
this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
|
|
18506
19023
|
if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
|
|
@@ -18553,6 +19070,7 @@ var Launcher = class {
|
|
|
18553
19070
|
this.childTimes.delete(pid);
|
|
18554
19071
|
this.creds.delete(pid);
|
|
18555
19072
|
this.tags.delete(pid);
|
|
19073
|
+
this.links.delete(pid);
|
|
18556
19074
|
this.granted.delete(pid);
|
|
18557
19075
|
}
|
|
18558
19076
|
reaped(pid, parent) {
|
|
@@ -18728,6 +19246,7 @@ var Launcher = class {
|
|
|
18728
19246
|
umask: this.umaskOf(ppid),
|
|
18729
19247
|
cred,
|
|
18730
19248
|
tag: this.tagOf(ppid),
|
|
19249
|
+
links: grant ? grant.cred.euid : this.links.get(ppid),
|
|
18731
19250
|
...group,
|
|
18732
19251
|
...exec
|
|
18733
19252
|
});
|
|
@@ -18760,6 +19279,9 @@ var Launcher = class {
|
|
|
18760
19279
|
}
|
|
18761
19280
|
};
|
|
18762
19281
|
}
|
|
19282
|
+
connectorStamp(pid) {
|
|
19283
|
+
return this.sealed.stamp(this.identityOf(pid), this.credOf(pid), this.tagOf(pid));
|
|
19284
|
+
}
|
|
18763
19285
|
identityOf(pid) {
|
|
18764
19286
|
const parent = this.jobs.shownParent(pid);
|
|
18765
19287
|
const alive = parent !== void 0 && this.running(parent);
|
|
@@ -18789,7 +19311,8 @@ var Launcher = class {
|
|
|
18789
19311
|
blocked: this.blockedBy(ppid),
|
|
18790
19312
|
umask: this.umaskOf(ppid),
|
|
18791
19313
|
cred: this.credOf(ppid),
|
|
18792
|
-
tag: this.tagOf(ppid)
|
|
19314
|
+
tag: this.tagOf(ppid),
|
|
19315
|
+
links: this.links.get(ppid)
|
|
18793
19316
|
})
|
|
18794
19317
|
);
|
|
18795
19318
|
}
|
|
@@ -18969,6 +19492,23 @@ var Launcher = class {
|
|
|
18969
19492
|
}
|
|
18970
19493
|
};
|
|
18971
19494
|
}
|
|
19495
|
+
async revokeIntegrity(path) {
|
|
19496
|
+
if (path !== void 0 && (typeof path !== "string" || !path.startsWith("/"))) {
|
|
19497
|
+
throw new TypeError("integrity.revoke takes an absolute path");
|
|
19498
|
+
}
|
|
19499
|
+
if (!this.integrity) return;
|
|
19500
|
+
const at = path === void 0 ? void 0 : normalizePath(path);
|
|
19501
|
+
const real = at && await this.base.realpath?.(at, true).catch(() => void 0);
|
|
19502
|
+
const roots = [at, real].filter((p) => p !== void 0);
|
|
19503
|
+
this.revocations++;
|
|
19504
|
+
const hit = (key) => key.includes("\0") && (at === void 0 || key.split("\0").slice(0, 2).some((part) => isProtected(roots, part)));
|
|
19505
|
+
for (const cache of [this.compiled, this.texts]) {
|
|
19506
|
+
for (const key of [...cache.keys()]) if (hit(key)) cache.delete(key);
|
|
19507
|
+
}
|
|
19508
|
+
if (at === void 0) this.integrity.forget();
|
|
19509
|
+
for (const root of roots) this.integrity.forget(root);
|
|
19510
|
+
this.resetCatalogs();
|
|
19511
|
+
}
|
|
18972
19512
|
attest(path) {
|
|
18973
19513
|
return attest(this.rootFs, path, {
|
|
18974
19514
|
users: this.usersMode,
|
|
@@ -19413,6 +19953,20 @@ function cdpOption(req, port) {
|
|
|
19413
19953
|
)
|
|
19414
19954
|
};
|
|
19415
19955
|
}
|
|
19956
|
+
function pageHooks(req, port) {
|
|
19957
|
+
return { ...cdpOption(req, port), ...facadesOption(req, port) };
|
|
19958
|
+
}
|
|
19959
|
+
function facadesOption(req, port) {
|
|
19960
|
+
if (!req.facades) return {};
|
|
19961
|
+
const hook = portFacadeHook(
|
|
19962
|
+
(request2, facade) => port.postMessage({ facadeOpen: request2, port: facade }, [facade])
|
|
19963
|
+
);
|
|
19964
|
+
const facades = {};
|
|
19965
|
+
for (const [name2, spec] of Object.entries(req.facades)) {
|
|
19966
|
+
facades[name2] = { port: spec.port, ...spec.hook ? { hook } : {} };
|
|
19967
|
+
}
|
|
19968
|
+
return { facades };
|
|
19969
|
+
}
|
|
19416
19970
|
function remotes(port, req) {
|
|
19417
19971
|
return {
|
|
19418
19972
|
...req.transport ? { transport: new RemoteTransport(port, req.transport) } : {},
|
|
@@ -19466,7 +20020,8 @@ var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
|
19466
20020
|
"attest",
|
|
19467
20021
|
"watch-files",
|
|
19468
20022
|
"unwatch-files",
|
|
19469
|
-
"chmod"
|
|
20023
|
+
"chmod",
|
|
20024
|
+
"integrity-revoke"
|
|
19470
20025
|
]);
|
|
19471
20026
|
function isAttestRequest(req) {
|
|
19472
20027
|
return ATTEST_OPS.has(req.op);
|
|
@@ -19484,6 +20039,7 @@ function attestOps(port) {
|
|
|
19484
20039
|
return async (l, req) => {
|
|
19485
20040
|
if (req.op === "attest") return l.attest(req.path);
|
|
19486
20041
|
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
20042
|
+
if (req.op === "integrity-revoke") return l.revokeIntegrity(req.path).then(() => true);
|
|
19487
20043
|
if (req.op === "unwatch-files") {
|
|
19488
20044
|
watches.get(req.watch)?.();
|
|
19489
20045
|
return watches.delete(req.watch);
|
|
@@ -19624,7 +20180,7 @@ function serveKernel(port, deps) {
|
|
|
19624
20180
|
...media ? { media } : {},
|
|
19625
20181
|
onMountPending: (medium) => port.postMessage({ medium }),
|
|
19626
20182
|
...req.hostfs ? { hostfs: askGrant } : {},
|
|
19627
|
-
...
|
|
20183
|
+
...pageHooks(req, port),
|
|
19628
20184
|
...mountPolicy(req.processMounts),
|
|
19629
20185
|
caStore: caStore(deps.metadata ? caDb(req) : false)
|
|
19630
20186
|
});
|