@ai-ecoverse/slicc-kernel 1.167.3 → 1.168.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 +10 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +218 -87
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +61 -2
- package/dist/meta.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +1 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +372 -241
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/dac.d.ts +1 -1
- package/dist/types/fs/opfs.d.ts +1 -0
- package/dist/types/fs/remote.d.ts +1 -0
- package/dist/types/fs/types.d.ts +2 -0
- package/dist/types/kernel/replacing.d.ts +17 -0
- package/dist/types/launcher.d.ts +7 -0
- package/dist/types/meta.d.ts +4 -0
- package/package.json +3 -3
package/dist/node.js
CHANGED
|
@@ -800,28 +800,39 @@ async function stickyEntry(g, op, path, dir) {
|
|
|
800
800
|
if (sticky(g.cred, perm, (await ancestryOf(g.fs, entry)).at(-1))) return;
|
|
801
801
|
if (await present(g.fs, entry, false)) deny(g, op, path, "EPERM");
|
|
802
802
|
}
|
|
803
|
+
async function unwritable(g, op, path, dir) {
|
|
804
|
+
if (dir.denied === void 0) return false;
|
|
805
|
+
if (dir.link) {
|
|
806
|
+
deny(g, op, dir.denied);
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
const perm = dir.denied === dir.path ? dir.perm : void 0;
|
|
810
|
+
if (perm && !await present(g.fs, dir.path, true)) return false;
|
|
811
|
+
if (perm && permits(g.cred, perm, X_OK)) return true;
|
|
812
|
+
deny(g, op, path);
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
803
815
|
async function inParent(g, op, path, old = false) {
|
|
804
816
|
await fence(g, op, path);
|
|
805
|
-
if (old === "replaced") {
|
|
806
|
-
const dir2 = await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
|
|
807
|
-
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
808
|
-
}
|
|
809
|
-
if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
|
|
810
817
|
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, linked(g, DIR));
|
|
818
|
+
if (old !== true) {
|
|
819
|
+
if (await unwritable(g, op, path, dir)) deny(g, op, path);
|
|
820
|
+
else if (old === "replaced" && dir.denied === void 0) await stickyEntry(g, op, path, dir);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
811
823
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
812
824
|
if (dir.link) return deny(g, op, dir.denied);
|
|
813
825
|
const lookup4 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
814
826
|
if (!lookup4 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
815
827
|
}
|
|
816
|
-
async function makeIn(g, op, path) {
|
|
828
|
+
async function makeIn(g, op, path, parents = true) {
|
|
817
829
|
for (let dir = parentOf(path); ; dir = parentOf(dir)) {
|
|
818
830
|
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
819
|
-
if (
|
|
820
|
-
if (walked.denied !== void 0) {
|
|
831
|
+
if (await unwritable(g, op, path, walked)) {
|
|
821
832
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
822
833
|
return;
|
|
823
834
|
}
|
|
824
|
-
if (!walked.missing || dir === "/") return;
|
|
835
|
+
if (!parents || !walked.missing || dir === "/") return;
|
|
825
836
|
}
|
|
826
837
|
}
|
|
827
838
|
async function tree(g, op, dir, perm) {
|
|
@@ -3684,7 +3695,7 @@ function satisfies(version, range2) {
|
|
|
3684
3695
|
}
|
|
3685
3696
|
|
|
3686
3697
|
// src/version.ts
|
|
3687
|
-
var KERNEL_VERSION = true ? "1.
|
|
3698
|
+
var KERNEL_VERSION = true ? "1.168.0" : "0.0.0-dev";
|
|
3688
3699
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3689
3700
|
function procVersion() {
|
|
3690
3701
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -3767,8 +3778,8 @@ function abiOf(raw2, fallback) {
|
|
|
3767
3778
|
const abi = raw2 ?? fallback;
|
|
3768
3779
|
return abi === "emscripten" || abi === "wasi" || abi === "js" ? abi : void 0;
|
|
3769
3780
|
}
|
|
3770
|
-
function commandOf(pkg, name2, raw2, packageAbi,
|
|
3771
|
-
const withEnv = envFields({ ...
|
|
3781
|
+
function commandOf(pkg, name2, raw2, packageAbi, shared2) {
|
|
3782
|
+
const withEnv = envFields({ ...shared2, ...envOf(pkg, raw2.env) });
|
|
3772
3783
|
const script = inside(pkg, raw2.script);
|
|
3773
3784
|
if (script) {
|
|
3774
3785
|
return { name: name2, abi: packageAbi, glue: script, wasm: script, argv0: name2, script, ...withEnv };
|
|
@@ -3818,13 +3829,13 @@ function commandsOf(pkg, manifest) {
|
|
|
3818
3829
|
const packageAbi = abiOf(slicc.abi, "emscripten");
|
|
3819
3830
|
const entries = slicc.commands;
|
|
3820
3831
|
if (!packageAbi || !entries || typeof entries !== "object") return [];
|
|
3821
|
-
const
|
|
3832
|
+
const shared2 = envOf(pkg, slicc.env);
|
|
3822
3833
|
const out = [];
|
|
3823
3834
|
for (const [name2, raw2] of Object.entries(entries)) {
|
|
3824
3835
|
if (!commandName(name2) || !raw2 || typeof raw2 !== "object") {
|
|
3825
3836
|
continue;
|
|
3826
3837
|
}
|
|
3827
|
-
const command = commandOf(pkg, name2, raw2, packageAbi,
|
|
3838
|
+
const command = commandOf(pkg, name2, raw2, packageAbi, shared2);
|
|
3828
3839
|
if (command) out.push(command);
|
|
3829
3840
|
}
|
|
3830
3841
|
return out;
|
|
@@ -4998,8 +5009,8 @@ var UnlinkedKeeper = class {
|
|
|
4998
5009
|
void peers.ask(tab, { kept: { items: [], paths } }, PEER_RM_MS);
|
|
4999
5010
|
throw fsError("EBUSY", `${target}: open in another tab that did not answer`);
|
|
5000
5011
|
}
|
|
5001
|
-
const { whole, sends, shared } = await this.setAside(target, asked);
|
|
5002
|
-
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard,
|
|
5012
|
+
const { whole, sends, shared: shared2 } = await this.setAside(target, asked);
|
|
5013
|
+
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard, shared2) };
|
|
5003
5014
|
}
|
|
5004
5015
|
async setAside(target, asked) {
|
|
5005
5016
|
const mine = this.heldWithin(target);
|
|
@@ -5007,25 +5018,25 @@ var UnlinkedKeeper = class {
|
|
|
5007
5018
|
for (const { holders } of asked)
|
|
5008
5019
|
for (const { path } of holders) tabsOf.set(path, (tabsOf.get(path) ?? 0) + 1);
|
|
5009
5020
|
const done4 = /* @__PURE__ */ new Map();
|
|
5010
|
-
const
|
|
5021
|
+
const shared2 = [];
|
|
5011
5022
|
const sends = [];
|
|
5012
5023
|
for (const { tab, holders, paths } of asked) {
|
|
5013
5024
|
const items = [];
|
|
5014
5025
|
for (const holder of holders) {
|
|
5015
5026
|
if (!done4.has(holder.path)) {
|
|
5016
5027
|
const many = mine.has(holder.path) || (tabsOf.get(holder.path) ?? 0) > 1;
|
|
5017
|
-
done4.set(holder.path, await this.asideOne(holder, many, mine,
|
|
5028
|
+
done4.set(holder.path, await this.asideOne(holder, many, mine, shared2));
|
|
5018
5029
|
}
|
|
5019
5030
|
items.push({ path: holder.path, hidden: done4.get(holder.path), fid: holder.fid });
|
|
5020
5031
|
}
|
|
5021
5032
|
sends.push({ tab, items, paths });
|
|
5022
5033
|
}
|
|
5023
|
-
return { whole: done4.get(target) !== void 0, sends, shared };
|
|
5034
|
+
return { whole: done4.get(target) !== void 0, sends, shared: shared2 };
|
|
5024
5035
|
}
|
|
5025
|
-
async asideOne(holder, many, mine,
|
|
5036
|
+
async asideOne(holder, many, mine, shared2) {
|
|
5026
5037
|
if (!many) return this.asideFor(holder.path, holder.instance);
|
|
5027
5038
|
const one = await this.sharedAside(holder.path, mine);
|
|
5028
|
-
if (one)
|
|
5039
|
+
if (one) shared2.push(one);
|
|
5029
5040
|
return one?.hidden;
|
|
5030
5041
|
}
|
|
5031
5042
|
async sharedAside(path, mine) {
|
|
@@ -5070,16 +5081,16 @@ var UnlinkedKeeper = class {
|
|
|
5070
5081
|
sharedLocks() {
|
|
5071
5082
|
return this.locks;
|
|
5072
5083
|
}
|
|
5073
|
-
async undoing(op, peers, sends, heard,
|
|
5084
|
+
async undoing(op, peers, sends, heard, shared2 = []) {
|
|
5074
5085
|
let failed3;
|
|
5075
5086
|
let out;
|
|
5076
5087
|
try {
|
|
5077
5088
|
out = await op();
|
|
5078
5089
|
} catch (err) {
|
|
5079
5090
|
failed3 = err ?? new Error("failed");
|
|
5080
|
-
await this.rollBackAsides(sends,
|
|
5091
|
+
await this.rollBackAsides(sends, shared2);
|
|
5081
5092
|
}
|
|
5082
|
-
const hiddenShared = new Set(
|
|
5093
|
+
const hiddenShared = new Set(shared2.map((one) => one.hidden));
|
|
5083
5094
|
const answers2 = sends.map(({ tab, items, paths }) => {
|
|
5084
5095
|
const keeps = items.some((item) => item.hidden && hiddenShared.has(item.hidden));
|
|
5085
5096
|
return {
|
|
@@ -5090,7 +5101,7 @@ var UnlinkedKeeper = class {
|
|
|
5090
5101
|
await Promise.all(
|
|
5091
5102
|
answers2.map(({ told }, i) => heard[i] ? Promise.race([told, delay(PEER_RM_MS)]) : void 0)
|
|
5092
5103
|
);
|
|
5093
|
-
for (const one of
|
|
5104
|
+
for (const one of shared2) {
|
|
5094
5105
|
const waits = answers2.filter(
|
|
5095
5106
|
({ keeps }, i) => keeps && sends[i]?.items.some((item) => item.hidden === one.hidden)
|
|
5096
5107
|
);
|
|
@@ -5100,7 +5111,7 @@ var UnlinkedKeeper = class {
|
|
|
5100
5111
|
if (failed3 !== void 0) throw failed3;
|
|
5101
5112
|
return out;
|
|
5102
5113
|
}
|
|
5103
|
-
async rollBackAsides(sends,
|
|
5114
|
+
async rollBackAsides(sends, shared2) {
|
|
5104
5115
|
const back = /* @__PURE__ */ new Map();
|
|
5105
5116
|
for (const item of sends.flatMap((send2) => send2.items)) {
|
|
5106
5117
|
const { hidden, path } = item;
|
|
@@ -5108,7 +5119,7 @@ var UnlinkedKeeper = class {
|
|
|
5108
5119
|
if (!back.has(hidden)) back.set(hidden, await this.moveBack(hidden, path));
|
|
5109
5120
|
if (back.get(hidden)) item.hidden = void 0;
|
|
5110
5121
|
}
|
|
5111
|
-
for (const { hidden, path, local: local2, file } of
|
|
5122
|
+
for (const { hidden, path, local: local2, file } of shared2) {
|
|
5112
5123
|
if (!back.get(hidden) || !file) continue;
|
|
5113
5124
|
for (const holder of local2) {
|
|
5114
5125
|
holder.unkeep(path, file);
|
|
@@ -7464,6 +7475,142 @@ var Integrity = class {
|
|
|
7464
7475
|
}
|
|
7465
7476
|
};
|
|
7466
7477
|
|
|
7478
|
+
// src/fs/path-map.ts
|
|
7479
|
+
function parentOf4(path) {
|
|
7480
|
+
if (path === "/" || path === "") return void 0;
|
|
7481
|
+
const at = path.lastIndexOf("/");
|
|
7482
|
+
return at <= 0 ? "/" : path.slice(0, at);
|
|
7483
|
+
}
|
|
7484
|
+
var PathMap = class {
|
|
7485
|
+
values = /* @__PURE__ */ new Map();
|
|
7486
|
+
children = /* @__PURE__ */ new Map();
|
|
7487
|
+
get size() {
|
|
7488
|
+
return this.values.size;
|
|
7489
|
+
}
|
|
7490
|
+
has(path) {
|
|
7491
|
+
return this.values.has(path);
|
|
7492
|
+
}
|
|
7493
|
+
get(path) {
|
|
7494
|
+
return this.values.get(path);
|
|
7495
|
+
}
|
|
7496
|
+
keys() {
|
|
7497
|
+
return this.values.keys();
|
|
7498
|
+
}
|
|
7499
|
+
set(path, value2) {
|
|
7500
|
+
if (!this.values.has(path)) this.link(path);
|
|
7501
|
+
this.values.set(path, value2);
|
|
7502
|
+
return this;
|
|
7503
|
+
}
|
|
7504
|
+
delete(path) {
|
|
7505
|
+
if (!this.values.delete(path)) return false;
|
|
7506
|
+
this.prune(path);
|
|
7507
|
+
return true;
|
|
7508
|
+
}
|
|
7509
|
+
subtree(root) {
|
|
7510
|
+
const out = [];
|
|
7511
|
+
const stack = [root];
|
|
7512
|
+
for (let path = stack.pop(); path !== void 0; path = stack.pop()) {
|
|
7513
|
+
if (this.values.has(path)) out.push(path);
|
|
7514
|
+
const below = this.children.get(path);
|
|
7515
|
+
if (below) for (const child of below) stack.push(child);
|
|
7516
|
+
}
|
|
7517
|
+
return out;
|
|
7518
|
+
}
|
|
7519
|
+
entries() {
|
|
7520
|
+
return this.values.entries();
|
|
7521
|
+
}
|
|
7522
|
+
deleteTree(root) {
|
|
7523
|
+
const stack = [root];
|
|
7524
|
+
for (let path = stack.pop(); path !== void 0; path = stack.pop()) {
|
|
7525
|
+
this.values.delete(path);
|
|
7526
|
+
const below = this.children.get(path);
|
|
7527
|
+
if (below) for (const child of below) stack.push(child);
|
|
7528
|
+
this.children.delete(path);
|
|
7529
|
+
}
|
|
7530
|
+
this.prune(root);
|
|
7531
|
+
}
|
|
7532
|
+
clear() {
|
|
7533
|
+
this.values.clear();
|
|
7534
|
+
this.children.clear();
|
|
7535
|
+
}
|
|
7536
|
+
link(path) {
|
|
7537
|
+
for (let child = path, parent = parentOf4(path); parent !== void 0; ) {
|
|
7538
|
+
const set3 = this.children.get(parent);
|
|
7539
|
+
if (set3?.has(child)) return;
|
|
7540
|
+
if (set3) set3.add(child);
|
|
7541
|
+
else this.children.set(parent, /* @__PURE__ */ new Set([child]));
|
|
7542
|
+
child = parent;
|
|
7543
|
+
parent = parentOf4(parent);
|
|
7544
|
+
}
|
|
7545
|
+
}
|
|
7546
|
+
prune(path) {
|
|
7547
|
+
for (let child = path, parent = parentOf4(path); parent !== void 0; ) {
|
|
7548
|
+
if (this.values.has(child) || this.children.has(child)) return;
|
|
7549
|
+
const set3 = this.children.get(parent);
|
|
7550
|
+
set3?.delete(child);
|
|
7551
|
+
if (set3 && set3.size > 0) return;
|
|
7552
|
+
this.children.delete(parent);
|
|
7553
|
+
child = parent;
|
|
7554
|
+
parent = parentOf4(parent);
|
|
7555
|
+
}
|
|
7556
|
+
}
|
|
7557
|
+
};
|
|
7558
|
+
|
|
7559
|
+
// src/fs/meta.ts
|
|
7560
|
+
var META_DB = "slicc-kernel";
|
|
7561
|
+
function parentOf5(path) {
|
|
7562
|
+
return path.slice(0, path.lastIndexOf("/")) || "/";
|
|
7563
|
+
}
|
|
7564
|
+
function moved(entry, path) {
|
|
7565
|
+
return entry.link === void 0 ? { ...entry, path } : { ...entry, path, dir: parentOf5(path) };
|
|
7566
|
+
}
|
|
7567
|
+
function under2(path, root) {
|
|
7568
|
+
return path === root || path.startsWith(`${root}/`);
|
|
7569
|
+
}
|
|
7570
|
+
var MemoryMeta = class {
|
|
7571
|
+
entries = new PathMap();
|
|
7572
|
+
async get(paths) {
|
|
7573
|
+
return paths.map((path) => this.entries.get(path));
|
|
7574
|
+
}
|
|
7575
|
+
async fresh(paths) {
|
|
7576
|
+
return this.get(paths);
|
|
7577
|
+
}
|
|
7578
|
+
async update(path, change) {
|
|
7579
|
+
this.set(path, change(this.entries.get(path)));
|
|
7580
|
+
}
|
|
7581
|
+
set(path, entry) {
|
|
7582
|
+
if (entry) this.entries.set(path, entry);
|
|
7583
|
+
else this.entries.delete(path);
|
|
7584
|
+
}
|
|
7585
|
+
async move(from, to, root, left) {
|
|
7586
|
+
await this.remove([to]);
|
|
7587
|
+
const carried = this.entries.subtree(from).map((path) => this.entries.get(path));
|
|
7588
|
+
for (const entry of carried) this.entries.delete(entry.path);
|
|
7589
|
+
for (const entry of carried) {
|
|
7590
|
+
const path = to + entry.path.slice(from.length);
|
|
7591
|
+
if (path !== to) this.entries.set(path, moved(entry, path));
|
|
7592
|
+
}
|
|
7593
|
+
this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));
|
|
7594
|
+
if (left) this.entries.set(from, left);
|
|
7595
|
+
}
|
|
7596
|
+
async remove(paths, left) {
|
|
7597
|
+
for (const path of paths) this.entries.deleteTree(path);
|
|
7598
|
+
if (left) this.entries.set(left.path, left);
|
|
7599
|
+
}
|
|
7600
|
+
absent(path) {
|
|
7601
|
+
return !this.entries.has(path);
|
|
7602
|
+
}
|
|
7603
|
+
async links(dir) {
|
|
7604
|
+
return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);
|
|
7605
|
+
}
|
|
7606
|
+
async under(path) {
|
|
7607
|
+
return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under2(entry.path, path));
|
|
7608
|
+
}
|
|
7609
|
+
async all() {
|
|
7610
|
+
return [...this.entries.entries()].map(([, e]) => e);
|
|
7611
|
+
}
|
|
7612
|
+
};
|
|
7613
|
+
|
|
7467
7614
|
// src/fs/physical-path.ts
|
|
7468
7615
|
var MAX_HOPS3 = 40;
|
|
7469
7616
|
function start(path) {
|
|
@@ -7515,11 +7662,11 @@ async function physicalPathAsync(fs, path) {
|
|
|
7515
7662
|
var WATCH_NOTES_LIMIT = 1e3;
|
|
7516
7663
|
var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
7517
7664
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
7518
|
-
var
|
|
7519
|
-
var
|
|
7665
|
+
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
7666
|
+
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
7520
7667
|
function touches(watcher, changed) {
|
|
7521
7668
|
return watcher.paths.some(
|
|
7522
|
-
(watched) => changed === watched ||
|
|
7669
|
+
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) : parentOf6(changed) === watched)
|
|
7523
7670
|
);
|
|
7524
7671
|
}
|
|
7525
7672
|
var REALS_KEPT = 4096;
|
|
@@ -7542,13 +7689,13 @@ function route(watch, type, path, seq2) {
|
|
|
7542
7689
|
for (const root of watch.roots) if (routed(watch, root, type, path, seq2)) return;
|
|
7543
7690
|
}
|
|
7544
7691
|
function routed(watch, root, type, path, seq2) {
|
|
7545
|
-
if (path === root || type === "rename" && root !== "/" &&
|
|
7692
|
+
if (path === root || type === "rename" && root !== "/" && under3(root, path)) {
|
|
7546
7693
|
noted(watch, { type, filename: watch.names.get(root) ?? baseOf2(root), seq: seq2 });
|
|
7547
7694
|
if (type === "rename") noted(watch, { ended: true, seq: seq2 });
|
|
7548
7695
|
return true;
|
|
7549
7696
|
}
|
|
7550
|
-
if (
|
|
7551
|
-
else if (watch.recursive &&
|
|
7697
|
+
if (parentOf6(path) === root) noted(watch, { type, filename: baseOf2(path), seq: seq2 });
|
|
7698
|
+
else if (watch.recursive && under3(path, root)) {
|
|
7552
7699
|
noted(watch, { type, filename: path.slice(root === "/" ? 1 : root.length + 1), seq: seq2 });
|
|
7553
7700
|
} else return false;
|
|
7554
7701
|
return true;
|
|
@@ -7632,7 +7779,7 @@ var FsWatchers = class {
|
|
|
7632
7779
|
covers(path) {
|
|
7633
7780
|
for (const watch of this.typed) {
|
|
7634
7781
|
for (const root of watch.roots) {
|
|
7635
|
-
if (path === root ||
|
|
7782
|
+
if (path === root || parentOf6(path) === root || watch.recursive && under3(path, root))
|
|
7636
7783
|
return true;
|
|
7637
7784
|
}
|
|
7638
7785
|
}
|
|
@@ -7689,7 +7836,7 @@ var FsWatchers = class {
|
|
|
7689
7836
|
const at = normalizePath(path);
|
|
7690
7837
|
const seq2 = ++this.seq;
|
|
7691
7838
|
for (const watch of [...this.typed]) {
|
|
7692
|
-
if (type === "rename" && watch.roots.some((root) => at === root ||
|
|
7839
|
+
if (type === "rename" && watch.roots.some((root) => at === root || under3(root, at)))
|
|
7693
7840
|
continue;
|
|
7694
7841
|
if (type === "change" && watch.directory && watch.roots.includes(at)) continue;
|
|
7695
7842
|
route(watch, type, at, seq2);
|
|
@@ -8921,7 +9068,7 @@ var FifoTable = class {
|
|
|
8921
9068
|
// src/kernel/held-cwd.ts
|
|
8922
9069
|
var CWD_SLOTS = 1024;
|
|
8923
9070
|
var UNTRACKED = CWD_SLOTS - 1;
|
|
8924
|
-
var
|
|
9071
|
+
var under4 = (path, changed) => changed === "/" || path === changed || path.startsWith(`${changed}/`);
|
|
8925
9072
|
var CwdTable = class {
|
|
8926
9073
|
sab = new SharedArrayBuffer(CWD_SLOTS * 4);
|
|
8927
9074
|
view = new Int32Array(this.sab);
|
|
@@ -8934,8 +9081,8 @@ var CwdTable = class {
|
|
|
8934
9081
|
this.inodeOf = inodeOf2;
|
|
8935
9082
|
}
|
|
8936
9083
|
async hold(path, from) {
|
|
8937
|
-
const
|
|
8938
|
-
if (
|
|
9084
|
+
const shared2 = from === void 0 ? void 0 : this.held.get(from);
|
|
9085
|
+
if (shared2 && shared2.path === path) return this.share(from);
|
|
8939
9086
|
const ino = await this.inodeOf(path).catch(() => void 0);
|
|
8940
9087
|
const slot2 = this.free.pop() ?? (this.next < UNTRACKED ? this.next++ : UNTRACKED);
|
|
8941
9088
|
if (slot2 === UNTRACKED) return slot2;
|
|
@@ -8969,7 +9116,7 @@ var CwdTable = class {
|
|
|
8969
9116
|
if (this.held.size === 0) return;
|
|
8970
9117
|
for (const [slot2, held] of this.held) {
|
|
8971
9118
|
if (held.dead) continue;
|
|
8972
|
-
if (paths.some((p) =>
|
|
9119
|
+
if (paths.some((p) => under4(held.path, p)) || trees.some((t) => under4(held.path, t))) {
|
|
8973
9120
|
Atomics.add(this.view, slot2, 1);
|
|
8974
9121
|
}
|
|
8975
9122
|
}
|
|
@@ -9427,7 +9574,7 @@ var HeldPaths = class extends Map {
|
|
|
9427
9574
|
return this.revoked.has(path);
|
|
9428
9575
|
}
|
|
9429
9576
|
};
|
|
9430
|
-
var
|
|
9577
|
+
var parentOf7 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
9431
9578
|
var readonly = (mount) => mount.caps.readonly === true || mount.options.ro !== void 0;
|
|
9432
9579
|
function inodeless(mount, attr2) {
|
|
9433
9580
|
if (attr2.ino !== void 0) return false;
|
|
@@ -9727,7 +9874,7 @@ var MountTable = class {
|
|
|
9727
9874
|
for (const [key, cached] of [...mount.attrs])
|
|
9728
9875
|
if (within5(key, path) || linked2(cached.value)) mount.attrs.delete(key);
|
|
9729
9876
|
mount.lists.delete(path);
|
|
9730
|
-
mount.lists.delete(
|
|
9877
|
+
mount.lists.delete(parentOf7(path));
|
|
9731
9878
|
for (const [key, cached] of [...mount.lists])
|
|
9732
9879
|
if (within5(key, path) || cached.value.some((e) => linked2(e.attr))) mount.lists.delete(key);
|
|
9733
9880
|
}
|
|
@@ -9848,7 +9995,7 @@ var MountFs = class _MountFs {
|
|
|
9848
9995
|
const real = normalizePath(path);
|
|
9849
9996
|
if (this.at(real)) return real;
|
|
9850
9997
|
try {
|
|
9851
|
-
await this.base.stat(
|
|
9998
|
+
await this.base.stat(parentOf7(real));
|
|
9852
9999
|
return real;
|
|
9853
10000
|
} catch (err) {
|
|
9854
10001
|
const moved2 = redirectOf(err);
|
|
@@ -9890,7 +10037,7 @@ var MountFs = class _MountFs {
|
|
|
9890
10037
|
if (this.rejectLinks) throw errnoError("ELOOP", path);
|
|
9891
10038
|
if (hops >= MAX_LINKS5) throw errnoError("ELOOP", path);
|
|
9892
10039
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
9893
|
-
return this.follow(this.base.resolvePath(
|
|
10040
|
+
return this.follow(this.base.resolvePath(parentOf7(real), target), hops + 1, create);
|
|
9894
10041
|
}
|
|
9895
10042
|
async open(mount, rel2, write, owner, create = write) {
|
|
9896
10043
|
return await mount.conn.call({
|
|
@@ -9906,8 +10053,8 @@ var MountFs = class _MountFs {
|
|
|
9906
10053
|
async driverOwner(found, real, owner, directory) {
|
|
9907
10054
|
const { mount, rel: rel2 } = found;
|
|
9908
10055
|
if (!owner || !mount.owners || !mount.caps.owners) return void 0;
|
|
9909
|
-
const dir =
|
|
9910
|
-
const above = statOf2(await this.table.getattr(mount, dir,
|
|
10056
|
+
const dir = parentOf7(real);
|
|
10057
|
+
const above = statOf2(await this.table.getattr(mount, dir, parentOf7(rel2)), dir, mount);
|
|
9911
10058
|
const setgid = (above.mode & S_ISGID3) !== 0;
|
|
9912
10059
|
let mode = owner.mode;
|
|
9913
10060
|
if (directory && setgid) mode = (mode ?? 493) | S_ISGID3;
|
|
@@ -10426,7 +10573,7 @@ var MountFs = class _MountFs {
|
|
|
10426
10573
|
}
|
|
10427
10574
|
async named(path) {
|
|
10428
10575
|
const at = normalizePath(path);
|
|
10429
|
-
return joinName(await realDir(this,
|
|
10576
|
+
return joinName(await realDir(this, parentOf7(at)), at.slice(at.lastIndexOf("/") + 1));
|
|
10430
10577
|
}
|
|
10431
10578
|
async link(source, target, follow2 = false) {
|
|
10432
10579
|
const from = follow2 ? await realTarget(this, normalizePath(source)) : await this.named(source);
|
|
@@ -10956,7 +11103,7 @@ async function guard(g, path, req, cwd) {
|
|
|
10956
11103
|
return { path: w };
|
|
10957
11104
|
}
|
|
10958
11105
|
case "mkdir": {
|
|
10959
|
-
await makeIn(g, op, path);
|
|
11106
|
+
await makeIn(g, op, path, !req.exclusive);
|
|
10960
11107
|
return { path: await walkSafe(g, path, false) };
|
|
10961
11108
|
}
|
|
10962
11109
|
case "create":
|
|
@@ -13316,13 +13463,13 @@ async function flock(req, ctx) {
|
|
|
13316
13463
|
if (!FLOCK_KINDS.has(req.kind)) throw new KernelError("EINVAL");
|
|
13317
13464
|
const { key, owner } = await flockOf(req.fd);
|
|
13318
13465
|
const granted2 = req.kind !== "unlock";
|
|
13319
|
-
const
|
|
13320
|
-
if (
|
|
13466
|
+
const shared2 = locks.shared?.() === true;
|
|
13467
|
+
if (shared2 && !granted2) await ctx.settle?.(req.fd, false);
|
|
13321
13468
|
if (req.kind !== "unlock" && req.wait)
|
|
13322
13469
|
await locks.flocks.wait(key, owner, req.kind, ctx.blocking);
|
|
13323
13470
|
else if (!await locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
|
|
13324
|
-
if (
|
|
13325
|
-
return
|
|
13471
|
+
if (shared2 && granted2) await grantedAcross(ctx, req.fd);
|
|
13472
|
+
return shared2 ? json3(true) : done2;
|
|
13326
13473
|
}
|
|
13327
13474
|
async function grantedAcross(ctx, fd) {
|
|
13328
13475
|
ctx.locks?.fresh?.();
|
|
@@ -13350,15 +13497,15 @@ async function recordLock2(req, ctx) {
|
|
|
13350
13497
|
return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
|
|
13351
13498
|
}
|
|
13352
13499
|
const granted2 = req.kind !== "unlock";
|
|
13353
|
-
const
|
|
13354
|
-
const fd =
|
|
13500
|
+
const shared2 = locks.shared?.() === true;
|
|
13501
|
+
const fd = shared2 ? req.fd : void 0;
|
|
13355
13502
|
if (!granted2 && fd !== void 0) await ctx.settle?.(fd, false);
|
|
13356
13503
|
if (req.kind !== "unlock" && req.wait)
|
|
13357
13504
|
await locks.wait(key, owner, req.kind, range2, ctx.blocking);
|
|
13358
13505
|
else if (!await locks.set(key, owner, req.kind, range2.start, range2.end))
|
|
13359
13506
|
throw new KernelError("EAGAIN");
|
|
13360
|
-
if (granted2 &&
|
|
13361
|
-
return
|
|
13507
|
+
if (granted2 && shared2) await grantedAcross(ctx, fd);
|
|
13508
|
+
return shared2 ? json3(true) : done2;
|
|
13362
13509
|
}
|
|
13363
13510
|
|
|
13364
13511
|
// src/kernel/net/loopback-transport.ts
|
|
@@ -19438,9 +19585,9 @@ function pausing(signal) {
|
|
|
19438
19585
|
return { pausedAt, select };
|
|
19439
19586
|
}
|
|
19440
19587
|
async function serveSecure(proc, socket, req) {
|
|
19441
|
-
const
|
|
19442
|
-
if (req.listener && !
|
|
19443
|
-
const server =
|
|
19588
|
+
const shared2 = req.listener?.serving;
|
|
19589
|
+
if (req.listener && !shared2) throw new KernelError("EINVAL", "the listener has no tls");
|
|
19590
|
+
const server = shared2 ?? await serverOf(proc, req);
|
|
19444
19591
|
const { engine, leaf, alpn, store, flags: flags2 } = server;
|
|
19445
19592
|
const limit = handshakeSignal(proc, server.timeoutMs);
|
|
19446
19593
|
const { pausedAt, select } = pausing(limit.signal);
|
|
@@ -19454,12 +19601,12 @@ async function serveSecure(proc, socket, req) {
|
|
|
19454
19601
|
(flags2 & TLS_KEYLOG) !== 0
|
|
19455
19602
|
),
|
|
19456
19603
|
limit.signal,
|
|
19457
|
-
(reason) => !
|
|
19604
|
+
(reason) => !shared2 && reason === timedOut
|
|
19458
19605
|
).finally(() => {
|
|
19459
19606
|
limit.done();
|
|
19460
19607
|
selections.delete(socket);
|
|
19461
19608
|
socket.pending = void 0;
|
|
19462
|
-
if (!
|
|
19609
|
+
if (!shared2) server.release();
|
|
19463
19610
|
});
|
|
19464
19611
|
run2.catch(() => void 0);
|
|
19465
19612
|
const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
|
|
@@ -21075,7 +21222,7 @@ function isWatchSyscall(req) {
|
|
|
21075
21222
|
return WATCHING.has(req.op);
|
|
21076
21223
|
}
|
|
21077
21224
|
var WATCHES_MAX = 8192;
|
|
21078
|
-
var
|
|
21225
|
+
var parentOf8 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
21079
21226
|
function visibleTo(watch, root, visible) {
|
|
21080
21227
|
return {
|
|
21081
21228
|
close: () => watch.close(),
|
|
@@ -21086,7 +21233,7 @@ function visibleTo(watch, root, visible) {
|
|
|
21086
21233
|
notes.map(async (note) => {
|
|
21087
21234
|
if (!("filename" in note) || !note.filename.includes("/")) return true;
|
|
21088
21235
|
const at = watch.root?.() ?? root;
|
|
21089
|
-
const dir =
|
|
21236
|
+
const dir = parentOf8(`${at === "/" ? "" : at}/${note.filename}`);
|
|
21090
21237
|
if (!seen.has(dir)) seen.set(dir, visible(dir));
|
|
21091
21238
|
return seen.get(dir);
|
|
21092
21239
|
})
|
|
@@ -25129,6 +25276,39 @@ var RenameLog = class {
|
|
|
25129
25276
|
}
|
|
25130
25277
|
};
|
|
25131
25278
|
|
|
25279
|
+
// src/kernel/replacing.ts
|
|
25280
|
+
var REPLACING_LOCK = "slicc-kernel-replacing:v1:";
|
|
25281
|
+
function replacingLocks(scope = globalThis) {
|
|
25282
|
+
const locks = scope.navigator?.locks;
|
|
25283
|
+
return typeof locks?.request === "function" ? locks : void 0;
|
|
25284
|
+
}
|
|
25285
|
+
function replacingLock(metadata, root) {
|
|
25286
|
+
return `${REPLACING_LOCK}${metadata}:${root}`;
|
|
25287
|
+
}
|
|
25288
|
+
function shared(locks, names2, run2, waited) {
|
|
25289
|
+
const [name2, ...rest2] = names2;
|
|
25290
|
+
if (name2 === void 0) return run2(waited);
|
|
25291
|
+
const next3 = (after) => shared(locks, rest2, run2, after);
|
|
25292
|
+
return locks.request(
|
|
25293
|
+
name2,
|
|
25294
|
+
{ mode: "shared", ifAvailable: true },
|
|
25295
|
+
(lock) => lock ? next3(waited) : locks.request(name2, { mode: "shared" }, () => next3(true))
|
|
25296
|
+
);
|
|
25297
|
+
}
|
|
25298
|
+
var PackageLocks = class {
|
|
25299
|
+
locks;
|
|
25300
|
+
metadata;
|
|
25301
|
+
constructor(metadata, locks = replacingLocks()) {
|
|
25302
|
+
this.metadata = metadata;
|
|
25303
|
+
this.locks = locks;
|
|
25304
|
+
}
|
|
25305
|
+
loading(roots, run2) {
|
|
25306
|
+
if (!this.locks || roots.length === 0) return run2(false);
|
|
25307
|
+
const names2 = roots.map((root) => replacingLock(this.metadata, root));
|
|
25308
|
+
return shared(this.locks, names2, run2, false);
|
|
25309
|
+
}
|
|
25310
|
+
};
|
|
25311
|
+
|
|
25132
25312
|
// src/kernel/settling.ts
|
|
25133
25313
|
var SETUP_OPS = /* @__PURE__ */ new Set([
|
|
25134
25314
|
"proc-list",
|
|
@@ -25425,141 +25605,6 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
|
|
|
25425
25605
|
return { invalidate: (paths) => reply({ invalidate: paths }) };
|
|
25426
25606
|
}
|
|
25427
25607
|
|
|
25428
|
-
// src/fs/path-map.ts
|
|
25429
|
-
function parentOf7(path) {
|
|
25430
|
-
if (path === "/" || path === "") return void 0;
|
|
25431
|
-
const at = path.lastIndexOf("/");
|
|
25432
|
-
return at <= 0 ? "/" : path.slice(0, at);
|
|
25433
|
-
}
|
|
25434
|
-
var PathMap = class {
|
|
25435
|
-
values = /* @__PURE__ */ new Map();
|
|
25436
|
-
children = /* @__PURE__ */ new Map();
|
|
25437
|
-
get size() {
|
|
25438
|
-
return this.values.size;
|
|
25439
|
-
}
|
|
25440
|
-
has(path) {
|
|
25441
|
-
return this.values.has(path);
|
|
25442
|
-
}
|
|
25443
|
-
get(path) {
|
|
25444
|
-
return this.values.get(path);
|
|
25445
|
-
}
|
|
25446
|
-
keys() {
|
|
25447
|
-
return this.values.keys();
|
|
25448
|
-
}
|
|
25449
|
-
set(path, value2) {
|
|
25450
|
-
if (!this.values.has(path)) this.link(path);
|
|
25451
|
-
this.values.set(path, value2);
|
|
25452
|
-
return this;
|
|
25453
|
-
}
|
|
25454
|
-
delete(path) {
|
|
25455
|
-
if (!this.values.delete(path)) return false;
|
|
25456
|
-
this.prune(path);
|
|
25457
|
-
return true;
|
|
25458
|
-
}
|
|
25459
|
-
subtree(root) {
|
|
25460
|
-
const out = [];
|
|
25461
|
-
const stack = [root];
|
|
25462
|
-
for (let path = stack.pop(); path !== void 0; path = stack.pop()) {
|
|
25463
|
-
if (this.values.has(path)) out.push(path);
|
|
25464
|
-
const below = this.children.get(path);
|
|
25465
|
-
if (below) for (const child of below) stack.push(child);
|
|
25466
|
-
}
|
|
25467
|
-
return out;
|
|
25468
|
-
}
|
|
25469
|
-
entries() {
|
|
25470
|
-
return this.values.entries();
|
|
25471
|
-
}
|
|
25472
|
-
deleteTree(root) {
|
|
25473
|
-
const stack = [root];
|
|
25474
|
-
for (let path = stack.pop(); path !== void 0; path = stack.pop()) {
|
|
25475
|
-
this.values.delete(path);
|
|
25476
|
-
const below = this.children.get(path);
|
|
25477
|
-
if (below) for (const child of below) stack.push(child);
|
|
25478
|
-
this.children.delete(path);
|
|
25479
|
-
}
|
|
25480
|
-
this.prune(root);
|
|
25481
|
-
}
|
|
25482
|
-
clear() {
|
|
25483
|
-
this.values.clear();
|
|
25484
|
-
this.children.clear();
|
|
25485
|
-
}
|
|
25486
|
-
link(path) {
|
|
25487
|
-
for (let child = path, parent = parentOf7(path); parent !== void 0; ) {
|
|
25488
|
-
const set3 = this.children.get(parent);
|
|
25489
|
-
if (set3?.has(child)) return;
|
|
25490
|
-
if (set3) set3.add(child);
|
|
25491
|
-
else this.children.set(parent, /* @__PURE__ */ new Set([child]));
|
|
25492
|
-
child = parent;
|
|
25493
|
-
parent = parentOf7(parent);
|
|
25494
|
-
}
|
|
25495
|
-
}
|
|
25496
|
-
prune(path) {
|
|
25497
|
-
for (let child = path, parent = parentOf7(path); parent !== void 0; ) {
|
|
25498
|
-
if (this.values.has(child) || this.children.has(child)) return;
|
|
25499
|
-
const set3 = this.children.get(parent);
|
|
25500
|
-
set3?.delete(child);
|
|
25501
|
-
if (set3 && set3.size > 0) return;
|
|
25502
|
-
this.children.delete(parent);
|
|
25503
|
-
child = parent;
|
|
25504
|
-
parent = parentOf7(parent);
|
|
25505
|
-
}
|
|
25506
|
-
}
|
|
25507
|
-
};
|
|
25508
|
-
|
|
25509
|
-
// src/fs/meta.ts
|
|
25510
|
-
function parentOf8(path) {
|
|
25511
|
-
return path.slice(0, path.lastIndexOf("/")) || "/";
|
|
25512
|
-
}
|
|
25513
|
-
function moved(entry, path) {
|
|
25514
|
-
return entry.link === void 0 ? { ...entry, path } : { ...entry, path, dir: parentOf8(path) };
|
|
25515
|
-
}
|
|
25516
|
-
function under4(path, root) {
|
|
25517
|
-
return path === root || path.startsWith(`${root}/`);
|
|
25518
|
-
}
|
|
25519
|
-
var MemoryMeta = class {
|
|
25520
|
-
entries = new PathMap();
|
|
25521
|
-
async get(paths) {
|
|
25522
|
-
return paths.map((path) => this.entries.get(path));
|
|
25523
|
-
}
|
|
25524
|
-
async fresh(paths) {
|
|
25525
|
-
return this.get(paths);
|
|
25526
|
-
}
|
|
25527
|
-
async update(path, change) {
|
|
25528
|
-
this.set(path, change(this.entries.get(path)));
|
|
25529
|
-
}
|
|
25530
|
-
set(path, entry) {
|
|
25531
|
-
if (entry) this.entries.set(path, entry);
|
|
25532
|
-
else this.entries.delete(path);
|
|
25533
|
-
}
|
|
25534
|
-
async move(from, to, root, left) {
|
|
25535
|
-
await this.remove([to]);
|
|
25536
|
-
const carried = this.entries.subtree(from).map((path) => this.entries.get(path));
|
|
25537
|
-
for (const entry of carried) this.entries.delete(entry.path);
|
|
25538
|
-
for (const entry of carried) {
|
|
25539
|
-
const path = to + entry.path.slice(from.length);
|
|
25540
|
-
if (path !== to) this.entries.set(path, moved(entry, path));
|
|
25541
|
-
}
|
|
25542
|
-
this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));
|
|
25543
|
-
if (left) this.entries.set(from, left);
|
|
25544
|
-
}
|
|
25545
|
-
async remove(paths, left) {
|
|
25546
|
-
for (const path of paths) this.entries.deleteTree(path);
|
|
25547
|
-
if (left) this.entries.set(left.path, left);
|
|
25548
|
-
}
|
|
25549
|
-
absent(path) {
|
|
25550
|
-
return !this.entries.has(path);
|
|
25551
|
-
}
|
|
25552
|
-
async links(dir) {
|
|
25553
|
-
return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);
|
|
25554
|
-
}
|
|
25555
|
-
async under(path) {
|
|
25556
|
-
return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under4(entry.path, path));
|
|
25557
|
-
}
|
|
25558
|
-
async all() {
|
|
25559
|
-
return [...this.entries.entries()].map(([, e]) => e);
|
|
25560
|
-
}
|
|
25561
|
-
};
|
|
25562
|
-
|
|
25563
25608
|
// src/fs/notice.ts
|
|
25564
25609
|
function noticeOf(data) {
|
|
25565
25610
|
if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === "string"), trees: [] };
|
|
@@ -25868,9 +25913,11 @@ var OpfsFs = class {
|
|
|
25868
25913
|
this.channel.onmessage = ({ data }) => {
|
|
25869
25914
|
const { paths, trees, outside } = noticeOf(data);
|
|
25870
25915
|
for (const path of [...paths, ...trees]) this.forget(normalizePath(path));
|
|
25871
|
-
|
|
25872
|
-
|
|
25873
|
-
|
|
25916
|
+
if (!outside) remote?.emit({ paths, trees });
|
|
25917
|
+
else
|
|
25918
|
+
void this.noticed(paths.map(normalizePath), Date.now()).finally(
|
|
25919
|
+
() => remote?.emit({ paths, trees, outside: true })
|
|
25920
|
+
);
|
|
25874
25921
|
};
|
|
25875
25922
|
this.channel.unref?.();
|
|
25876
25923
|
}
|
|
@@ -26236,6 +26283,9 @@ var OpfsFs = class {
|
|
|
26236
26283
|
this.exact--;
|
|
26237
26284
|
}
|
|
26238
26285
|
}
|
|
26286
|
+
refresh(trees) {
|
|
26287
|
+
for (const tree2 of trees) this.forget(normalizePath(tree2));
|
|
26288
|
+
}
|
|
26239
26289
|
forget(path) {
|
|
26240
26290
|
this.changes++;
|
|
26241
26291
|
this.dirs.deleteTree(path);
|
|
@@ -26953,6 +27003,10 @@ var OpfsFs = class {
|
|
|
26953
27003
|
const children3 = /* @__PURE__ */ new Map();
|
|
26954
27004
|
this.others++;
|
|
26955
27005
|
for await (const child of handle.values()) children3.set(child.name, child);
|
|
27006
|
+
if (this.absent.size > 0) {
|
|
27007
|
+
const base = found.path === "/" ? "" : found.path;
|
|
27008
|
+
for (const name2 of children3.keys()) this.absent.delete(`${base}/${name2}`);
|
|
27009
|
+
}
|
|
26956
27010
|
for (const link2 of await this.meta.links(found.path)) {
|
|
26957
27011
|
const name2 = baseOf3(link2.path);
|
|
26958
27012
|
if (!children3.has(name2)) children3.set(name2, link2);
|
|
@@ -29671,14 +29725,14 @@ var UserDb = class {
|
|
|
29671
29725
|
this.fs = fs;
|
|
29672
29726
|
this.owners = owners;
|
|
29673
29727
|
}
|
|
29674
|
-
async stampHome(row,
|
|
29728
|
+
async stampHome(row, shared2, homeMode) {
|
|
29675
29729
|
const home = this.fs.resolvePath("/", row.home);
|
|
29676
29730
|
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
29677
29731
|
if (!await this.realDir(home)) return;
|
|
29678
|
-
const gid =
|
|
29732
|
+
const gid = shared2?.gid ?? row.gid;
|
|
29679
29733
|
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
29680
29734
|
const scoop = row.name.startsWith("scoop-");
|
|
29681
|
-
await this.fs.chmod(home, homeMode ?? (
|
|
29735
|
+
await this.fs.chmod(home, homeMode ?? (shared2 ? 1512 : scoop ? 488 : 448));
|
|
29682
29736
|
const pnpm = `${home}/.local/share/pnpm`;
|
|
29683
29737
|
if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
|
|
29684
29738
|
}
|
|
@@ -29715,9 +29769,9 @@ var UserDb = class {
|
|
|
29715
29769
|
const [passwd, group] = await this.texts();
|
|
29716
29770
|
return { passwd: parsePasswd(passwd), group: parseGroup(group) };
|
|
29717
29771
|
}
|
|
29718
|
-
async provision(row, umask,
|
|
29719
|
-
const dirs = 511 & ~umask | (
|
|
29720
|
-
const gid =
|
|
29772
|
+
async provision(row, umask, shared2) {
|
|
29773
|
+
const dirs = 511 & ~umask | (shared2 ? 1024 : 0);
|
|
29774
|
+
const gid = shared2?.gid ?? row.gid;
|
|
29721
29775
|
const owner = this.owners ? { uid: row.uid, gid } : void 0;
|
|
29722
29776
|
const made2 = owner ? { recursive: true, owner: { ...owner, mode: dirs, parents: dirs } } : { recursive: true };
|
|
29723
29777
|
const pnpm = `${row.home}/.local/share/pnpm`;
|
|
@@ -29821,7 +29875,7 @@ var UserDb = class {
|
|
|
29821
29875
|
const users = parsed(passwd);
|
|
29822
29876
|
const groups = parsed(group);
|
|
29823
29877
|
const found = users.find((r) => r.name === name2);
|
|
29824
|
-
const
|
|
29878
|
+
const shared2 = homeGroupOf(groups, options.homeGroup);
|
|
29825
29879
|
const homeMode = homeModeOf(options.homeMode);
|
|
29826
29880
|
if (found) {
|
|
29827
29881
|
const more = groupsOf(groups, options.groups ?? []);
|
|
@@ -29829,8 +29883,8 @@ var UserDb = class {
|
|
|
29829
29883
|
throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
|
|
29830
29884
|
}
|
|
29831
29885
|
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
29832
|
-
await this.provision(found, this.umaskFor(options),
|
|
29833
|
-
await this.stampHome(found,
|
|
29886
|
+
await this.provision(found, this.umaskFor(options), shared2);
|
|
29887
|
+
await this.stampHome(found, shared2, homeMode);
|
|
29834
29888
|
}
|
|
29835
29889
|
if (joined4(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
29836
29890
|
remember();
|
|
@@ -29847,8 +29901,8 @@ var UserDb = class {
|
|
|
29847
29901
|
const fresh3 = !await this.fs.exists(home);
|
|
29848
29902
|
await this.fs.mkdir(home, { recursive: true });
|
|
29849
29903
|
try {
|
|
29850
|
-
await this.provision(row, this.umaskFor(options),
|
|
29851
|
-
await this.stampHome(row,
|
|
29904
|
+
await this.provision(row, this.umaskFor(options), shared2);
|
|
29905
|
+
await this.stampHome(row, shared2, homeMode);
|
|
29852
29906
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
29853
29907
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
29854
29908
|
} catch (err) {
|
|
@@ -29897,10 +29951,10 @@ var UserDb = class {
|
|
|
29897
29951
|
);
|
|
29898
29952
|
for (const r of parsed(keptGroups)) r.members = r.members.filter((m) => m !== name2);
|
|
29899
29953
|
const home = this.fs.resolvePath("/", row.home);
|
|
29900
|
-
const
|
|
29954
|
+
const shared2 = parsed(passwd).some(
|
|
29901
29955
|
(r) => r !== row && this.fs.resolvePath("/", r.home) === home
|
|
29902
29956
|
);
|
|
29903
|
-
const removeHome = !options.keepHome && !
|
|
29957
|
+
const removeHome = !options.keepHome && !shared2 && HOME_DIR.test(home) && await this.fs.exists(home);
|
|
29904
29958
|
const staged = `/home/.${name2}.removed-${Date.now()}`;
|
|
29905
29959
|
await this.commit(
|
|
29906
29960
|
formatPasswd(passwd.filter((r) => r !== row)),
|
|
@@ -30389,6 +30443,7 @@ var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
|
30389
30443
|
var SHIM_MARKER = /^\/\/ pnpm-wasm-shim=(\{.*\})$/gm;
|
|
30390
30444
|
var SHIM_MAX = 64 * 1024;
|
|
30391
30445
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
30446
|
+
var NODE_MODULES = /\/node_modules(?:\/|$)/;
|
|
30392
30447
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
30393
30448
|
var WASM_MAGIC = [0, 97, 115, 109];
|
|
30394
30449
|
var SHEBANG_MAX = 256;
|
|
@@ -30456,6 +30511,21 @@ function packageRootOf(path, roots) {
|
|
|
30456
30511
|
}
|
|
30457
30512
|
return void 0;
|
|
30458
30513
|
}
|
|
30514
|
+
function planFiles(planned) {
|
|
30515
|
+
const { target } = planned;
|
|
30516
|
+
const files = [
|
|
30517
|
+
target.glue,
|
|
30518
|
+
target.wasm,
|
|
30519
|
+
target.imports,
|
|
30520
|
+
target.copy,
|
|
30521
|
+
...(target.variants ?? []).map((variant) => variant.wasm),
|
|
30522
|
+
...planned.sources ?? []
|
|
30523
|
+
];
|
|
30524
|
+
return files.filter((file) => file !== void 0);
|
|
30525
|
+
}
|
|
30526
|
+
function sameList(a, b) {
|
|
30527
|
+
return a.length === b.length && a.every((item, i) => item === b[i]);
|
|
30528
|
+
}
|
|
30459
30529
|
function modulePath(glue) {
|
|
30460
30530
|
return glue.endsWith(".js") ? `${glue.slice(0, -3)}.wasm` : `${glue}.wasm`;
|
|
30461
30531
|
}
|
|
@@ -30629,6 +30699,7 @@ var Launcher = class {
|
|
|
30629
30699
|
sudoer;
|
|
30630
30700
|
jobs = new JobTable();
|
|
30631
30701
|
locks;
|
|
30702
|
+
packageLocks;
|
|
30632
30703
|
fifos = new FifoTable();
|
|
30633
30704
|
memories;
|
|
30634
30705
|
sems = new SemTable();
|
|
@@ -30701,6 +30772,7 @@ var Launcher = class {
|
|
|
30701
30772
|
this.memories = memoriesOf(options.wasmMemories);
|
|
30702
30773
|
this.rootFs = options.fs;
|
|
30703
30774
|
this.locks = kernelLocks(options.fs.rootName, this.flushingPeers(options.fs));
|
|
30775
|
+
this.packageLocks = new PackageLocks(options.packageLocks ?? META_DB);
|
|
30704
30776
|
this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
|
|
30705
30777
|
if (this.dac) this.wireDac(this.dac);
|
|
30706
30778
|
this.clipboard = new ClipboardBroker(
|
|
@@ -30794,15 +30866,7 @@ var Launcher = class {
|
|
|
30794
30866
|
this.nodes.keepsOnDisk = true;
|
|
30795
30867
|
this.openFiles.add(this.nodes);
|
|
30796
30868
|
options.fs.onPeer?.(() => this.flushOpen());
|
|
30797
|
-
options.fs.remoteChanges?.((change) =>
|
|
30798
|
-
this.held.doubt(change.paths, change.moved?.to);
|
|
30799
|
-
if (change.moved) this.moved(change.moved.from, change.moved.to);
|
|
30800
|
-
this.changes.flush();
|
|
30801
|
-
this.cwds.touched(change.paths, change.trees);
|
|
30802
|
-
this.rewritten(change.paths, change.trees);
|
|
30803
|
-
this.watchers.heard(change.content ? "change" : "rename", change.paths);
|
|
30804
|
-
this.watchers.heard("rename", change.trees ?? []);
|
|
30805
|
-
});
|
|
30869
|
+
options.fs.remoteChanges?.((change) => this.remoteChanged(change));
|
|
30806
30870
|
const holders = [this.held, this.openFiles];
|
|
30807
30871
|
options.fs.heldBy?.(
|
|
30808
30872
|
(dir) => holders.flatMap((set3) => [...set3].flatMap((holder) => [...holder.held()])).filter((p) => p.startsWith(`${dir}/`) && this.mounts.locate(p) === void 0)
|
|
@@ -31012,6 +31076,26 @@ var Launcher = class {
|
|
|
31012
31076
|
}
|
|
31013
31077
|
return trusted;
|
|
31014
31078
|
}
|
|
31079
|
+
remoteChanged(change) {
|
|
31080
|
+
this.held.doubt(change.paths, change.moved?.to);
|
|
31081
|
+
if (change.moved) this.moved(change.moved.from, change.moved.to);
|
|
31082
|
+
this.changes.flush();
|
|
31083
|
+
this.cwds.touched(change.paths, change.trees);
|
|
31084
|
+
this.rewritten(change.paths, change.trees);
|
|
31085
|
+
this.watchers.heard(change.content ? "change" : "rename", change.paths);
|
|
31086
|
+
this.watchers.heard("rename", change.trees ?? []);
|
|
31087
|
+
if (change.outside && this.catalogChanged([...change.paths, ...change.trees ?? []])) {
|
|
31088
|
+
this.resetCatalogs();
|
|
31089
|
+
}
|
|
31090
|
+
}
|
|
31091
|
+
catalogChanged(paths) {
|
|
31092
|
+
const roots = [this.modulesDir, this.pnpmHome, ...this.appended].map(normalizePath);
|
|
31093
|
+
return paths.map(normalizePath).some(
|
|
31094
|
+
(at) => at === "/" || NODE_MODULES.test(at) || roots.some(
|
|
31095
|
+
(root) => at === root || at.startsWith(`${root}/`) || root.startsWith(`${at}/`)
|
|
31096
|
+
)
|
|
31097
|
+
);
|
|
31098
|
+
}
|
|
31015
31099
|
resetCatalogs() {
|
|
31016
31100
|
this.catalogs.clear();
|
|
31017
31101
|
this.ownCatalogs.clear();
|
|
@@ -31412,7 +31496,11 @@ var Launcher = class {
|
|
|
31412
31496
|
secrets.push({ name: name2, value: value2, placeholder });
|
|
31413
31497
|
}
|
|
31414
31498
|
const scrub = scrubberOf(secrets);
|
|
31415
|
-
|
|
31499
|
+
const recheck = async (next3) => {
|
|
31500
|
+
const same2 = sameList(planFiles(next3), planFiles(planned)) && sameList(await this.interpreterChain(next3, booked.cwd, scope), interpreters) && (this.usersMode === "enforce" && await this.trustedFiles(next3, req.file, booked.cwd, scope)) === trusted;
|
|
31501
|
+
if (!same2) throw new SpawnError("EACCES");
|
|
31502
|
+
};
|
|
31503
|
+
return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {}, recheck };
|
|
31416
31504
|
}
|
|
31417
31505
|
async interpreterChain(planned, cwd, scope) {
|
|
31418
31506
|
const out = [];
|
|
@@ -31697,25 +31785,16 @@ var Launcher = class {
|
|
|
31697
31785
|
async launch(asked, req) {
|
|
31698
31786
|
const cwd = await physicalPathAsync(this.base, req.cwd);
|
|
31699
31787
|
const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
|
|
31700
|
-
const env = { ...expandDefaults(asked.target.env, seen), ...req.env };
|
|
31701
|
-
for (const key of asked.target.unset ?? []) delete env[key];
|
|
31702
|
-
delete env[TICKET_ENV];
|
|
31703
|
-
const own = env.HOSTNAME;
|
|
31704
|
-
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
31705
|
-
const planned = chosen2(asked, env);
|
|
31706
|
-
const { target, args } = planned;
|
|
31707
|
-
let program;
|
|
31708
|
-
let exeId;
|
|
31709
31788
|
await this.pnpmReady();
|
|
31789
|
+
let loaded;
|
|
31710
31790
|
try {
|
|
31711
|
-
|
|
31712
|
-
if (this.integrity) await this.checkedSources(planned, caller);
|
|
31713
|
-
[program, exeId] = await this.loaded(target, env, caller);
|
|
31714
|
-
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
31791
|
+
loaded = await this.loadedUnder(asked, (planned2) => this.loadPlanned(planned2, req, seen));
|
|
31715
31792
|
} catch (err) {
|
|
31716
31793
|
await req.fds.closeAll();
|
|
31717
31794
|
throw err;
|
|
31718
31795
|
}
|
|
31796
|
+
const { planned, env, program, exeId } = loaded;
|
|
31797
|
+
const { target, args } = planned;
|
|
31719
31798
|
const done4 = this.heldUrl(program);
|
|
31720
31799
|
try {
|
|
31721
31800
|
const cwdSlot = await this.cwds.hold(cwd, req.cwdFrom);
|
|
@@ -31743,6 +31822,52 @@ var Launcher = class {
|
|
|
31743
31822
|
throw err;
|
|
31744
31823
|
}
|
|
31745
31824
|
}
|
|
31825
|
+
async loadPlanned(asked, req, seen) {
|
|
31826
|
+
const env = { ...expandDefaults(asked.target.env, seen), ...req.env };
|
|
31827
|
+
for (const key of asked.target.unset ?? []) delete env[key];
|
|
31828
|
+
delete env[TICKET_ENV];
|
|
31829
|
+
const own = env.HOSTNAME;
|
|
31830
|
+
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
31831
|
+
const planned = chosen2(asked, env);
|
|
31832
|
+
const caller = { pid: req.ppid ?? 0, uid: req.cred.euid, tag: req.tags?.[0] };
|
|
31833
|
+
if (this.integrity) await this.checkedSources(planned, caller);
|
|
31834
|
+
const [program, exeId] = await this.loaded(planned.target, env, caller);
|
|
31835
|
+
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
31836
|
+
return { planned, env, program, exeId };
|
|
31837
|
+
}
|
|
31838
|
+
packageRoots(planned) {
|
|
31839
|
+
const packages2 = [this.modulesDir, ...this.appended];
|
|
31840
|
+
const roots = /* @__PURE__ */ new Set();
|
|
31841
|
+
for (const file of planFiles(planned)) {
|
|
31842
|
+
if (!file.startsWith("/")) continue;
|
|
31843
|
+
const at = normalizePath(file);
|
|
31844
|
+
const root = PACKAGE_ROOT.exec(at)?.[1] ?? packageRootOf(at, packages2);
|
|
31845
|
+
if (root !== void 0 && root !== at) roots.add(root);
|
|
31846
|
+
}
|
|
31847
|
+
return [...roots].sort();
|
|
31848
|
+
}
|
|
31849
|
+
async loadedUnder(asked, load) {
|
|
31850
|
+
const { replan, recheck } = asked;
|
|
31851
|
+
let planned = asked;
|
|
31852
|
+
let roots = this.packageRoots(planned);
|
|
31853
|
+
let stale = false;
|
|
31854
|
+
for (; ; ) {
|
|
31855
|
+
const held = roots;
|
|
31856
|
+
const done4 = await this.packageLocks.loading(held, async (waited) => {
|
|
31857
|
+
if (!waited && !stale) return { value: await load(planned) };
|
|
31858
|
+
this.rootFs.refresh?.(held);
|
|
31859
|
+
this.resetCatalogs();
|
|
31860
|
+
if (replan) planned = await replan() ?? planned;
|
|
31861
|
+
await recheck?.(planned);
|
|
31862
|
+
const now = this.packageRoots(planned);
|
|
31863
|
+
if (now.every((root) => held.includes(root))) return { value: await load(planned) };
|
|
31864
|
+
roots = [.../* @__PURE__ */ new Set([...held, ...now])].sort();
|
|
31865
|
+
stale = true;
|
|
31866
|
+
return void 0;
|
|
31867
|
+
});
|
|
31868
|
+
if (done4) return done4.value;
|
|
31869
|
+
}
|
|
31870
|
+
}
|
|
31746
31871
|
groupSession(pgid) {
|
|
31747
31872
|
return this.jobs.sessionOf(pgid);
|
|
31748
31873
|
}
|
|
@@ -32171,7 +32296,7 @@ var Launcher = class {
|
|
|
32171
32296
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
32172
32297
|
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
32173
32298
|
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
32174
|
-
const redeemed = await this.redeemed(
|
|
32299
|
+
const { recheck, ...redeemed } = await this.redeemed(
|
|
32175
32300
|
{ ...req, file },
|
|
32176
32301
|
{ ppid, cred, scope, booked },
|
|
32177
32302
|
planned,
|
|
@@ -32179,7 +32304,9 @@ var Launcher = class {
|
|
|
32179
32304
|
);
|
|
32180
32305
|
const exec = req.exec ? { exec: true } : {};
|
|
32181
32306
|
const deciding = req.exec ? void 0 : this.undecided(ppid);
|
|
32182
|
-
const
|
|
32307
|
+
const replan = () => this.planOrSearch({ ...req, file }, { ppid, cred, scope });
|
|
32308
|
+
const again = { ...planned, replan, recheck };
|
|
32309
|
+
const handle = await this.launch(again, {
|
|
32183
32310
|
...deciding ? { decided: deciding.promise } : {},
|
|
32184
32311
|
cwd: req.cwd,
|
|
32185
32312
|
cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
|
|
@@ -33073,9 +33200,13 @@ var Launcher = class {
|
|
|
33073
33200
|
const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
|
|
33074
33201
|
if (!await this.base.exists(cwd))
|
|
33075
33202
|
await this.stackFor(tags, base).fs.mkdir(cwd, { recursive: true });
|
|
33076
|
-
const
|
|
33077
|
-
|
|
33078
|
-
|
|
33203
|
+
const plan = async () => {
|
|
33204
|
+
const found = await this.plan(file, argv, cwd, scope);
|
|
33205
|
+
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, found);
|
|
33206
|
+
return found;
|
|
33207
|
+
};
|
|
33208
|
+
const planned = await plan();
|
|
33209
|
+
return { cwd, file, planned: planned && { ...planned, replan: plan } };
|
|
33079
33210
|
}
|
|
33080
33211
|
async openTerminal(argv, options) {
|
|
33081
33212
|
const tagged = tagsOption(options);
|