@ai-ecoverse/slicc-kernel 1.72.0 → 1.73.1
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 +8 -7
- package/dist/index.js +13 -3
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +142 -37
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +117 -78
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +137 -36
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +117 -78
- package/dist/process-worker.js.map +2 -2
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -2246,6 +2246,9 @@ var UserDb = class {
|
|
|
2246
2246
|
const pnpm = `${home}/.local/share/pnpm`;
|
|
2247
2247
|
if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
|
|
2248
2248
|
}
|
|
2249
|
+
umaskFor(options) {
|
|
2250
|
+
return (options.umask ?? this.umasks.get(options.name) ?? 18) & 511;
|
|
2251
|
+
}
|
|
2249
2252
|
async realDir(path) {
|
|
2250
2253
|
const parts2 = path.split("/").filter(Boolean);
|
|
2251
2254
|
for (let n = 1; n <= parts2.length; n++) {
|
|
@@ -2269,9 +2272,11 @@ var UserDb = class {
|
|
|
2269
2272
|
group: parseGroup(await this.read(GROUP, DEFAULT_GROUP))
|
|
2270
2273
|
};
|
|
2271
2274
|
}
|
|
2272
|
-
async provision(row) {
|
|
2273
|
-
const
|
|
2274
|
-
const
|
|
2275
|
+
async provision(row, umask, shared) {
|
|
2276
|
+
const dirs = 511 & ~umask | (shared ? 1024 : 0);
|
|
2277
|
+
const gid = shared?.gid ?? row.gid;
|
|
2278
|
+
const owner = this.owners ? { uid: row.uid, gid } : void 0;
|
|
2279
|
+
const made2 = owner ? { recursive: true, owner: { ...owner, mode: dirs, parents: dirs } } : { recursive: true };
|
|
2275
2280
|
const pnpm = `${row.home}/.local/share/pnpm`;
|
|
2276
2281
|
if (!await this.fs.exists(pnpm)) {
|
|
2277
2282
|
await this.fs.mkdir(pnpm, made2);
|
|
@@ -2280,7 +2285,7 @@ var UserDb = class {
|
|
|
2280
2285
|
const config = `${row.home}/.config/pnpm/config.yaml`;
|
|
2281
2286
|
if (!await this.fs.exists(config)) {
|
|
2282
2287
|
await this.fs.mkdir(`${row.home}/.config/pnpm`, made2);
|
|
2283
|
-
await this.fs.writeFile(config, PNPM_CONFIG, owner);
|
|
2288
|
+
await this.fs.writeFile(config, PNPM_CONFIG, owner && { ...owner, mode: 438 & ~umask });
|
|
2284
2289
|
}
|
|
2285
2290
|
}
|
|
2286
2291
|
async commit(passwd, group, then) {
|
|
@@ -2371,7 +2376,7 @@ var UserDb = class {
|
|
|
2371
2376
|
throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
|
|
2372
2377
|
}
|
|
2373
2378
|
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
2374
|
-
await this.provision(found);
|
|
2379
|
+
await this.provision(found, this.umaskFor(options), shared);
|
|
2375
2380
|
await this.stampHome(found, shared, homeMode);
|
|
2376
2381
|
}
|
|
2377
2382
|
if (joined(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
@@ -2389,7 +2394,7 @@ var UserDb = class {
|
|
|
2389
2394
|
const fresh2 = !await this.fs.exists(home);
|
|
2390
2395
|
await this.fs.mkdir(home, { recursive: true });
|
|
2391
2396
|
try {
|
|
2392
|
-
await this.provision(row);
|
|
2397
|
+
await this.provision(row, this.umaskFor(options), shared);
|
|
2393
2398
|
await this.stampHome(row, shared, homeMode);
|
|
2394
2399
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
2395
2400
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
@@ -2525,6 +2530,12 @@ var CLIENT_CHECKS = {
|
|
|
2525
2530
|
readlink: (g, at) => searchable(g, "readlink", at(0), false),
|
|
2526
2531
|
exists: (g, at) => searchable(g, "exists", at(0), true)
|
|
2527
2532
|
};
|
|
2533
|
+
function clientFs(l, tag, self, req) {
|
|
2534
|
+
if (!FS_METHODS.includes(req.method)) {
|
|
2535
|
+
throw new Error(`unknown file system call ${req.method}`);
|
|
2536
|
+
}
|
|
2537
|
+
return fsCall(l.fsFor(tag), req.method, req.args, ownerFor(l, self), guardFor(l, self, tag));
|
|
2538
|
+
}
|
|
2528
2539
|
async function fsCall(fs, method, args, owner, g) {
|
|
2529
2540
|
const path = (i) => fs.resolvePath("/", String(args[i]));
|
|
2530
2541
|
if (g) {
|
|
@@ -2812,10 +2823,7 @@ function serveClient(port, host) {
|
|
|
2812
2823
|
case "ps":
|
|
2813
2824
|
return { result: processes(l, self) };
|
|
2814
2825
|
case "fs":
|
|
2815
|
-
|
|
2816
|
-
throw new Error(`unknown file system call ${req.method}`);
|
|
2817
|
-
}
|
|
2818
|
-
return fsCall(l.processFs, req.method, req.args, ownerFor(l, self), guard2(l));
|
|
2826
|
+
return clientFs(l, host.tag, self, req);
|
|
2819
2827
|
case "watch":
|
|
2820
2828
|
case "unwatch":
|
|
2821
2829
|
return watchOp(l, req, watches, send, guard2(l));
|
|
@@ -3003,7 +3011,13 @@ var MemoryMeta = class {
|
|
|
3003
3011
|
};
|
|
3004
3012
|
|
|
3005
3013
|
// src/fs/protect.ts
|
|
3006
|
-
|
|
3014
|
+
function writerTags(protection) {
|
|
3015
|
+
const writers = protection?.writers ?? [];
|
|
3016
|
+
if (!Array.isArray(writers) || writers.some((tag) => typeof tag !== "string" || tag === "")) {
|
|
3017
|
+
throw new TypeError("protect.writers must be a list of process tags");
|
|
3018
|
+
}
|
|
3019
|
+
return new Set(writers);
|
|
3020
|
+
}
|
|
3007
3021
|
function protectedPrefixes(paths) {
|
|
3008
3022
|
return [...new Set(paths.map((p) => normalizePath(p)))];
|
|
3009
3023
|
}
|
|
@@ -3511,6 +3525,9 @@ var OpfsFs = class {
|
|
|
3511
3525
|
protect(prefixes2) {
|
|
3512
3526
|
this.guarded = prefixes2;
|
|
3513
3527
|
}
|
|
3528
|
+
unguarded() {
|
|
3529
|
+
return Object.create(this, { guarded: { value: [] } });
|
|
3530
|
+
}
|
|
3514
3531
|
refuse(path, holding = false) {
|
|
3515
3532
|
if (isProtected(this.guarded, path) || holding && holdsProtected(this.guarded, path)) {
|
|
3516
3533
|
throw fsError("EROFS", path);
|
|
@@ -3680,15 +3697,15 @@ var OpfsFs = class {
|
|
|
3680
3697
|
}
|
|
3681
3698
|
dirTimes = /* @__PURE__ */ new Map();
|
|
3682
3699
|
dirDirty = /* @__PURE__ */ new Set();
|
|
3683
|
-
|
|
3700
|
+
flushing = {};
|
|
3684
3701
|
touch(...dirs) {
|
|
3685
3702
|
const now = Date.now();
|
|
3686
3703
|
for (const dir of dirs) {
|
|
3687
3704
|
this.dirTimes.set(dir, now);
|
|
3688
3705
|
this.dirDirty.add(dir);
|
|
3689
3706
|
}
|
|
3690
|
-
this.
|
|
3691
|
-
this.
|
|
3707
|
+
this.flushing.dir ??= Promise.resolve().then(() => this.flushDirTimes()).catch(() => void 0).finally(() => {
|
|
3708
|
+
this.flushing.dir = void 0;
|
|
3692
3709
|
});
|
|
3693
3710
|
}
|
|
3694
3711
|
async flushDirTimes() {
|
|
@@ -3932,7 +3949,7 @@ var OpfsFs = class {
|
|
|
3932
3949
|
const above = owner && {
|
|
3933
3950
|
uid: owner.uid,
|
|
3934
3951
|
gid: owner.gid,
|
|
3935
|
-
...mode ? { mode, parents: mode } : {}
|
|
3952
|
+
...mode !== void 0 ? { mode, parents: mode } : {}
|
|
3936
3953
|
};
|
|
3937
3954
|
await this.mkdir(parentOf4(path), { recursive: true, ...above ? { owner: above } : {} });
|
|
3938
3955
|
}
|
|
@@ -6236,6 +6253,11 @@ var HeldPaths = class extends Map {
|
|
|
6236
6253
|
keptFor(handle) {
|
|
6237
6254
|
return this.keptHandles.get(handle);
|
|
6238
6255
|
}
|
|
6256
|
+
keeps(hidden) {
|
|
6257
|
+
for (const file of this.uses.keys()) if (file.hidden === hidden) return true;
|
|
6258
|
+
for (const file of this.unlinked.values()) if (file.hidden === hidden) return true;
|
|
6259
|
+
return false;
|
|
6260
|
+
}
|
|
6239
6261
|
keep(path, file) {
|
|
6240
6262
|
const fresh2 = this.handlesAt(path).filter((id2) => !this.keptHandles.has(id2));
|
|
6241
6263
|
for (const id2 of fresh2) this.keptHandles.set(id2, file);
|
|
@@ -7337,6 +7359,7 @@ function guardOf(entry) {
|
|
|
7337
7359
|
return { fs: entry.fs, cred, pid: entry.pid ?? 0, dac: entry.dac };
|
|
7338
7360
|
}
|
|
7339
7361
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
7362
|
+
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
7340
7363
|
var NOT_FOLLOWING = /* @__PURE__ */ new Set(["lstat", "readlink", "lchown"]);
|
|
7341
7364
|
async function guard(g, path, req, cwd) {
|
|
7342
7365
|
const { op } = req;
|
|
@@ -7406,6 +7429,7 @@ async function accessOp(entry, path, req) {
|
|
|
7406
7429
|
async function guarded(entry, path, req) {
|
|
7407
7430
|
const g = guardOf(entry);
|
|
7408
7431
|
if (!g) return void 0;
|
|
7432
|
+
if (LOOKS.has(req.op) && await entry.holdsKept?.(path)) return void 0;
|
|
7409
7433
|
try {
|
|
7410
7434
|
await guard(g, path, req, entry.cwd);
|
|
7411
7435
|
return void 0;
|
|
@@ -12297,6 +12321,13 @@ var WasmProcess = class {
|
|
|
12297
12321
|
}
|
|
12298
12322
|
}
|
|
12299
12323
|
keptPath;
|
|
12324
|
+
async holds(path) {
|
|
12325
|
+
for (const fd of this.fds.numbers()) {
|
|
12326
|
+
const { file } = this.fds.get(fd);
|
|
12327
|
+
if ((await file.stat?.().catch(() => void 0))?.path === path) return true;
|
|
12328
|
+
}
|
|
12329
|
+
return false;
|
|
12330
|
+
}
|
|
12300
12331
|
keptHandle;
|
|
12301
12332
|
async keptOr(path, handle) {
|
|
12302
12333
|
const held = handle === void 0 ? void 0 : this.keptHandle?.(handle);
|
|
@@ -12940,7 +12971,8 @@ function spawnWasmProcess(opts) {
|
|
|
12940
12971
|
const token = holdingToken(opts, holds, {
|
|
12941
12972
|
cred: () => process2.cred,
|
|
12942
12973
|
umask: () => process2.umask,
|
|
12943
|
-
created: created3
|
|
12974
|
+
created: created3,
|
|
12975
|
+
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds.keeps(path) || await process2.holds(path))
|
|
12944
12976
|
});
|
|
12945
12977
|
process2.keptPath = (path) => holds.keptAt(path)?.hidden;
|
|
12946
12978
|
process2.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
|
|
@@ -15405,9 +15437,14 @@ var Sudo = class {
|
|
|
15405
15437
|
if (walked.denied !== void 0 || walked.missing) return false;
|
|
15406
15438
|
return (await this.o.fs.stat(cwd).catch(() => void 0))?.isDirectory === true;
|
|
15407
15439
|
}
|
|
15408
|
-
async untrusted(path, cwd) {
|
|
15409
|
-
const files = await this.o.backing
|
|
15410
|
-
|
|
15440
|
+
async untrusted(path, cwd, word) {
|
|
15441
|
+
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
15442
|
+
if (!files) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
15443
|
+
for (const file of [path, ...files]) {
|
|
15444
|
+
if (!await this.trusted(file)) {
|
|
15445
|
+
return failed2("EPERM", `sudo: ${file} must be root's, and writable by root only`);
|
|
15446
|
+
}
|
|
15447
|
+
}
|
|
15411
15448
|
return void 0;
|
|
15412
15449
|
}
|
|
15413
15450
|
async locate(word, cwd) {
|
|
@@ -15448,10 +15485,8 @@ var Sudo = class {
|
|
|
15448
15485
|
}
|
|
15449
15486
|
const path = await this.locate(word, cwd);
|
|
15450
15487
|
if (!path) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
15451
|
-
const untrusted = await this.untrusted(path, cwd);
|
|
15452
|
-
if (untrusted)
|
|
15453
|
-
return failed2("EPERM", `sudo: ${untrusted} must be root's, and writable by root only`);
|
|
15454
|
-
}
|
|
15488
|
+
const untrusted = await this.untrusted(path, cwd, word);
|
|
15489
|
+
if (untrusted) return untrusted;
|
|
15455
15490
|
const argv = [path, ...args];
|
|
15456
15491
|
const matching = rules.filter(
|
|
15457
15492
|
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
|
|
@@ -15474,10 +15509,8 @@ var Sudo = class {
|
|
|
15474
15509
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
15475
15510
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
15476
15511
|
}
|
|
15477
|
-
const changed = await this.untrusted(path, cwd);
|
|
15478
|
-
if (changed)
|
|
15479
|
-
return failed2("EPERM", `sudo: ${changed} must be root's, and writable by root only`);
|
|
15480
|
-
}
|
|
15512
|
+
const changed = await this.untrusted(path, cwd, word);
|
|
15513
|
+
if (changed) return changed;
|
|
15481
15514
|
if (answer === "always" && !await this.remember(self, target, argv)) {
|
|
15482
15515
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
15483
15516
|
}
|
|
@@ -15751,6 +15784,10 @@ var Launcher = class {
|
|
|
15751
15784
|
fs;
|
|
15752
15785
|
processFs;
|
|
15753
15786
|
prefixes;
|
|
15787
|
+
writerTags;
|
|
15788
|
+
unguardedRoot;
|
|
15789
|
+
writers;
|
|
15790
|
+
unlinkOwnerOption;
|
|
15754
15791
|
base;
|
|
15755
15792
|
createWorker;
|
|
15756
15793
|
modulesDir;
|
|
@@ -15868,7 +15905,7 @@ var Launcher = class {
|
|
|
15868
15905
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
15869
15906
|
this.nodes.keepsOnDisk = true;
|
|
15870
15907
|
this.openFiles.add(this.nodes);
|
|
15871
|
-
const holders = [this.held,
|
|
15908
|
+
const holders = [this.held, this.openFiles];
|
|
15872
15909
|
this.unlinked = new UnlinkedKeeper(
|
|
15873
15910
|
fs,
|
|
15874
15911
|
{ [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
|
|
@@ -15881,7 +15918,12 @@ var Launcher = class {
|
|
|
15881
15918
|
}
|
|
15882
15919
|
);
|
|
15883
15920
|
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
15884
|
-
|
|
15921
|
+
this.writerTags = writerTags(options.protect);
|
|
15922
|
+
this.unlinkOwnerOption = options.unlinkOwner;
|
|
15923
|
+
if (this.writerTags.size > 0 && options.fs.protect && !options.fs.unguarded) {
|
|
15924
|
+
throw new TypeError("protect.writers needs a root file system with an unguarded view");
|
|
15925
|
+
}
|
|
15926
|
+
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
15885
15927
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
15886
15928
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
15887
15929
|
options.fs.protect?.(this.prefixes);
|
|
@@ -16098,7 +16140,7 @@ var Launcher = class {
|
|
|
16098
16140
|
}
|
|
16099
16141
|
async backing(file, cwd) {
|
|
16100
16142
|
const planned = await this.plan(file, [file], cwd, "");
|
|
16101
|
-
if (!planned) return
|
|
16143
|
+
if (!planned) return void 0;
|
|
16102
16144
|
const { glue, wasm, imports } = planned.target;
|
|
16103
16145
|
const files = [glue, wasm, ...imports ? [imports] : []];
|
|
16104
16146
|
const scripts = [];
|
|
@@ -16205,6 +16247,7 @@ var Launcher = class {
|
|
|
16205
16247
|
throw fsError("ESRCH", `no process group ${req.pgid}`);
|
|
16206
16248
|
}
|
|
16207
16249
|
const pid = this.nextPid++;
|
|
16250
|
+
const stack = this.stackFor(req.tag);
|
|
16208
16251
|
const terminal = req.fds.stdioTerminal();
|
|
16209
16252
|
const decided = req.decided ?? Promise.resolve(true);
|
|
16210
16253
|
const count = (byParent) => {
|
|
@@ -16235,8 +16278,8 @@ var Launcher = class {
|
|
|
16235
16278
|
env: req.env,
|
|
16236
16279
|
cwd: req.cwd,
|
|
16237
16280
|
fds: req.fds,
|
|
16238
|
-
fs:
|
|
16239
|
-
...this.prefixes.length > 0 ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
16281
|
+
fs: stack.fs,
|
|
16282
|
+
...this.prefixes.length > 0 && !stack.writer ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
16240
16283
|
createWorker: this.createWorker,
|
|
16241
16284
|
onError: req.report,
|
|
16242
16285
|
spawner: this.spawner(pid, req.report),
|
|
@@ -16251,9 +16294,9 @@ var Launcher = class {
|
|
|
16251
16294
|
}),
|
|
16252
16295
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
16253
16296
|
openFiles: this.openFiles,
|
|
16254
|
-
nodes:
|
|
16297
|
+
nodes: stack.nodes,
|
|
16255
16298
|
held: this.held,
|
|
16256
|
-
unlinkGate:
|
|
16299
|
+
unlinkGate: stack.unlinked.gate,
|
|
16257
16300
|
statfs: (path) => this.mounts.statfs(path),
|
|
16258
16301
|
mounts: () => this.mounts.list(),
|
|
16259
16302
|
mount: (call, signal) => this.processMount(pid, call, signal),
|
|
@@ -16554,6 +16597,7 @@ var Launcher = class {
|
|
|
16554
16597
|
released(path) {
|
|
16555
16598
|
const at = normalizePath(path);
|
|
16556
16599
|
this.unlinked.closed(at);
|
|
16600
|
+
this.writers?.unlinked.closed(at);
|
|
16557
16601
|
const open = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
16558
16602
|
if (!open) void this.mounts.commit(at).catch(() => void 0);
|
|
16559
16603
|
}
|
|
@@ -16704,6 +16748,27 @@ var Launcher = class {
|
|
|
16704
16748
|
await this.provisionPnpmHome();
|
|
16705
16749
|
return entry;
|
|
16706
16750
|
}
|
|
16751
|
+
async ownTmp() {
|
|
16752
|
+
const real = await this.realLayoutPath("/tmp");
|
|
16753
|
+
const st = real === void 0 ? void 0 : await this.base.lstat(real).catch(() => void 0);
|
|
16754
|
+
if (real !== void 0 && st?.isDirectory && this.base.hasOwner && !await this.base.hasOwner(real)) {
|
|
16755
|
+
let removed = 0;
|
|
16756
|
+
for (const name2 of await this.base.readdir(real).catch(() => [])) {
|
|
16757
|
+
const path = joinName(real, name2);
|
|
16758
|
+
if (await this.base.hasOwner(path) || this.inUse(path)) continue;
|
|
16759
|
+
const failed3 = await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
16760
|
+
if (failed3 === void 0) removed++;
|
|
16761
|
+
}
|
|
16762
|
+
if (removed > 0) {
|
|
16763
|
+
console.warn(`slicc-kernel users: removed ${removed} entries from /tmp that had no owner`);
|
|
16764
|
+
}
|
|
16765
|
+
await this.base.chown?.(real, { uid: 0, gid: 0, mode: 1023, follow: false });
|
|
16766
|
+
}
|
|
16767
|
+
if (st?.isDirectory) await this.base.chmod(real, 1023);
|
|
16768
|
+
}
|
|
16769
|
+
inUse(path) {
|
|
16770
|
+
return [...this.openFiles].some((nodes) => nodes.holds(path)) || heldUnder(this.held, path);
|
|
16771
|
+
}
|
|
16707
16772
|
async stampLayout() {
|
|
16708
16773
|
const layout = [
|
|
16709
16774
|
...LAYOUT,
|
|
@@ -16823,7 +16888,7 @@ var Launcher = class {
|
|
|
16823
16888
|
async prepare() {
|
|
16824
16889
|
await this.resolvePrefixes();
|
|
16825
16890
|
for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
|
|
16826
|
-
if (this.owners) await this.
|
|
16891
|
+
if (this.owners) await this.ownTmp();
|
|
16827
16892
|
await this.provisionPnpmHome();
|
|
16828
16893
|
await this.users.ensure();
|
|
16829
16894
|
if (this.owners) await this.stampLayout();
|
|
@@ -16872,13 +16937,49 @@ var Launcher = class {
|
|
|
16872
16937
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
16873
16938
|
};
|
|
16874
16939
|
}
|
|
16940
|
+
fsFor(tag) {
|
|
16941
|
+
return this.stackFor(tag).fs;
|
|
16942
|
+
}
|
|
16943
|
+
isWriter(tag) {
|
|
16944
|
+
return tag !== void 0 && this.prefixes.length > 0 && this.writerTags.has(tag);
|
|
16945
|
+
}
|
|
16946
|
+
stackFor(tag) {
|
|
16947
|
+
if (!this.isWriter(tag)) {
|
|
16948
|
+
return { fs: this.processFs, nodes: this.nodes, unlinked: this.unlinked, writer: false };
|
|
16949
|
+
}
|
|
16950
|
+
this.writers ??= this.writerStack();
|
|
16951
|
+
return this.writers;
|
|
16952
|
+
}
|
|
16953
|
+
writerStack() {
|
|
16954
|
+
const fs = withCommandDirs(
|
|
16955
|
+
this.watchers.wrap(this.mounts.wrap(this.unguardedRoot)),
|
|
16956
|
+
async () => new Set((await this.commands()).keys()),
|
|
16957
|
+
(dir) => this.userCommandDir(dir),
|
|
16958
|
+
this.owners
|
|
16959
|
+
);
|
|
16960
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
16961
|
+
nodes.keepsOnDisk = true;
|
|
16962
|
+
this.openFiles.add(nodes);
|
|
16963
|
+
const unlinked = new UnlinkedKeeper(
|
|
16964
|
+
fs,
|
|
16965
|
+
{ [Symbol.iterator]: () => [this.held, this.openFiles].flatMap((set2) => [...set2]).values() },
|
|
16966
|
+
(path) => this.mountRoot(path),
|
|
16967
|
+
{
|
|
16968
|
+
locks: webLocks(),
|
|
16969
|
+
busy: (path) => [...this.openFiles].some((open) => open.holds(path)),
|
|
16970
|
+
owner: this.unlinkOwnerOption,
|
|
16971
|
+
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
16972
|
+
}
|
|
16973
|
+
);
|
|
16974
|
+
return { fs: unlinked.wrap(keepingOpen(fs, nodes)), nodes, unlinked, writer: true };
|
|
16975
|
+
}
|
|
16875
16976
|
async starting(argv, dir, account, tag) {
|
|
16876
16977
|
this.resetCatalogs();
|
|
16877
16978
|
const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
|
|
16878
16979
|
const start2 = dir ?? "/";
|
|
16879
16980
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
16880
16981
|
const [file = ""] = argv;
|
|
16881
|
-
if (!await this.base.exists(cwd)) await this.
|
|
16982
|
+
if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
|
|
16882
16983
|
const planned = await this.plan(file, argv, cwd, scope);
|
|
16883
16984
|
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
|
|
16884
16985
|
return { cwd, file, planned };
|