@ai-ecoverse/slicc-kernel 1.56.1 → 1.57.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 +20 -4
- package/dist/driver-worker.js +1 -0
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +5 -2
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +336 -64
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +1 -0
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +94 -21
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +333 -64
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +94 -21
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -1753,12 +1753,30 @@ function userEnv(account, system) {
|
|
|
1753
1753
|
PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
|
|
1754
1754
|
};
|
|
1755
1755
|
}
|
|
1756
|
+
function homeGroupOf(groups, name2) {
|
|
1757
|
+
if (name2 === void 0) return void 0;
|
|
1758
|
+
const found = groups.find((g) => g.name === name2);
|
|
1759
|
+
if (!found) throw fsError("ENOENT", `no group ${name2}`);
|
|
1760
|
+
return found;
|
|
1761
|
+
}
|
|
1756
1762
|
var UserDb = class {
|
|
1757
1763
|
fs;
|
|
1764
|
+
owners;
|
|
1758
1765
|
umasks = /* @__PURE__ */ new Map();
|
|
1759
1766
|
writing = Promise.resolve();
|
|
1760
|
-
constructor(fs) {
|
|
1767
|
+
constructor(fs, owners = false) {
|
|
1761
1768
|
this.fs = fs;
|
|
1769
|
+
this.owners = owners;
|
|
1770
|
+
}
|
|
1771
|
+
async stampHome(row, shared) {
|
|
1772
|
+
const home = this.fs.resolvePath("/", row.home);
|
|
1773
|
+
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
1774
|
+
if (await this.fs.realpath?.(home, false).catch(() => void 0) !== home) return;
|
|
1775
|
+
if (!(await this.fs.lstat(home)).isDirectory) return;
|
|
1776
|
+
const gid = shared?.gid ?? row.gid;
|
|
1777
|
+
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
1778
|
+
const mode = shared ? 1512 : row.name.startsWith("scoop-") ? 488 : 448;
|
|
1779
|
+
await this.fs.chmod(home, mode);
|
|
1762
1780
|
}
|
|
1763
1781
|
async read(path, fallback) {
|
|
1764
1782
|
try {
|
|
@@ -1858,8 +1876,12 @@ var UserDb = class {
|
|
|
1858
1876
|
const users = parsed(passwd);
|
|
1859
1877
|
const groups = parsed(group);
|
|
1860
1878
|
const found = users.find((r) => r.name === name2);
|
|
1879
|
+
const shared = homeGroupOf(groups, options.homeGroup);
|
|
1861
1880
|
if (found) {
|
|
1862
|
-
if (found.uid >= FIRST_UID && found.uid <= LAST_UID)
|
|
1881
|
+
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
1882
|
+
await this.provision(found);
|
|
1883
|
+
await this.stampHome(found, shared);
|
|
1884
|
+
}
|
|
1863
1885
|
remember();
|
|
1864
1886
|
return this.account(found, groups);
|
|
1865
1887
|
}
|
|
@@ -1879,6 +1901,7 @@ var UserDb = class {
|
|
|
1879
1901
|
await this.fs.mkdir(home, { recursive: true });
|
|
1880
1902
|
try {
|
|
1881
1903
|
await this.provision(row);
|
|
1904
|
+
await this.stampHome(row, shared);
|
|
1882
1905
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
1883
1906
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
1884
1907
|
} catch (err) {
|
|
@@ -1974,7 +1997,7 @@ async function realpath(fs, path) {
|
|
|
1974
1997
|
}
|
|
1975
1998
|
return resolved || "/";
|
|
1976
1999
|
}
|
|
1977
|
-
async function fsCall(fs, method, args) {
|
|
2000
|
+
async function fsCall(fs, method, args, owner) {
|
|
1978
2001
|
const path = (i) => fs.resolvePath("/", String(args[i]));
|
|
1979
2002
|
switch (method) {
|
|
1980
2003
|
case "readFile": {
|
|
@@ -1982,7 +2005,7 @@ async function fsCall(fs, method, args) {
|
|
|
1982
2005
|
return { result: bytes, transfer: [bytes.buffer] };
|
|
1983
2006
|
}
|
|
1984
2007
|
case "writeFile":
|
|
1985
|
-
await fs.writeFile(path(0), args[1]);
|
|
2008
|
+
await fs.writeFile(path(0), args[1], owner);
|
|
1986
2009
|
return { result: true };
|
|
1987
2010
|
case "stat":
|
|
1988
2011
|
return { result: await fs.stat(path(0)) };
|
|
@@ -1991,7 +2014,7 @@ async function fsCall(fs, method, args) {
|
|
|
1991
2014
|
case "readdir":
|
|
1992
2015
|
return { result: await fs.readdir(path(0)) };
|
|
1993
2016
|
case "mkdir":
|
|
1994
|
-
await fs.mkdir(path(0), { recursive: true });
|
|
2017
|
+
await fs.mkdir(path(0), owner ? { recursive: true, owner } : { recursive: true });
|
|
1995
2018
|
return { result: true };
|
|
1996
2019
|
case "rm":
|
|
1997
2020
|
await fs.rm(path(0), { recursive: true, force: args[1] === true });
|
|
@@ -2002,7 +2025,7 @@ async function fsCall(fs, method, args) {
|
|
|
2002
2025
|
case "realpath":
|
|
2003
2026
|
return { result: await realpath(fs, String(args[0])) };
|
|
2004
2027
|
case "symlink":
|
|
2005
|
-
await fs.symlink(String(args[0]), path(1));
|
|
2028
|
+
await fs.symlink(String(args[0]), path(1), owner);
|
|
2006
2029
|
return { result: true };
|
|
2007
2030
|
case "readlink":
|
|
2008
2031
|
return { result: await fs.readlink(path(0)) };
|
|
@@ -2024,6 +2047,9 @@ function dialFor(l, req, open) {
|
|
|
2024
2047
|
);
|
|
2025
2048
|
return { result: port2, transfer: [port2] };
|
|
2026
2049
|
}
|
|
2050
|
+
function ownerFor(l, self) {
|
|
2051
|
+
return l.owners && self ? { uid: self.uid, gid: self.gid } : void 0;
|
|
2052
|
+
}
|
|
2027
2053
|
async function accountOf(l, user) {
|
|
2028
2054
|
const found = await l.users.lookup(user);
|
|
2029
2055
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
@@ -2151,6 +2177,7 @@ function serveClient(port, host) {
|
|
|
2151
2177
|
hello: {
|
|
2152
2178
|
protocol: PROTOCOL,
|
|
2153
2179
|
traits: transport.traits,
|
|
2180
|
+
...launcher.usersMode ? { users: launcher.usersMode } : {},
|
|
2154
2181
|
...host.lock ? { lock: host.lock } : {}
|
|
2155
2182
|
}
|
|
2156
2183
|
});
|
|
@@ -2216,7 +2243,7 @@ function serveClient(port, host) {
|
|
|
2216
2243
|
if (!FS_METHODS.includes(req.method)) {
|
|
2217
2244
|
throw new Error(`unknown file system call ${req.method}`);
|
|
2218
2245
|
}
|
|
2219
|
-
return fsCall(l.fs, req.method, req.args);
|
|
2246
|
+
return fsCall(l.fs, req.method, req.args, ownerFor(l, self));
|
|
2220
2247
|
case "watch":
|
|
2221
2248
|
case "unwatch":
|
|
2222
2249
|
return watchOp(l, req, watches, send);
|
|
@@ -2324,11 +2351,69 @@ var MemoryMeta = class {
|
|
|
2324
2351
|
}
|
|
2325
2352
|
};
|
|
2326
2353
|
|
|
2354
|
+
// src/fs/owners.ts
|
|
2355
|
+
var ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
|
|
2356
|
+
var S_ISUID = 2048;
|
|
2357
|
+
var S_ISGID = 1024;
|
|
2358
|
+
var S_IXGRP = 8;
|
|
2359
|
+
function ownOf(entry) {
|
|
2360
|
+
if (entry?.uid === void 0 || entry.gid === void 0) return void 0;
|
|
2361
|
+
return { uid: entry.uid, gid: entry.gid };
|
|
2362
|
+
}
|
|
2363
|
+
function handedBy(entry) {
|
|
2364
|
+
return entry?.heir ? { uid: entry.heir[0], gid: entry.heir[1] } : ownOf(entry);
|
|
2365
|
+
}
|
|
2366
|
+
function inherit(entries) {
|
|
2367
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2368
|
+
const found = handedBy(entries[i]);
|
|
2369
|
+
if (found) return found;
|
|
2370
|
+
}
|
|
2371
|
+
return { ...ROOT_OWNER };
|
|
2372
|
+
}
|
|
2373
|
+
function chain(path) {
|
|
2374
|
+
const parts = path.split("/").filter(Boolean);
|
|
2375
|
+
return ["/", ...parts.map((_, i) => `/${parts.slice(0, i + 1).join("/")}`)];
|
|
2376
|
+
}
|
|
2377
|
+
function sameOwner(a, b) {
|
|
2378
|
+
return a.uid === b.uid && a.gid === b.gid;
|
|
2379
|
+
}
|
|
2380
|
+
function ownerOf(cred, mode) {
|
|
2381
|
+
return { uid: cred.euid, gid: cred.egid, ...mode !== void 0 ? { mode } : {} };
|
|
2382
|
+
}
|
|
2383
|
+
function inGroup(cred, gid) {
|
|
2384
|
+
return cred.egid === gid || cred.groups.includes(gid);
|
|
2385
|
+
}
|
|
2386
|
+
function mayChown(cred, current, uid, gid) {
|
|
2387
|
+
if (cred.euid === 0) return true;
|
|
2388
|
+
const owner = cred.euid === current.uid;
|
|
2389
|
+
if (uid !== void 0 && !(owner && uid === current.uid)) return false;
|
|
2390
|
+
if (gid !== void 0 && !(owner && (gid === current.gid || inGroup(cred, gid)))) return false;
|
|
2391
|
+
return true;
|
|
2392
|
+
}
|
|
2393
|
+
function clearedSetId(mode) {
|
|
2394
|
+
const bits2 = S_ISUID | (mode & S_IXGRP ? S_ISGID : 0);
|
|
2395
|
+
return mode & 4095 & ~bits2;
|
|
2396
|
+
}
|
|
2397
|
+
async function chownAs(fs, cred, path, change) {
|
|
2398
|
+
const { uid, gid, follow: follow2 } = change;
|
|
2399
|
+
const st = follow2 ? await fs.stat(path) : await fs.lstat(path);
|
|
2400
|
+
const current = { uid: st.uid ?? 0, gid: st.gid ?? 0 };
|
|
2401
|
+
if (!fs.chown || !mayChown(cred, current, uid, gid)) throw fsError("EPERM", path);
|
|
2402
|
+
const clear = st.isFile && (uid !== void 0 || gid !== void 0) ? clearedSetId(st.mode) : void 0;
|
|
2403
|
+
await fs.chown(path, {
|
|
2404
|
+
...uid !== void 0 ? { uid } : {},
|
|
2405
|
+
...gid !== void 0 ? { gid } : {},
|
|
2406
|
+
follow: follow2,
|
|
2407
|
+
...clear !== void 0 && clear !== (st.mode & 4095) ? { mode: clear } : {}
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2327
2411
|
// src/fs/opfs.ts
|
|
2328
2412
|
var S_IFDIR = 16384;
|
|
2329
2413
|
var S_IFREG = 32768;
|
|
2330
2414
|
var S_IFLNK = 40960;
|
|
2331
2415
|
var PERM_MASK = 4095;
|
|
2416
|
+
var S_ISGID2 = 1024;
|
|
2332
2417
|
var READ_ATTEMPTS = 3;
|
|
2333
2418
|
var MAX_LINKS2 = 40;
|
|
2334
2419
|
var CHECK_MS = 1e3;
|
|
@@ -2426,6 +2511,7 @@ var OpfsFs = class {
|
|
|
2426
2511
|
checked = /* @__PURE__ */ new WeakMap();
|
|
2427
2512
|
channel;
|
|
2428
2513
|
ranged;
|
|
2514
|
+
owners = false;
|
|
2429
2515
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
2430
2516
|
this.root = root;
|
|
2431
2517
|
this.meta = meta;
|
|
@@ -2445,6 +2531,73 @@ var OpfsFs = class {
|
|
|
2445
2531
|
resolvePath(base, path) {
|
|
2446
2532
|
return resolvePath(base, path);
|
|
2447
2533
|
}
|
|
2534
|
+
trackOwners() {
|
|
2535
|
+
this.owners = true;
|
|
2536
|
+
}
|
|
2537
|
+
async handedTo(dir) {
|
|
2538
|
+
return inherit(await this.meta.get(chain(dir)));
|
|
2539
|
+
}
|
|
2540
|
+
async ownerAt(path, entry) {
|
|
2541
|
+
const own = ownOf(entry);
|
|
2542
|
+
if (own) return own;
|
|
2543
|
+
return path === "/" ? { ...ROOT_OWNER } : this.handedTo(parentOf2(path));
|
|
2544
|
+
}
|
|
2545
|
+
async owned(stat, path, entry) {
|
|
2546
|
+
return this.owners ? { ...stat, ...await this.ownerAt(path, entry) } : stat;
|
|
2547
|
+
}
|
|
2548
|
+
async newFields(path, owner, directory) {
|
|
2549
|
+
if (!this.owners || !owner) return void 0;
|
|
2550
|
+
const entries = await this.meta.get(chain(path));
|
|
2551
|
+
const self = entries.pop();
|
|
2552
|
+
const parent = entries.at(-1);
|
|
2553
|
+
const setgid = ((parent?.mode ?? 0) & S_ISGID2) !== 0;
|
|
2554
|
+
const parentGid = (ownOf(parent) ?? inherit(entries.slice(0, -1))).gid;
|
|
2555
|
+
const want = { uid: owner.uid, gid: setgid ? parentGid : owner.gid };
|
|
2556
|
+
let mode = owner.mode === void 0 ? void 0 : owner.mode & PERM_MASK;
|
|
2557
|
+
if (directory && setgid) mode = (mode ?? 493) | S_ISGID2;
|
|
2558
|
+
const fields = {};
|
|
2559
|
+
if (mode !== void 0 && mode !== (this.mode(path, directory, void 0) & PERM_MASK)) {
|
|
2560
|
+
fields.mode = mode;
|
|
2561
|
+
}
|
|
2562
|
+
if (self) fields.heir = void 0;
|
|
2563
|
+
if (ownOf(self) || !sameOwner(want, inherit(entries))) Object.assign(fields, want);
|
|
2564
|
+
return Object.keys(fields).length > 0 ? fields : void 0;
|
|
2565
|
+
}
|
|
2566
|
+
async stampNew(path, owner, directory) {
|
|
2567
|
+
const fields = await this.newFields(path, owner, directory);
|
|
2568
|
+
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
2569
|
+
}
|
|
2570
|
+
async chown(path, change) {
|
|
2571
|
+
if (!this.owners) return;
|
|
2572
|
+
if (change.kind === "new") {
|
|
2573
|
+
const at = resolvePath((await this.locate(parentOf2(path), true)).path, baseOf(path));
|
|
2574
|
+
const { uid = 0, gid = 0, mode } = change;
|
|
2575
|
+
return this.stampNew(at, { uid, gid, ...mode !== void 0 ? { mode } : {} }, false);
|
|
2576
|
+
}
|
|
2577
|
+
const found = await this.locate(path, change.follow !== false);
|
|
2578
|
+
const [stored] = found.link ? [found.link] : await this.meta.get([found.path]);
|
|
2579
|
+
const current = await this.ownerAt(found.path, stored);
|
|
2580
|
+
const next2 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
|
|
2581
|
+
const handing = found.handle?.kind === "directory" && !sameOwner(next2, current);
|
|
2582
|
+
const heir = change.kind === "adopt" ? void 0 : stored?.heir ?? (handing ? [current.uid, current.gid] : void 0);
|
|
2583
|
+
const ctimeMs = Date.now();
|
|
2584
|
+
await this.meta.update(found.path, (entry) => {
|
|
2585
|
+
const { heir: _, ...rest2 } = entry ?? found.link ?? { path: found.path };
|
|
2586
|
+
return {
|
|
2587
|
+
...rest2,
|
|
2588
|
+
path: found.path,
|
|
2589
|
+
...next2,
|
|
2590
|
+
...heir ? { heir } : {},
|
|
2591
|
+
...change.mode !== void 0 ? { mode: change.mode & PERM_MASK } : {},
|
|
2592
|
+
ctimeMs
|
|
2593
|
+
};
|
|
2594
|
+
});
|
|
2595
|
+
}
|
|
2596
|
+
async movedOwner(source) {
|
|
2597
|
+
if (!this.owners) return void 0;
|
|
2598
|
+
const [stored] = source.link ? [source.link] : await this.meta.get([source.path]);
|
|
2599
|
+
return ownOf(stored) ? void 0 : this.ownerAt(source.path, stored);
|
|
2600
|
+
}
|
|
2448
2601
|
async walk(parts, from, start2) {
|
|
2449
2602
|
let dir = start2;
|
|
2450
2603
|
for (let at = from; at < parts.length; at++) {
|
|
@@ -2542,12 +2695,34 @@ var OpfsFs = class {
|
|
|
2542
2695
|
const link2 = await this.linkAlong(current);
|
|
2543
2696
|
if (!link2) throw err;
|
|
2544
2697
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
2545
|
-
const
|
|
2546
|
-
current =
|
|
2698
|
+
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
2699
|
+
current = target.split("/").includes("..") ? await this.physical(parentOf2(link2.path), target, hops + 1) : resolvePath(parentOf2(link2.path), target);
|
|
2547
2700
|
}
|
|
2548
2701
|
}
|
|
2549
2702
|
throw fsError("ELOOP", path);
|
|
2550
2703
|
}
|
|
2704
|
+
async physical(base, path, used) {
|
|
2705
|
+
let done4 = [];
|
|
2706
|
+
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
2707
|
+
for (let hops = used; todo.length > 0; ) {
|
|
2708
|
+
const part = todo.shift();
|
|
2709
|
+
if (part === "..") done4.pop();
|
|
2710
|
+
else if (!todo.includes("..")) done4.push(part);
|
|
2711
|
+
else {
|
|
2712
|
+
const at = `/${[...done4, part].join("/")}`;
|
|
2713
|
+
const st = await this.lstat(at);
|
|
2714
|
+
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
2715
|
+
if (!st.isSymbolicLink) done4.push(part);
|
|
2716
|
+
else if (++hops > MAX_LINKS2) throw fsError("ELOOP", path);
|
|
2717
|
+
else {
|
|
2718
|
+
const link2 = await this.readlink(at);
|
|
2719
|
+
if (link2.startsWith("/")) done4 = [];
|
|
2720
|
+
todo = [...link2.split("/").filter((p) => p !== "" && p !== "."), ...todo];
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
return `/${done4.join("/")}`;
|
|
2725
|
+
}
|
|
2551
2726
|
mode(path, directory, meta) {
|
|
2552
2727
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
2553
2728
|
return (directory ? S_IFDIR : S_IFREG) | (meta?.mode ?? fallback);
|
|
@@ -2615,9 +2790,15 @@ var OpfsFs = class {
|
|
|
2615
2790
|
};
|
|
2616
2791
|
}
|
|
2617
2792
|
async describe(found) {
|
|
2618
|
-
if (found.link) return this.linkStat(found.link);
|
|
2619
|
-
|
|
2620
|
-
|
|
2793
|
+
if (found.link) return this.owned(this.linkStat(found.link), found.path, found.link);
|
|
2794
|
+
if (!this.owners) {
|
|
2795
|
+
const [meta2] = await this.meta.get([found.path]);
|
|
2796
|
+
return this.statOf(found.path, found.handle, meta2);
|
|
2797
|
+
}
|
|
2798
|
+
const entries = await this.meta.get(chain(found.path));
|
|
2799
|
+
const meta = entries.pop();
|
|
2800
|
+
const stat = await this.statOf(found.path, found.handle, meta);
|
|
2801
|
+
return { ...stat, ...ownOf(meta) ?? inherit(entries) };
|
|
2621
2802
|
}
|
|
2622
2803
|
async stat(path) {
|
|
2623
2804
|
return this.describe(await this.locate(path, true));
|
|
@@ -2707,14 +2888,15 @@ var OpfsFs = class {
|
|
|
2707
2888
|
(parent) => parent.getFileHandle(name2, { create: true })
|
|
2708
2889
|
);
|
|
2709
2890
|
if (!existed) this.touch(parentOf2(target));
|
|
2710
|
-
return [handle, existed];
|
|
2891
|
+
return [handle, existed, target];
|
|
2711
2892
|
} catch (err) {
|
|
2712
2893
|
const code = err?.name === "TypeMismatchError" ? "EISDIR" : null;
|
|
2713
2894
|
throw code ? fsError(code, path) : translate(err, path);
|
|
2714
2895
|
}
|
|
2715
2896
|
}
|
|
2716
|
-
async writeFile(path, content) {
|
|
2717
|
-
const [file, existed] = await this.fileFor(path);
|
|
2897
|
+
async writeFile(path, content, owner) {
|
|
2898
|
+
const [file, existed, target] = await this.fileFor(path);
|
|
2899
|
+
if (!existed) await this.stampNew(target, owner, false);
|
|
2718
2900
|
if (!existed && content.length === 0) return;
|
|
2719
2901
|
const writable = await file.createWritable();
|
|
2720
2902
|
await writable.write(content);
|
|
@@ -2739,11 +2921,13 @@ var OpfsFs = class {
|
|
|
2739
2921
|
const [dir, children2] = await this.listing(path);
|
|
2740
2922
|
const base = dir === "/" ? "" : dir;
|
|
2741
2923
|
const metas = await this.meta.get(children2.map(([name2]) => `${base}/${name2}`));
|
|
2924
|
+
const handed2 = this.owners ? await this.handedTo(dir) : void 0;
|
|
2925
|
+
const owned = (stat, entry) => handed2 ? { ...stat, ...ownOf(entry) ?? handed2 } : stat;
|
|
2742
2926
|
return Promise.all(
|
|
2743
2927
|
children2.map(async ([name2, child], i) => {
|
|
2744
|
-
if (!isHandle(child)) return [name2, this.linkStat(child)];
|
|
2928
|
+
if (!isHandle(child)) return [name2, owned(this.linkStat(child), child)];
|
|
2745
2929
|
const stat = await this.statOf(`${base}/${name2}`, child, metas[i]).catch(() => null);
|
|
2746
|
-
return [name2, stat];
|
|
2930
|
+
return [name2, stat && owned(stat, metas[i])];
|
|
2747
2931
|
})
|
|
2748
2932
|
);
|
|
2749
2933
|
}
|
|
@@ -2761,11 +2945,22 @@ var OpfsFs = class {
|
|
|
2761
2945
|
}
|
|
2762
2946
|
const [entry] = await this.meta.get([path]);
|
|
2763
2947
|
if (entry?.link !== void 0) throw fsError("EEXIST", path);
|
|
2764
|
-
|
|
2948
|
+
const { owner } = options;
|
|
2949
|
+
if (options.recursive) {
|
|
2950
|
+
const mode = owner?.parents;
|
|
2951
|
+
const above = owner && {
|
|
2952
|
+
uid: owner.uid,
|
|
2953
|
+
gid: owner.gid,
|
|
2954
|
+
...mode ? { mode, parents: mode } : {}
|
|
2955
|
+
};
|
|
2956
|
+
await this.mkdir(parentOf2(path), { recursive: true, ...above ? { owner: above } : {} });
|
|
2957
|
+
}
|
|
2765
2958
|
const parent = await this.locate(parentOf2(path), true);
|
|
2766
2959
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
2767
2960
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
2768
|
-
|
|
2961
|
+
const made = `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`;
|
|
2962
|
+
await this.stampNew(made, owner, true);
|
|
2963
|
+
this.touch(parent.path, made);
|
|
2769
2964
|
}
|
|
2770
2965
|
async rm(path, options = {}) {
|
|
2771
2966
|
let found;
|
|
@@ -2812,9 +3007,11 @@ var OpfsFs = class {
|
|
|
2812
3007
|
throw fsError("ENOTEMPTY", to);
|
|
2813
3008
|
}
|
|
2814
3009
|
const now = Date.now();
|
|
3010
|
+
const moving = await this.movedOwner(source);
|
|
2815
3011
|
const carry = (entry) => ({
|
|
2816
3012
|
ino: inodeOf(source.path),
|
|
2817
3013
|
...entry,
|
|
3014
|
+
...moving,
|
|
2818
3015
|
path: destination,
|
|
2819
3016
|
ctimeMs: now
|
|
2820
3017
|
});
|
|
@@ -2888,7 +3085,7 @@ var OpfsFs = class {
|
|
|
2888
3085
|
const target = await dir.getDirectoryHandle(name2, { create: true });
|
|
2889
3086
|
for await (const child of handle.values()) await this.copy(child, target, child.name);
|
|
2890
3087
|
}
|
|
2891
|
-
async symlink(target, path) {
|
|
3088
|
+
async symlink(target, path, owner) {
|
|
2892
3089
|
const parent = await this.locate(parentOf2(path), true);
|
|
2893
3090
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
2894
3091
|
const at = resolvePath(parent.path, baseOf(path));
|
|
@@ -2899,13 +3096,15 @@ var OpfsFs = class {
|
|
|
2899
3096
|
throw fsError("EEXIST", path);
|
|
2900
3097
|
}
|
|
2901
3098
|
const now = Date.now();
|
|
3099
|
+
const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
|
|
2902
3100
|
await this.meta.update(at, () => ({
|
|
2903
3101
|
path: at,
|
|
2904
3102
|
link: target,
|
|
2905
3103
|
dir: parent.path,
|
|
2906
3104
|
ino: inodeOf(at),
|
|
2907
3105
|
mtimeMs: now,
|
|
2908
|
-
ctimeMs: now
|
|
3106
|
+
ctimeMs: now,
|
|
3107
|
+
...fields
|
|
2909
3108
|
}));
|
|
2910
3109
|
this.touch(parent.path);
|
|
2911
3110
|
}
|
|
@@ -4212,7 +4411,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
|
4212
4411
|
throw err;
|
|
4213
4412
|
}
|
|
4214
4413
|
},
|
|
4215
|
-
writeFile: (path, content) => fs.writeFile(path, content),
|
|
4414
|
+
writeFile: (path, content, owner) => fs.writeFile(path, content, owner),
|
|
4216
4415
|
async exists(path) {
|
|
4217
4416
|
return await fs.exists(path) || await linked(path) !== void 0;
|
|
4218
4417
|
},
|
|
@@ -4250,9 +4449,10 @@ function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
|
4250
4449
|
mkdir: (path, options) => fs.mkdir(path, options),
|
|
4251
4450
|
rm: (path, options) => fs.rm(path, options),
|
|
4252
4451
|
rename: (from, to) => fs.rename(from, to),
|
|
4253
|
-
symlink: (target, path) => fs.symlink(target, path),
|
|
4452
|
+
symlink: (target, path, owner) => fs.symlink(target, path, owner),
|
|
4254
4453
|
readlink: (path) => fs.readlink(path),
|
|
4255
4454
|
...fs.realpath ? { realpath: fs.realpath.bind(fs) } : {},
|
|
4455
|
+
...fs.chown ? { chown: fs.chown.bind(fs) } : {},
|
|
4256
4456
|
chmod: (path, mode) => fs.chmod(path, mode),
|
|
4257
4457
|
utimes: (path, atime, mtime) => fs.utimes(path, atime, mtime),
|
|
4258
4458
|
lutimes: (path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -4378,6 +4578,7 @@ var FsWatchers = class {
|
|
|
4378
4578
|
rename: after(fs.rename.bind(fs), (from, to) => [from, to]),
|
|
4379
4579
|
symlink: after(fs.symlink.bind(fs), (_target, path) => [path]),
|
|
4380
4580
|
chmod: after(fs.chmod.bind(fs), (path) => [path]),
|
|
4581
|
+
...fs.chown ? { chown: after(fs.chown.bind(fs), (path) => [path]) } : {},
|
|
4381
4582
|
utimes: after(fs.utimes.bind(fs), (path) => [path]),
|
|
4382
4583
|
lutimes: after(
|
|
4383
4584
|
(path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -4449,13 +4650,13 @@ var ChildTable = class {
|
|
|
4449
4650
|
if (!this.forker) throw new SpawnError("ENOSYS");
|
|
4450
4651
|
return this.track(state, this.parentFds.fork(), /* @__PURE__ */ new Map(), this.forker);
|
|
4451
4652
|
}
|
|
4452
|
-
async spawn(req, stdio,
|
|
4653
|
+
async spawn(req, stdio, inherit2 = []) {
|
|
4453
4654
|
if (!this.spawner) throw new SpawnError("ENOSYS");
|
|
4454
4655
|
const fds = new FdTable();
|
|
4455
4656
|
const captured = /* @__PURE__ */ new Map();
|
|
4456
4657
|
try {
|
|
4457
4658
|
for (const [n, slot] of stdio.entries()) fds.installAt(n, this.openSlot(slot, n, captured));
|
|
4458
|
-
for (const slot of
|
|
4659
|
+
for (const slot of inherit2) {
|
|
4459
4660
|
if (slot.fd <= 2) continue;
|
|
4460
4661
|
if ("device" in slot) {
|
|
4461
4662
|
fds.installAt(slot.fd, deviceFile(slot.device, slot.access));
|
|
@@ -4536,8 +4737,8 @@ var ChildTable = class {
|
|
|
4536
4737
|
candidates(pid, flags) {
|
|
4537
4738
|
const all = [...this.children];
|
|
4538
4739
|
if (pid > 0) return all.filter(([p]) => p === pid);
|
|
4539
|
-
const
|
|
4540
|
-
return pid === -1 || !
|
|
4740
|
+
const inGroup2 = flags.inGroup;
|
|
4741
|
+
return pid === -1 || !inGroup2 ? all : all.filter(([p]) => inGroup2(p));
|
|
4541
4742
|
}
|
|
4542
4743
|
async nextChange(candidates, flags, interrupt) {
|
|
4543
4744
|
let wake;
|
|
@@ -5258,10 +5459,10 @@ var MountFs = class {
|
|
|
5258
5459
|
}
|
|
5259
5460
|
return concat3(chunks2, total);
|
|
5260
5461
|
}
|
|
5261
|
-
async writeFile(path, content) {
|
|
5462
|
+
async writeFile(path, content, owner) {
|
|
5262
5463
|
const real = await this.follow(path, 0, true);
|
|
5263
5464
|
const found = this.at(real);
|
|
5264
|
-
if (!found) return this.base.writeFile(real, content);
|
|
5465
|
+
if (!found) return this.base.writeFile(real, content, owner);
|
|
5265
5466
|
const { mount, rel: rel2 } = found;
|
|
5266
5467
|
this.writable(mount, real);
|
|
5267
5468
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -5528,9 +5729,9 @@ var MountFs = class {
|
|
|
5528
5729
|
this.table.forget(a.mount, normalizePath(to));
|
|
5529
5730
|
}
|
|
5530
5731
|
}
|
|
5531
|
-
async symlink(target, path) {
|
|
5732
|
+
async symlink(target, path, owner) {
|
|
5532
5733
|
const found = this.at(path);
|
|
5533
|
-
if (!found) return this.base.symlink(target, path);
|
|
5734
|
+
if (!found) return this.base.symlink(target, path, owner);
|
|
5534
5735
|
this.writable(found.mount, normalizePath(path));
|
|
5535
5736
|
if (!found.mount.caps.symlinks)
|
|
5536
5737
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -5548,6 +5749,15 @@ var MountFs = class {
|
|
|
5548
5749
|
if (!found) return this.base.readlink(path);
|
|
5549
5750
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
5550
5751
|
}
|
|
5752
|
+
async chown(path, change) {
|
|
5753
|
+
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
5754
|
+
if (this.at(real)) {
|
|
5755
|
+
if (change.kind === "new") return;
|
|
5756
|
+
throw errnoError("EPERM", `${path}: this file system keeps no owners`);
|
|
5757
|
+
}
|
|
5758
|
+
if (!this.base.chown) throw errnoError("EPERM", path);
|
|
5759
|
+
return this.base.chown(real, change);
|
|
5760
|
+
}
|
|
5551
5761
|
async chmod(path, mode) {
|
|
5552
5762
|
const found = this.at(path);
|
|
5553
5763
|
if (!found) return this.base.chmod(path, mode);
|
|
@@ -5622,7 +5832,9 @@ function statJson(s) {
|
|
|
5622
5832
|
...s.readonly ? { readonly: true } : {},
|
|
5623
5833
|
...s.maxFile ? { maxFile: s.maxFile } : {},
|
|
5624
5834
|
...s.ranged ? { ranged: true } : {},
|
|
5625
|
-
...s.version !== void 0 ? { version: s.version } : {}
|
|
5835
|
+
...s.version !== void 0 ? { version: s.version } : {},
|
|
5836
|
+
...s.uid !== void 0 ? { uid: s.uid } : {},
|
|
5837
|
+
...s.gid !== void 0 ? { gid: s.gid } : {}
|
|
5626
5838
|
};
|
|
5627
5839
|
}
|
|
5628
5840
|
async function readdirStat(fs, dir) {
|
|
@@ -5637,13 +5849,34 @@ var done = { ok: true, kind: "void" };
|
|
|
5637
5849
|
function json2(value) {
|
|
5638
5850
|
return { ok: true, kind: "json", json: value };
|
|
5639
5851
|
}
|
|
5852
|
+
function ownerFor2(entry, mode) {
|
|
5853
|
+
const cred = entry.cred?.();
|
|
5854
|
+
if (!cred) return void 0;
|
|
5855
|
+
return ownerOf(cred, mode === void 0 ? void 0 : mode & ~(entry.umask?.() ?? 18));
|
|
5856
|
+
}
|
|
5857
|
+
function mkdirOptions(entry, mode = 511) {
|
|
5858
|
+
const owner = ownerFor2(entry, mode);
|
|
5859
|
+
if (!owner) return { recursive: true };
|
|
5860
|
+
const parents = 511 & ~(entry.umask?.() ?? 18) | 192;
|
|
5861
|
+
return { recursive: true, owner: { ...owner, parents } };
|
|
5862
|
+
}
|
|
5863
|
+
async function chown(entry, path, req) {
|
|
5864
|
+
const cred = entry.cred?.();
|
|
5865
|
+
if (!cred) return done;
|
|
5866
|
+
await chownAs(entry.fs, cred, path, {
|
|
5867
|
+
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
5868
|
+
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
5869
|
+
follow: req.op === "chown"
|
|
5870
|
+
});
|
|
5871
|
+
return done;
|
|
5872
|
+
}
|
|
5640
5873
|
async function run(entry, path, req) {
|
|
5641
5874
|
const { fs, cwd } = entry;
|
|
5642
5875
|
switch (req.op) {
|
|
5643
5876
|
case "read":
|
|
5644
5877
|
return { ok: true, kind: "bytes", bytes: await fs.readFileBuffer(path) };
|
|
5645
5878
|
case "write":
|
|
5646
|
-
await fs.writeFile(path, req.body ?? new Uint8Array(0));
|
|
5879
|
+
await fs.writeFile(path, req.body ?? new Uint8Array(0), ownerFor2(entry, 438));
|
|
5647
5880
|
return done;
|
|
5648
5881
|
case "exists":
|
|
5649
5882
|
return json2(await fs.exists(path));
|
|
@@ -5656,7 +5889,7 @@ async function run(entry, path, req) {
|
|
|
5656
5889
|
case "readdir-stat":
|
|
5657
5890
|
return json2(await readdirStat(fs, path));
|
|
5658
5891
|
case "mkdir":
|
|
5659
|
-
await fs.mkdir(path,
|
|
5892
|
+
await fs.mkdir(path, mkdirOptions(entry, req.mode));
|
|
5660
5893
|
return done;
|
|
5661
5894
|
case "rm":
|
|
5662
5895
|
await fs.rm(path, { recursive: true });
|
|
@@ -5677,10 +5910,10 @@ async function run(entry, path, req) {
|
|
|
5677
5910
|
await fs.rm(path, { recursive: true });
|
|
5678
5911
|
return done;
|
|
5679
5912
|
case "symlink":
|
|
5680
|
-
await fs.symlink(req.arg2 ?? "", path);
|
|
5913
|
+
await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
|
|
5681
5914
|
return done;
|
|
5682
5915
|
case "create":
|
|
5683
|
-
await createExclusive(fs, path);
|
|
5916
|
+
await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
|
|
5684
5917
|
return done;
|
|
5685
5918
|
case "readlink":
|
|
5686
5919
|
return json2(await fs.readlink(path));
|
|
@@ -5693,6 +5926,9 @@ async function run(entry, path, req) {
|
|
|
5693
5926
|
case "lutimes":
|
|
5694
5927
|
await lutimesOf(fs, path, new Date(req.atimeMs ?? 0), new Date(req.mtimeMs ?? 0));
|
|
5695
5928
|
return done;
|
|
5929
|
+
case "chown":
|
|
5930
|
+
case "lchown":
|
|
5931
|
+
return chown(entry, path, req);
|
|
5696
5932
|
case "pread":
|
|
5697
5933
|
case "pwrite":
|
|
5698
5934
|
case "truncate":
|
|
@@ -5701,14 +5937,14 @@ async function run(entry, path, req) {
|
|
|
5701
5937
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
5702
5938
|
}
|
|
5703
5939
|
}
|
|
5704
|
-
async function createExclusive(fs, path) {
|
|
5705
|
-
if (fs.createExclusive) return fs.createExclusive(path);
|
|
5940
|
+
async function createExclusive(fs, path, owner) {
|
|
5941
|
+
if (fs.createExclusive) return fs.createExclusive(path, owner);
|
|
5706
5942
|
if (await fs.lstat(path).then(
|
|
5707
5943
|
() => true,
|
|
5708
5944
|
() => false
|
|
5709
5945
|
))
|
|
5710
5946
|
throw syncError("EEXIST", path);
|
|
5711
|
-
await fs.writeFile(path, new Uint8Array(0));
|
|
5947
|
+
await fs.writeFile(path, new Uint8Array(0), owner);
|
|
5712
5948
|
}
|
|
5713
5949
|
async function ranged(fs, path, req) {
|
|
5714
5950
|
const ops = rangedOps(fs);
|
|
@@ -7198,10 +7434,10 @@ var RealmProxy = class {
|
|
|
7198
7434
|
}
|
|
7199
7435
|
async bridge(ctx, socket, hangup) {
|
|
7200
7436
|
const stop = this.stop.signal;
|
|
7201
|
-
let
|
|
7437
|
+
let chain2 = Promise.resolve();
|
|
7202
7438
|
const toGuest = (bytes) => {
|
|
7203
|
-
|
|
7204
|
-
return
|
|
7439
|
+
chain2 = chain2.then(() => ctx.sink.write(bytes, stop));
|
|
7440
|
+
return chain2;
|
|
7205
7441
|
};
|
|
7206
7442
|
const done4 = new AbortController();
|
|
7207
7443
|
const reading = AbortSignal.any([stop, done4.signal, hangup]);
|
|
@@ -9251,12 +9487,12 @@ var VfsNodes = class {
|
|
|
9251
9487
|
}
|
|
9252
9488
|
return walk();
|
|
9253
9489
|
}
|
|
9254
|
-
createExclusive(path) {
|
|
9490
|
+
createExclusive(path, owner) {
|
|
9255
9491
|
return this.onEntry(path, async () => {
|
|
9256
9492
|
const node = this.byPath.get(path);
|
|
9257
9493
|
const held = node ? await node.serial(async () => node.holds()) : false;
|
|
9258
9494
|
if (held || await present(this.fs, path)) throw fsError("EEXIST", path);
|
|
9259
|
-
await this.fs.writeFile(path, new Uint8Array(0));
|
|
9495
|
+
await this.fs.writeFile(path, new Uint8Array(0), owner);
|
|
9260
9496
|
});
|
|
9261
9497
|
}
|
|
9262
9498
|
open(path, pin, writable = false) {
|
|
@@ -9386,6 +9622,11 @@ var MAX_LINKS5 = 40;
|
|
|
9386
9622
|
function parentOf6(path) {
|
|
9387
9623
|
return path.slice(0, path.lastIndexOf("/")) || "/";
|
|
9388
9624
|
}
|
|
9625
|
+
async function mustBeDir(fs, path) {
|
|
9626
|
+
if (!fs.lstat) return;
|
|
9627
|
+
const st = await fs.lstat(path);
|
|
9628
|
+
if (st.isDirectory !== true) throw fsError("ENOTDIR", path);
|
|
9629
|
+
}
|
|
9389
9630
|
async function linkOf(fs, path) {
|
|
9390
9631
|
return fs.readlink?.(path).catch(() => void 0);
|
|
9391
9632
|
}
|
|
@@ -9402,6 +9643,7 @@ async function realDir(fs, dir, budget = { hops: 0 }) {
|
|
|
9402
9643
|
const next2 = at === "/" ? `/${part}` : `${at}/${part}`;
|
|
9403
9644
|
const link2 = await linkOf(fs, next2);
|
|
9404
9645
|
if (link2 === void 0) {
|
|
9646
|
+
if (queue.find((p) => p !== ".") === "..") await mustBeDir(fs, next2);
|
|
9405
9647
|
at = next2;
|
|
9406
9648
|
continue;
|
|
9407
9649
|
}
|
|
@@ -9467,9 +9709,9 @@ function keepingOpen(fs, nodes) {
|
|
|
9467
9709
|
nodes.renamed(a, b);
|
|
9468
9710
|
});
|
|
9469
9711
|
},
|
|
9470
|
-
writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
|
|
9471
|
-
createExclusive: async (path) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path))),
|
|
9472
|
-
symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
|
|
9712
|
+
writeFile: (path, content, owner) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content, owner)),
|
|
9713
|
+
createExclusive: async (path, owner) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path)), owner),
|
|
9714
|
+
symlink: (target, path, owner) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path, owner)),
|
|
9473
9715
|
mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
|
|
9474
9716
|
};
|
|
9475
9717
|
}
|
|
@@ -9740,9 +9982,9 @@ var WasmProcess = class {
|
|
|
9740
9982
|
return "deliver";
|
|
9741
9983
|
}
|
|
9742
9984
|
async spawn(req) {
|
|
9743
|
-
const { file, argv, env, cwd, stdio, inherit, exec } = req;
|
|
9985
|
+
const { file, argv, env, cwd, stdio, inherit: inherit2, exec } = req;
|
|
9744
9986
|
const spawned = { file, argv, env, cwd, ...exec ? { exec } : {} };
|
|
9745
|
-
const pid = await this.children.spawn(spawned, stdio,
|
|
9987
|
+
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
9746
9988
|
if (!exec) return pid;
|
|
9747
9989
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
9748
9990
|
else this.adoptExec(pid);
|
|
@@ -9907,12 +10149,14 @@ var WasmProcess = class {
|
|
|
9907
10149
|
}
|
|
9908
10150
|
const open = { ...req, path };
|
|
9909
10151
|
if (req.exclusive) {
|
|
9910
|
-
await nodes.createExclusive(path);
|
|
10152
|
+
await nodes.createExclusive(path, this.newOwner());
|
|
9911
10153
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
9912
10154
|
} else if (req.create) {
|
|
9913
10155
|
await nodes.onEntry(path, async () => {
|
|
10156
|
+
const fresh = this.options.owners && !await present(this.options.fs, path, true);
|
|
9914
10157
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
9915
10158
|
await this.fds.get(fd).file.stat?.();
|
|
10159
|
+
if (fresh) await this.options.fs.chown?.(path, { ...this.newOwner(), kind: "new" });
|
|
9916
10160
|
});
|
|
9917
10161
|
} else {
|
|
9918
10162
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
@@ -9926,6 +10170,10 @@ var WasmProcess = class {
|
|
|
9926
10170
|
}
|
|
9927
10171
|
return fd;
|
|
9928
10172
|
}
|
|
10173
|
+
newOwner() {
|
|
10174
|
+
if (!this.options.owners) return void 0;
|
|
10175
|
+
return { uid: this.cred.euid, gid: this.cred.egid, mode: 438 & ~this.umask };
|
|
10176
|
+
}
|
|
9929
10177
|
async openProc(req, path) {
|
|
9930
10178
|
return this.fds.install(await this.procFile(req, path), 3);
|
|
9931
10179
|
}
|
|
@@ -10572,6 +10820,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
10572
10820
|
sab,
|
|
10573
10821
|
umask,
|
|
10574
10822
|
cred,
|
|
10823
|
+
...opts.owners ? { owners: true } : {},
|
|
10575
10824
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
10576
10825
|
};
|
|
10577
10826
|
if (opts.program.abi === "js") {
|
|
@@ -10595,8 +10844,9 @@ function inherited(opts) {
|
|
|
10595
10844
|
...opts.cred ? { cred: opts.cred } : {}
|
|
10596
10845
|
};
|
|
10597
10846
|
}
|
|
10598
|
-
function holdingToken(opts, holds) {
|
|
10847
|
+
function holdingToken(opts, holds, caller) {
|
|
10599
10848
|
return mintSyncFsToken({
|
|
10849
|
+
...opts.owners ? caller : {},
|
|
10600
10850
|
fs: opts.fs,
|
|
10601
10851
|
cwd: opts.cwd,
|
|
10602
10852
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
@@ -10612,6 +10862,7 @@ function holdingToken(opts, holds) {
|
|
|
10612
10862
|
function processOptions(opts, header4, hooks) {
|
|
10613
10863
|
return {
|
|
10614
10864
|
...inherited(opts),
|
|
10865
|
+
...opts.owners ? { owners: true } : {},
|
|
10615
10866
|
...opts.identity ? { identity: opts.identity } : {},
|
|
10616
10867
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
10617
10868
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -10656,7 +10907,10 @@ function spawnWasmProcess(opts) {
|
|
|
10656
10907
|
publishStops(process2, header4);
|
|
10657
10908
|
const holds = new HeldPaths();
|
|
10658
10909
|
opts.held?.add(holds);
|
|
10659
|
-
const token = holdingToken(opts, holds
|
|
10910
|
+
const token = holdingToken(opts, holds, {
|
|
10911
|
+
cred: () => process2.cred,
|
|
10912
|
+
umask: () => process2.umask
|
|
10913
|
+
});
|
|
10660
10914
|
process2.keptPath = (path) => holds.keptAt(path)?.hidden;
|
|
10661
10915
|
process2.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
|
|
10662
10916
|
const worker = opts.createWorker();
|
|
@@ -11017,26 +11271,26 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
11017
11271
|
void entry.final.cancel().catch(() => void 0);
|
|
11018
11272
|
};
|
|
11019
11273
|
const keyOf2 = (owner, method, url) => `${owner} ${method} ${url}`;
|
|
11020
|
-
const hold = (key,
|
|
11274
|
+
const hold = (key, chain2) => {
|
|
11021
11275
|
drop(key);
|
|
11022
|
-
const mine = [...held.keys()].filter((k) => held.get(k)?.owner ===
|
|
11276
|
+
const mine = [...held.keys()].filter((k) => held.get(k)?.owner === chain2.owner);
|
|
11023
11277
|
if (mine.length >= HELD_PER_OWNER) drop(mine[0]);
|
|
11024
11278
|
if (held.size >= HELD_MAX) drop(held.keys().next().value);
|
|
11025
11279
|
const timer = setTimeout(() => drop(key), heldMs);
|
|
11026
11280
|
timer.unref?.();
|
|
11027
|
-
held.set(key, { ...
|
|
11281
|
+
held.set(key, { ...chain2, timer });
|
|
11028
11282
|
};
|
|
11029
|
-
const replay = (
|
|
11030
|
-
const [hop, ...rest2] =
|
|
11283
|
+
const replay = (chain2) => {
|
|
11284
|
+
const [hop, ...rest2] = chain2.hops;
|
|
11031
11285
|
const location = hop && header2(hop.headers, "location");
|
|
11032
|
-
if (!hop || location === void 0) return
|
|
11286
|
+
if (!hop || location === void 0) return chain2.final;
|
|
11033
11287
|
const target = new URL(location, hop.url);
|
|
11034
11288
|
target.hash = "";
|
|
11035
|
-
const method = followedWith(hop.status,
|
|
11289
|
+
const method = followedWith(hop.status, chain2.method);
|
|
11036
11290
|
const away = target.origin !== new URL(hop.url).origin;
|
|
11037
|
-
const print = away ? unauthorized(
|
|
11038
|
-
hold(keyOf2(
|
|
11039
|
-
...
|
|
11291
|
+
const print = away ? unauthorized(chain2.fingerprint) : chain2.fingerprint;
|
|
11292
|
+
hold(keyOf2(chain2.owner, method, target.href), {
|
|
11293
|
+
...chain2,
|
|
11040
11294
|
method,
|
|
11041
11295
|
fingerprint: print,
|
|
11042
11296
|
hops: rest2
|
|
@@ -12728,6 +12982,11 @@ var DECIDE_MS = 100;
|
|
|
12728
12982
|
var INIT_PID = 1;
|
|
12729
12983
|
var SHARED_DIRS = ["/tmp", "/home"];
|
|
12730
12984
|
var encoder3 = new TextEncoder();
|
|
12985
|
+
var USERS_MODES = ["off", "report", "enforce"];
|
|
12986
|
+
function usersMode(mode = "off") {
|
|
12987
|
+
if (USERS_MODES.includes(mode)) return mode;
|
|
12988
|
+
throw new Error(`users must be 'off', 'report' or 'enforce', not ${String(mode)}`);
|
|
12989
|
+
}
|
|
12731
12990
|
function baseName(path) {
|
|
12732
12991
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
12733
12992
|
}
|
|
@@ -12855,10 +13114,13 @@ var Launcher = class {
|
|
|
12855
13114
|
processMounts;
|
|
12856
13115
|
booting = new AbortController();
|
|
12857
13116
|
fstab = Promise.resolve([]);
|
|
13117
|
+
usersMode;
|
|
12858
13118
|
nextPid = 1e3;
|
|
12859
13119
|
boot = Date.now();
|
|
12860
13120
|
terminals = 0;
|
|
12861
13121
|
constructor(options) {
|
|
13122
|
+
this.usersMode = usersMode(options.users);
|
|
13123
|
+
if (this.owners) options.fs.trackOwners?.();
|
|
12862
13124
|
this.mounts = new MountTable({
|
|
12863
13125
|
open: (type, spec) => this.driver(type, spec),
|
|
12864
13126
|
busy: (target) => [...this.openFiles].some((nodes) => nodes.holds(target)) || heldUnder(this.held, target),
|
|
@@ -12912,7 +13174,7 @@ var Launcher = class {
|
|
|
12912
13174
|
}
|
|
12913
13175
|
);
|
|
12914
13176
|
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
12915
|
-
this.users = new UserDb(this.fs);
|
|
13177
|
+
this.users = new UserDb(this.fs, this.owners);
|
|
12916
13178
|
void this.unlinked.sweep("/");
|
|
12917
13179
|
this.watchers.watch(
|
|
12918
13180
|
[this.modulesDir, this.pnpmHome],
|
|
@@ -12924,6 +13186,9 @@ var Launcher = class {
|
|
|
12924
13186
|
this.resetCatalogs();
|
|
12925
13187
|
});
|
|
12926
13188
|
}
|
|
13189
|
+
get owners() {
|
|
13190
|
+
return this.usersMode !== "off";
|
|
13191
|
+
}
|
|
12927
13192
|
setRoutes(table) {
|
|
12928
13193
|
this.routes.set(table);
|
|
12929
13194
|
}
|
|
@@ -13182,6 +13447,7 @@ var Launcher = class {
|
|
|
13182
13447
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
13183
13448
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
13184
13449
|
cred: req.cred,
|
|
13450
|
+
...this.owners ? { owners: true } : {},
|
|
13185
13451
|
program: req.program,
|
|
13186
13452
|
argv0: req.argv0,
|
|
13187
13453
|
args: req.args,
|
|
@@ -14643,6 +14909,7 @@ async function attachKernel(port, options = {}) {
|
|
|
14643
14909
|
return {
|
|
14644
14910
|
protocol: hello.protocol,
|
|
14645
14911
|
transport,
|
|
14912
|
+
users: hello.users ?? "off",
|
|
14646
14913
|
closed: channel.ended.promise,
|
|
14647
14914
|
spawn: (argv, opts = {}) => spawnOn(channel, argv, opts),
|
|
14648
14915
|
run: (argv, opts = {}) => runOn(channel, argv, opts),
|
|
@@ -14770,7 +15037,8 @@ async function createNodeKernel(options = {}) {
|
|
|
14770
15037
|
...options.hostfs ? { hostfs: options.hostfs } : {},
|
|
14771
15038
|
...hostfsFetchOf(options),
|
|
14772
15039
|
...options.cdp ? { cdp: options.cdp } : {},
|
|
14773
|
-
...options.hostname !== void 0 ? { hostname: options.hostname } : {}
|
|
15040
|
+
...options.hostname !== void 0 ? { hostname: options.hostname } : {},
|
|
15041
|
+
...options.users !== void 0 ? { users: options.users } : {}
|
|
14774
15042
|
});
|
|
14775
15043
|
await launcher.prepare();
|
|
14776
15044
|
const guard = (work) => new Promise((resolve, reject) => {
|
|
@@ -14836,6 +15104,7 @@ async function createNodeKernel(options = {}) {
|
|
|
14836
15104
|
mounts: async () => launcher.mounts.list(),
|
|
14837
15105
|
setRoutes: (routes) => guard(async () => launcher.setRoutes(routes)),
|
|
14838
15106
|
users: {
|
|
15107
|
+
mode: launcher.usersMode,
|
|
14839
15108
|
add: (user) => guard(() => launcher.users.add(user)),
|
|
14840
15109
|
remove: (name2, options2) => guard(() => launcher.users.remove(name2, options2)),
|
|
14841
15110
|
list: () => guard(() => launcher.users.list())
|