@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/kernel-worker.js
CHANGED
|
@@ -216,11 +216,69 @@ function inodeOf(path) {
|
|
|
216
216
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// src/fs/owners.ts
|
|
220
|
+
var ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
|
|
221
|
+
var S_ISUID = 2048;
|
|
222
|
+
var S_ISGID = 1024;
|
|
223
|
+
var S_IXGRP = 8;
|
|
224
|
+
function ownOf(entry) {
|
|
225
|
+
if (entry?.uid === void 0 || entry.gid === void 0) return void 0;
|
|
226
|
+
return { uid: entry.uid, gid: entry.gid };
|
|
227
|
+
}
|
|
228
|
+
function handedBy(entry) {
|
|
229
|
+
return entry?.heir ? { uid: entry.heir[0], gid: entry.heir[1] } : ownOf(entry);
|
|
230
|
+
}
|
|
231
|
+
function inherit(entries) {
|
|
232
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
233
|
+
const found = handedBy(entries[i]);
|
|
234
|
+
if (found) return found;
|
|
235
|
+
}
|
|
236
|
+
return { ...ROOT_OWNER };
|
|
237
|
+
}
|
|
238
|
+
function chain(path) {
|
|
239
|
+
const parts = path.split("/").filter(Boolean);
|
|
240
|
+
return ["/", ...parts.map((_, i) => `/${parts.slice(0, i + 1).join("/")}`)];
|
|
241
|
+
}
|
|
242
|
+
function sameOwner(a, b) {
|
|
243
|
+
return a.uid === b.uid && a.gid === b.gid;
|
|
244
|
+
}
|
|
245
|
+
function ownerOf(cred, mode) {
|
|
246
|
+
return { uid: cred.euid, gid: cred.egid, ...mode !== void 0 ? { mode } : {} };
|
|
247
|
+
}
|
|
248
|
+
function inGroup(cred, gid) {
|
|
249
|
+
return cred.egid === gid || cred.groups.includes(gid);
|
|
250
|
+
}
|
|
251
|
+
function mayChown(cred, current, uid, gid) {
|
|
252
|
+
if (cred.euid === 0) return true;
|
|
253
|
+
const owner = cred.euid === current.uid;
|
|
254
|
+
if (uid !== void 0 && !(owner && uid === current.uid)) return false;
|
|
255
|
+
if (gid !== void 0 && !(owner && (gid === current.gid || inGroup(cred, gid)))) return false;
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
function clearedSetId(mode) {
|
|
259
|
+
const bits2 = S_ISUID | (mode & S_IXGRP ? S_ISGID : 0);
|
|
260
|
+
return mode & 4095 & ~bits2;
|
|
261
|
+
}
|
|
262
|
+
async function chownAs(fs, cred, path, change) {
|
|
263
|
+
const { uid, gid, follow: follow2 } = change;
|
|
264
|
+
const st = follow2 ? await fs.stat(path) : await fs.lstat(path);
|
|
265
|
+
const current = { uid: st.uid ?? 0, gid: st.gid ?? 0 };
|
|
266
|
+
if (!fs.chown || !mayChown(cred, current, uid, gid)) throw fsError("EPERM", path);
|
|
267
|
+
const clear = st.isFile && (uid !== void 0 || gid !== void 0) ? clearedSetId(st.mode) : void 0;
|
|
268
|
+
await fs.chown(path, {
|
|
269
|
+
...uid !== void 0 ? { uid } : {},
|
|
270
|
+
...gid !== void 0 ? { gid } : {},
|
|
271
|
+
follow: follow2,
|
|
272
|
+
...clear !== void 0 && clear !== (st.mode & 4095) ? { mode: clear } : {}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
219
276
|
// src/fs/opfs.ts
|
|
220
277
|
var S_IFDIR = 16384;
|
|
221
278
|
var S_IFREG = 32768;
|
|
222
279
|
var S_IFLNK = 40960;
|
|
223
280
|
var PERM_MASK = 4095;
|
|
281
|
+
var S_ISGID2 = 1024;
|
|
224
282
|
var READ_ATTEMPTS = 3;
|
|
225
283
|
var MAX_LINKS = 40;
|
|
226
284
|
var CHECK_MS = 1e3;
|
|
@@ -322,6 +380,7 @@ var OpfsFs = class {
|
|
|
322
380
|
checked = /* @__PURE__ */ new WeakMap();
|
|
323
381
|
channel;
|
|
324
382
|
ranged;
|
|
383
|
+
owners = false;
|
|
325
384
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
326
385
|
this.root = root;
|
|
327
386
|
this.meta = meta;
|
|
@@ -341,6 +400,73 @@ var OpfsFs = class {
|
|
|
341
400
|
resolvePath(base, path) {
|
|
342
401
|
return resolvePath(base, path);
|
|
343
402
|
}
|
|
403
|
+
trackOwners() {
|
|
404
|
+
this.owners = true;
|
|
405
|
+
}
|
|
406
|
+
async handedTo(dir) {
|
|
407
|
+
return inherit(await this.meta.get(chain(dir)));
|
|
408
|
+
}
|
|
409
|
+
async ownerAt(path, entry) {
|
|
410
|
+
const own = ownOf(entry);
|
|
411
|
+
if (own) return own;
|
|
412
|
+
return path === "/" ? { ...ROOT_OWNER } : this.handedTo(parentOf2(path));
|
|
413
|
+
}
|
|
414
|
+
async owned(stat, path, entry) {
|
|
415
|
+
return this.owners ? { ...stat, ...await this.ownerAt(path, entry) } : stat;
|
|
416
|
+
}
|
|
417
|
+
async newFields(path, owner, directory) {
|
|
418
|
+
if (!this.owners || !owner) return void 0;
|
|
419
|
+
const entries = await this.meta.get(chain(path));
|
|
420
|
+
const self = entries.pop();
|
|
421
|
+
const parent = entries.at(-1);
|
|
422
|
+
const setgid = ((parent?.mode ?? 0) & S_ISGID2) !== 0;
|
|
423
|
+
const parentGid = (ownOf(parent) ?? inherit(entries.slice(0, -1))).gid;
|
|
424
|
+
const want = { uid: owner.uid, gid: setgid ? parentGid : owner.gid };
|
|
425
|
+
let mode = owner.mode === void 0 ? void 0 : owner.mode & PERM_MASK;
|
|
426
|
+
if (directory && setgid) mode = (mode ?? 493) | S_ISGID2;
|
|
427
|
+
const fields = {};
|
|
428
|
+
if (mode !== void 0 && mode !== (this.mode(path, directory, void 0) & PERM_MASK)) {
|
|
429
|
+
fields.mode = mode;
|
|
430
|
+
}
|
|
431
|
+
if (self) fields.heir = void 0;
|
|
432
|
+
if (ownOf(self) || !sameOwner(want, inherit(entries))) Object.assign(fields, want);
|
|
433
|
+
return Object.keys(fields).length > 0 ? fields : void 0;
|
|
434
|
+
}
|
|
435
|
+
async stampNew(path, owner, directory) {
|
|
436
|
+
const fields = await this.newFields(path, owner, directory);
|
|
437
|
+
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
438
|
+
}
|
|
439
|
+
async chown(path, change) {
|
|
440
|
+
if (!this.owners) return;
|
|
441
|
+
if (change.kind === "new") {
|
|
442
|
+
const at = resolvePath((await this.locate(parentOf2(path), true)).path, baseOf(path));
|
|
443
|
+
const { uid = 0, gid = 0, mode } = change;
|
|
444
|
+
return this.stampNew(at, { uid, gid, ...mode !== void 0 ? { mode } : {} }, false);
|
|
445
|
+
}
|
|
446
|
+
const found = await this.locate(path, change.follow !== false);
|
|
447
|
+
const [stored] = found.link ? [found.link] : await this.meta.get([found.path]);
|
|
448
|
+
const current = await this.ownerAt(found.path, stored);
|
|
449
|
+
const next2 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
|
|
450
|
+
const handing = found.handle?.kind === "directory" && !sameOwner(next2, current);
|
|
451
|
+
const heir = change.kind === "adopt" ? void 0 : stored?.heir ?? (handing ? [current.uid, current.gid] : void 0);
|
|
452
|
+
const ctimeMs = Date.now();
|
|
453
|
+
await this.meta.update(found.path, (entry) => {
|
|
454
|
+
const { heir: _, ...rest2 } = entry ?? found.link ?? { path: found.path };
|
|
455
|
+
return {
|
|
456
|
+
...rest2,
|
|
457
|
+
path: found.path,
|
|
458
|
+
...next2,
|
|
459
|
+
...heir ? { heir } : {},
|
|
460
|
+
...change.mode !== void 0 ? { mode: change.mode & PERM_MASK } : {},
|
|
461
|
+
ctimeMs
|
|
462
|
+
};
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
async movedOwner(source) {
|
|
466
|
+
if (!this.owners) return void 0;
|
|
467
|
+
const [stored] = source.link ? [source.link] : await this.meta.get([source.path]);
|
|
468
|
+
return ownOf(stored) ? void 0 : this.ownerAt(source.path, stored);
|
|
469
|
+
}
|
|
344
470
|
async walk(parts, from, start2) {
|
|
345
471
|
let dir = start2;
|
|
346
472
|
for (let at = from; at < parts.length; at++) {
|
|
@@ -438,12 +564,34 @@ var OpfsFs = class {
|
|
|
438
564
|
const link2 = await this.linkAlong(current);
|
|
439
565
|
if (!link2) throw err;
|
|
440
566
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
441
|
-
const
|
|
442
|
-
current =
|
|
567
|
+
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
568
|
+
current = target.split("/").includes("..") ? await this.physical(parentOf2(link2.path), target, hops + 1) : resolvePath(parentOf2(link2.path), target);
|
|
443
569
|
}
|
|
444
570
|
}
|
|
445
571
|
throw fsError("ELOOP", path);
|
|
446
572
|
}
|
|
573
|
+
async physical(base, path, used) {
|
|
574
|
+
let done4 = [];
|
|
575
|
+
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
576
|
+
for (let hops = used; todo.length > 0; ) {
|
|
577
|
+
const part = todo.shift();
|
|
578
|
+
if (part === "..") done4.pop();
|
|
579
|
+
else if (!todo.includes("..")) done4.push(part);
|
|
580
|
+
else {
|
|
581
|
+
const at = `/${[...done4, part].join("/")}`;
|
|
582
|
+
const st = await this.lstat(at);
|
|
583
|
+
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
584
|
+
if (!st.isSymbolicLink) done4.push(part);
|
|
585
|
+
else if (++hops > MAX_LINKS) throw fsError("ELOOP", path);
|
|
586
|
+
else {
|
|
587
|
+
const link2 = await this.readlink(at);
|
|
588
|
+
if (link2.startsWith("/")) done4 = [];
|
|
589
|
+
todo = [...link2.split("/").filter((p) => p !== "" && p !== "."), ...todo];
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return `/${done4.join("/")}`;
|
|
594
|
+
}
|
|
447
595
|
mode(path, directory, meta) {
|
|
448
596
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
449
597
|
return (directory ? S_IFDIR : S_IFREG) | (meta?.mode ?? fallback);
|
|
@@ -511,9 +659,15 @@ var OpfsFs = class {
|
|
|
511
659
|
};
|
|
512
660
|
}
|
|
513
661
|
async describe(found) {
|
|
514
|
-
if (found.link) return this.linkStat(found.link);
|
|
515
|
-
|
|
516
|
-
|
|
662
|
+
if (found.link) return this.owned(this.linkStat(found.link), found.path, found.link);
|
|
663
|
+
if (!this.owners) {
|
|
664
|
+
const [meta2] = await this.meta.get([found.path]);
|
|
665
|
+
return this.statOf(found.path, found.handle, meta2);
|
|
666
|
+
}
|
|
667
|
+
const entries = await this.meta.get(chain(found.path));
|
|
668
|
+
const meta = entries.pop();
|
|
669
|
+
const stat = await this.statOf(found.path, found.handle, meta);
|
|
670
|
+
return { ...stat, ...ownOf(meta) ?? inherit(entries) };
|
|
517
671
|
}
|
|
518
672
|
async stat(path) {
|
|
519
673
|
return this.describe(await this.locate(path, true));
|
|
@@ -603,14 +757,15 @@ var OpfsFs = class {
|
|
|
603
757
|
(parent) => parent.getFileHandle(name2, { create: true })
|
|
604
758
|
);
|
|
605
759
|
if (!existed) this.touch(parentOf2(target));
|
|
606
|
-
return [handle, existed];
|
|
760
|
+
return [handle, existed, target];
|
|
607
761
|
} catch (err) {
|
|
608
762
|
const code = err?.name === "TypeMismatchError" ? "EISDIR" : null;
|
|
609
763
|
throw code ? fsError(code, path) : translate(err, path);
|
|
610
764
|
}
|
|
611
765
|
}
|
|
612
|
-
async writeFile(path, content) {
|
|
613
|
-
const [file, existed] = await this.fileFor(path);
|
|
766
|
+
async writeFile(path, content, owner) {
|
|
767
|
+
const [file, existed, target] = await this.fileFor(path);
|
|
768
|
+
if (!existed) await this.stampNew(target, owner, false);
|
|
614
769
|
if (!existed && content.length === 0) return;
|
|
615
770
|
const writable = await file.createWritable();
|
|
616
771
|
await writable.write(content);
|
|
@@ -635,11 +790,13 @@ var OpfsFs = class {
|
|
|
635
790
|
const [dir, children2] = await this.listing(path);
|
|
636
791
|
const base = dir === "/" ? "" : dir;
|
|
637
792
|
const metas = await this.meta.get(children2.map(([name2]) => `${base}/${name2}`));
|
|
793
|
+
const handed2 = this.owners ? await this.handedTo(dir) : void 0;
|
|
794
|
+
const owned = (stat, entry) => handed2 ? { ...stat, ...ownOf(entry) ?? handed2 } : stat;
|
|
638
795
|
return Promise.all(
|
|
639
796
|
children2.map(async ([name2, child], i) => {
|
|
640
|
-
if (!isHandle(child)) return [name2, this.linkStat(child)];
|
|
797
|
+
if (!isHandle(child)) return [name2, owned(this.linkStat(child), child)];
|
|
641
798
|
const stat = await this.statOf(`${base}/${name2}`, child, metas[i]).catch(() => null);
|
|
642
|
-
return [name2, stat];
|
|
799
|
+
return [name2, stat && owned(stat, metas[i])];
|
|
643
800
|
})
|
|
644
801
|
);
|
|
645
802
|
}
|
|
@@ -657,11 +814,22 @@ var OpfsFs = class {
|
|
|
657
814
|
}
|
|
658
815
|
const [entry] = await this.meta.get([path]);
|
|
659
816
|
if (entry?.link !== void 0) throw fsError("EEXIST", path);
|
|
660
|
-
|
|
817
|
+
const { owner } = options;
|
|
818
|
+
if (options.recursive) {
|
|
819
|
+
const mode = owner?.parents;
|
|
820
|
+
const above = owner && {
|
|
821
|
+
uid: owner.uid,
|
|
822
|
+
gid: owner.gid,
|
|
823
|
+
...mode ? { mode, parents: mode } : {}
|
|
824
|
+
};
|
|
825
|
+
await this.mkdir(parentOf2(path), { recursive: true, ...above ? { owner: above } : {} });
|
|
826
|
+
}
|
|
661
827
|
const parent = await this.locate(parentOf2(path), true);
|
|
662
828
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
663
829
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
664
|
-
|
|
830
|
+
const made = `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`;
|
|
831
|
+
await this.stampNew(made, owner, true);
|
|
832
|
+
this.touch(parent.path, made);
|
|
665
833
|
}
|
|
666
834
|
async rm(path, options = {}) {
|
|
667
835
|
let found;
|
|
@@ -708,9 +876,11 @@ var OpfsFs = class {
|
|
|
708
876
|
throw fsError("ENOTEMPTY", to);
|
|
709
877
|
}
|
|
710
878
|
const now = Date.now();
|
|
879
|
+
const moving = await this.movedOwner(source);
|
|
711
880
|
const carry = (entry) => ({
|
|
712
881
|
ino: inodeOf(source.path),
|
|
713
882
|
...entry,
|
|
883
|
+
...moving,
|
|
714
884
|
path: destination,
|
|
715
885
|
ctimeMs: now
|
|
716
886
|
});
|
|
@@ -784,7 +954,7 @@ var OpfsFs = class {
|
|
|
784
954
|
const target = await dir.getDirectoryHandle(name2, { create: true });
|
|
785
955
|
for await (const child of handle.values()) await this.copy(child, target, child.name);
|
|
786
956
|
}
|
|
787
|
-
async symlink(target, path) {
|
|
957
|
+
async symlink(target, path, owner) {
|
|
788
958
|
const parent = await this.locate(parentOf2(path), true);
|
|
789
959
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
790
960
|
const at = resolvePath(parent.path, baseOf(path));
|
|
@@ -795,13 +965,15 @@ var OpfsFs = class {
|
|
|
795
965
|
throw fsError("EEXIST", path);
|
|
796
966
|
}
|
|
797
967
|
const now = Date.now();
|
|
968
|
+
const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
|
|
798
969
|
await this.meta.update(at, () => ({
|
|
799
970
|
path: at,
|
|
800
971
|
link: target,
|
|
801
972
|
dir: parent.path,
|
|
802
973
|
ino: inodeOf(at),
|
|
803
974
|
mtimeMs: now,
|
|
804
|
-
ctimeMs: now
|
|
975
|
+
ctimeMs: now,
|
|
976
|
+
...fields
|
|
805
977
|
}));
|
|
806
978
|
this.touch(parent.path);
|
|
807
979
|
}
|
|
@@ -2445,12 +2617,30 @@ function userEnv(account, system) {
|
|
|
2445
2617
|
PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
|
|
2446
2618
|
};
|
|
2447
2619
|
}
|
|
2620
|
+
function homeGroupOf(groups, name2) {
|
|
2621
|
+
if (name2 === void 0) return void 0;
|
|
2622
|
+
const found = groups.find((g) => g.name === name2);
|
|
2623
|
+
if (!found) throw fsError("ENOENT", `no group ${name2}`);
|
|
2624
|
+
return found;
|
|
2625
|
+
}
|
|
2448
2626
|
var UserDb = class {
|
|
2449
2627
|
fs;
|
|
2628
|
+
owners;
|
|
2450
2629
|
umasks = /* @__PURE__ */ new Map();
|
|
2451
2630
|
writing = Promise.resolve();
|
|
2452
|
-
constructor(fs) {
|
|
2631
|
+
constructor(fs, owners = false) {
|
|
2453
2632
|
this.fs = fs;
|
|
2633
|
+
this.owners = owners;
|
|
2634
|
+
}
|
|
2635
|
+
async stampHome(row, shared) {
|
|
2636
|
+
const home = this.fs.resolvePath("/", row.home);
|
|
2637
|
+
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
2638
|
+
if (await this.fs.realpath?.(home, false).catch(() => void 0) !== home) return;
|
|
2639
|
+
if (!(await this.fs.lstat(home)).isDirectory) return;
|
|
2640
|
+
const gid = shared?.gid ?? row.gid;
|
|
2641
|
+
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
2642
|
+
const mode = shared ? 1512 : row.name.startsWith("scoop-") ? 488 : 448;
|
|
2643
|
+
await this.fs.chmod(home, mode);
|
|
2454
2644
|
}
|
|
2455
2645
|
async read(path, fallback) {
|
|
2456
2646
|
try {
|
|
@@ -2550,8 +2740,12 @@ var UserDb = class {
|
|
|
2550
2740
|
const users = parsed(passwd);
|
|
2551
2741
|
const groups = parsed(group);
|
|
2552
2742
|
const found = users.find((r) => r.name === name2);
|
|
2743
|
+
const shared = homeGroupOf(groups, options.homeGroup);
|
|
2553
2744
|
if (found) {
|
|
2554
|
-
if (found.uid >= FIRST_UID && found.uid <= LAST_UID)
|
|
2745
|
+
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
2746
|
+
await this.provision(found);
|
|
2747
|
+
await this.stampHome(found, shared);
|
|
2748
|
+
}
|
|
2555
2749
|
remember();
|
|
2556
2750
|
return this.account(found, groups);
|
|
2557
2751
|
}
|
|
@@ -2571,6 +2765,7 @@ var UserDb = class {
|
|
|
2571
2765
|
await this.fs.mkdir(home, { recursive: true });
|
|
2572
2766
|
try {
|
|
2573
2767
|
await this.provision(row);
|
|
2768
|
+
await this.stampHome(row, shared);
|
|
2574
2769
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
2575
2770
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
2576
2771
|
} catch (err) {
|
|
@@ -2639,7 +2834,7 @@ async function realpath(fs, path) {
|
|
|
2639
2834
|
}
|
|
2640
2835
|
return resolved || "/";
|
|
2641
2836
|
}
|
|
2642
|
-
async function fsCall(fs, method, args) {
|
|
2837
|
+
async function fsCall(fs, method, args, owner) {
|
|
2643
2838
|
const path = (i) => fs.resolvePath("/", String(args[i]));
|
|
2644
2839
|
switch (method) {
|
|
2645
2840
|
case "readFile": {
|
|
@@ -2647,7 +2842,7 @@ async function fsCall(fs, method, args) {
|
|
|
2647
2842
|
return { result: bytes, transfer: [bytes.buffer] };
|
|
2648
2843
|
}
|
|
2649
2844
|
case "writeFile":
|
|
2650
|
-
await fs.writeFile(path(0), args[1]);
|
|
2845
|
+
await fs.writeFile(path(0), args[1], owner);
|
|
2651
2846
|
return { result: true };
|
|
2652
2847
|
case "stat":
|
|
2653
2848
|
return { result: await fs.stat(path(0)) };
|
|
@@ -2656,7 +2851,7 @@ async function fsCall(fs, method, args) {
|
|
|
2656
2851
|
case "readdir":
|
|
2657
2852
|
return { result: await fs.readdir(path(0)) };
|
|
2658
2853
|
case "mkdir":
|
|
2659
|
-
await fs.mkdir(path(0), { recursive: true });
|
|
2854
|
+
await fs.mkdir(path(0), owner ? { recursive: true, owner } : { recursive: true });
|
|
2660
2855
|
return { result: true };
|
|
2661
2856
|
case "rm":
|
|
2662
2857
|
await fs.rm(path(0), { recursive: true, force: args[1] === true });
|
|
@@ -2667,7 +2862,7 @@ async function fsCall(fs, method, args) {
|
|
|
2667
2862
|
case "realpath":
|
|
2668
2863
|
return { result: await realpath(fs, String(args[0])) };
|
|
2669
2864
|
case "symlink":
|
|
2670
|
-
await fs.symlink(String(args[0]), path(1));
|
|
2865
|
+
await fs.symlink(String(args[0]), path(1), owner);
|
|
2671
2866
|
return { result: true };
|
|
2672
2867
|
case "readlink":
|
|
2673
2868
|
return { result: await fs.readlink(path(0)) };
|
|
@@ -2689,6 +2884,9 @@ function dialFor(l, req, open) {
|
|
|
2689
2884
|
);
|
|
2690
2885
|
return { result: port2, transfer: [port2] };
|
|
2691
2886
|
}
|
|
2887
|
+
function ownerFor(l, self) {
|
|
2888
|
+
return l.owners && self ? { uid: self.uid, gid: self.gid } : void 0;
|
|
2889
|
+
}
|
|
2692
2890
|
async function accountOf(l, user) {
|
|
2693
2891
|
const found = await l.users.lookup(user);
|
|
2694
2892
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
@@ -2816,6 +3014,7 @@ function serveClient(port, host) {
|
|
|
2816
3014
|
hello: {
|
|
2817
3015
|
protocol: PROTOCOL,
|
|
2818
3016
|
traits: transport.traits,
|
|
3017
|
+
...launcher.usersMode ? { users: launcher.usersMode } : {},
|
|
2819
3018
|
...host.lock ? { lock: host.lock } : {}
|
|
2820
3019
|
}
|
|
2821
3020
|
});
|
|
@@ -2881,7 +3080,7 @@ function serveClient(port, host) {
|
|
|
2881
3080
|
if (!FS_METHODS.includes(req.method)) {
|
|
2882
3081
|
throw new Error(`unknown file system call ${req.method}`);
|
|
2883
3082
|
}
|
|
2884
|
-
return fsCall(l.fs, req.method, req.args);
|
|
3083
|
+
return fsCall(l.fs, req.method, req.args, ownerFor(l, self));
|
|
2885
3084
|
case "watch":
|
|
2886
3085
|
case "unwatch":
|
|
2887
3086
|
return watchOp(l, req, watches, send);
|
|
@@ -3904,10 +4103,10 @@ var RealmProxy = class {
|
|
|
3904
4103
|
}
|
|
3905
4104
|
async bridge(ctx, socket, hangup) {
|
|
3906
4105
|
const stop = this.stop.signal;
|
|
3907
|
-
let
|
|
4106
|
+
let chain2 = Promise.resolve();
|
|
3908
4107
|
const toGuest = (bytes) => {
|
|
3909
|
-
|
|
3910
|
-
return
|
|
4108
|
+
chain2 = chain2.then(() => ctx.sink.write(bytes, stop));
|
|
4109
|
+
return chain2;
|
|
3911
4110
|
};
|
|
3912
4111
|
const done4 = new AbortController();
|
|
3913
4112
|
const reading = AbortSignal.any([stop, done4.signal, hangup]);
|
|
@@ -5614,7 +5813,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
|
5614
5813
|
throw err;
|
|
5615
5814
|
}
|
|
5616
5815
|
},
|
|
5617
|
-
writeFile: (path, content) => fs.writeFile(path, content),
|
|
5816
|
+
writeFile: (path, content, owner) => fs.writeFile(path, content, owner),
|
|
5618
5817
|
async exists(path) {
|
|
5619
5818
|
return await fs.exists(path) || await linked(path) !== void 0;
|
|
5620
5819
|
},
|
|
@@ -5652,9 +5851,10 @@ function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
|
5652
5851
|
mkdir: (path, options) => fs.mkdir(path, options),
|
|
5653
5852
|
rm: (path, options) => fs.rm(path, options),
|
|
5654
5853
|
rename: (from, to) => fs.rename(from, to),
|
|
5655
|
-
symlink: (target, path) => fs.symlink(target, path),
|
|
5854
|
+
symlink: (target, path, owner) => fs.symlink(target, path, owner),
|
|
5656
5855
|
readlink: (path) => fs.readlink(path),
|
|
5657
5856
|
...fs.realpath ? { realpath: fs.realpath.bind(fs) } : {},
|
|
5857
|
+
...fs.chown ? { chown: fs.chown.bind(fs) } : {},
|
|
5658
5858
|
chmod: (path, mode) => fs.chmod(path, mode),
|
|
5659
5859
|
utimes: (path, atime, mtime) => fs.utimes(path, atime, mtime),
|
|
5660
5860
|
lutimes: (path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -5971,6 +6171,7 @@ var FsWatchers = class {
|
|
|
5971
6171
|
rename: after(fs.rename.bind(fs), (from, to) => [from, to]),
|
|
5972
6172
|
symlink: after(fs.symlink.bind(fs), (_target, path) => [path]),
|
|
5973
6173
|
chmod: after(fs.chmod.bind(fs), (path) => [path]),
|
|
6174
|
+
...fs.chown ? { chown: after(fs.chown.bind(fs), (path) => [path]) } : {},
|
|
5974
6175
|
utimes: after(fs.utimes.bind(fs), (path) => [path]),
|
|
5975
6176
|
lutimes: after(
|
|
5976
6177
|
(path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -6042,13 +6243,13 @@ var ChildTable = class {
|
|
|
6042
6243
|
if (!this.forker) throw new SpawnError("ENOSYS");
|
|
6043
6244
|
return this.track(state, this.parentFds.fork(), /* @__PURE__ */ new Map(), this.forker);
|
|
6044
6245
|
}
|
|
6045
|
-
async spawn(req, stdio,
|
|
6246
|
+
async spawn(req, stdio, inherit2 = []) {
|
|
6046
6247
|
if (!this.spawner) throw new SpawnError("ENOSYS");
|
|
6047
6248
|
const fds = new FdTable();
|
|
6048
6249
|
const captured = /* @__PURE__ */ new Map();
|
|
6049
6250
|
try {
|
|
6050
6251
|
for (const [n, slot] of stdio.entries()) fds.installAt(n, this.openSlot(slot, n, captured));
|
|
6051
|
-
for (const slot of
|
|
6252
|
+
for (const slot of inherit2) {
|
|
6052
6253
|
if (slot.fd <= 2) continue;
|
|
6053
6254
|
if ("device" in slot) {
|
|
6054
6255
|
fds.installAt(slot.fd, deviceFile(slot.device, slot.access));
|
|
@@ -6129,8 +6330,8 @@ var ChildTable = class {
|
|
|
6129
6330
|
candidates(pid, flags) {
|
|
6130
6331
|
const all = [...this.children];
|
|
6131
6332
|
if (pid > 0) return all.filter(([p]) => p === pid);
|
|
6132
|
-
const
|
|
6133
|
-
return pid === -1 || !
|
|
6333
|
+
const inGroup2 = flags.inGroup;
|
|
6334
|
+
return pid === -1 || !inGroup2 ? all : all.filter(([p]) => inGroup2(p));
|
|
6134
6335
|
}
|
|
6135
6336
|
async nextChange(candidates, flags, interrupt) {
|
|
6136
6337
|
let wake;
|
|
@@ -6851,10 +7052,10 @@ var MountFs = class {
|
|
|
6851
7052
|
}
|
|
6852
7053
|
return concat4(chunks, total);
|
|
6853
7054
|
}
|
|
6854
|
-
async writeFile(path, content) {
|
|
7055
|
+
async writeFile(path, content, owner) {
|
|
6855
7056
|
const real = await this.follow(path, 0, true);
|
|
6856
7057
|
const found = this.at(real);
|
|
6857
|
-
if (!found) return this.base.writeFile(real, content);
|
|
7058
|
+
if (!found) return this.base.writeFile(real, content, owner);
|
|
6858
7059
|
const { mount, rel: rel2 } = found;
|
|
6859
7060
|
this.writable(mount, real);
|
|
6860
7061
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -7121,9 +7322,9 @@ var MountFs = class {
|
|
|
7121
7322
|
this.table.forget(a.mount, normalizePath(to));
|
|
7122
7323
|
}
|
|
7123
7324
|
}
|
|
7124
|
-
async symlink(target, path) {
|
|
7325
|
+
async symlink(target, path, owner) {
|
|
7125
7326
|
const found = this.at(path);
|
|
7126
|
-
if (!found) return this.base.symlink(target, path);
|
|
7327
|
+
if (!found) return this.base.symlink(target, path, owner);
|
|
7127
7328
|
this.writable(found.mount, normalizePath(path));
|
|
7128
7329
|
if (!found.mount.caps.symlinks)
|
|
7129
7330
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -7141,6 +7342,15 @@ var MountFs = class {
|
|
|
7141
7342
|
if (!found) return this.base.readlink(path);
|
|
7142
7343
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
7143
7344
|
}
|
|
7345
|
+
async chown(path, change) {
|
|
7346
|
+
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
7347
|
+
if (this.at(real)) {
|
|
7348
|
+
if (change.kind === "new") return;
|
|
7349
|
+
throw errnoError("EPERM", `${path}: this file system keeps no owners`);
|
|
7350
|
+
}
|
|
7351
|
+
if (!this.base.chown) throw errnoError("EPERM", path);
|
|
7352
|
+
return this.base.chown(real, change);
|
|
7353
|
+
}
|
|
7144
7354
|
async chmod(path, mode) {
|
|
7145
7355
|
const found = this.at(path);
|
|
7146
7356
|
if (!found) return this.base.chmod(path, mode);
|
|
@@ -7215,7 +7425,9 @@ function statJson(s) {
|
|
|
7215
7425
|
...s.readonly ? { readonly: true } : {},
|
|
7216
7426
|
...s.maxFile ? { maxFile: s.maxFile } : {},
|
|
7217
7427
|
...s.ranged ? { ranged: true } : {},
|
|
7218
|
-
...s.version !== void 0 ? { version: s.version } : {}
|
|
7428
|
+
...s.version !== void 0 ? { version: s.version } : {},
|
|
7429
|
+
...s.uid !== void 0 ? { uid: s.uid } : {},
|
|
7430
|
+
...s.gid !== void 0 ? { gid: s.gid } : {}
|
|
7219
7431
|
};
|
|
7220
7432
|
}
|
|
7221
7433
|
async function readdirStat(fs, dir) {
|
|
@@ -7230,13 +7442,34 @@ var done = { ok: true, kind: "void" };
|
|
|
7230
7442
|
function json2(value) {
|
|
7231
7443
|
return { ok: true, kind: "json", json: value };
|
|
7232
7444
|
}
|
|
7445
|
+
function ownerFor2(entry, mode) {
|
|
7446
|
+
const cred = entry.cred?.();
|
|
7447
|
+
if (!cred) return void 0;
|
|
7448
|
+
return ownerOf(cred, mode === void 0 ? void 0 : mode & ~(entry.umask?.() ?? 18));
|
|
7449
|
+
}
|
|
7450
|
+
function mkdirOptions(entry, mode = 511) {
|
|
7451
|
+
const owner = ownerFor2(entry, mode);
|
|
7452
|
+
if (!owner) return { recursive: true };
|
|
7453
|
+
const parents = 511 & ~(entry.umask?.() ?? 18) | 192;
|
|
7454
|
+
return { recursive: true, owner: { ...owner, parents } };
|
|
7455
|
+
}
|
|
7456
|
+
async function chown(entry, path, req) {
|
|
7457
|
+
const cred = entry.cred?.();
|
|
7458
|
+
if (!cred) return done;
|
|
7459
|
+
await chownAs(entry.fs, cred, path, {
|
|
7460
|
+
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
7461
|
+
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
7462
|
+
follow: req.op === "chown"
|
|
7463
|
+
});
|
|
7464
|
+
return done;
|
|
7465
|
+
}
|
|
7233
7466
|
async function run(entry, path, req) {
|
|
7234
7467
|
const { fs, cwd } = entry;
|
|
7235
7468
|
switch (req.op) {
|
|
7236
7469
|
case "read":
|
|
7237
7470
|
return { ok: true, kind: "bytes", bytes: await fs.readFileBuffer(path) };
|
|
7238
7471
|
case "write":
|
|
7239
|
-
await fs.writeFile(path, req.body ?? new Uint8Array(0));
|
|
7472
|
+
await fs.writeFile(path, req.body ?? new Uint8Array(0), ownerFor2(entry, 438));
|
|
7240
7473
|
return done;
|
|
7241
7474
|
case "exists":
|
|
7242
7475
|
return json2(await fs.exists(path));
|
|
@@ -7249,7 +7482,7 @@ async function run(entry, path, req) {
|
|
|
7249
7482
|
case "readdir-stat":
|
|
7250
7483
|
return json2(await readdirStat(fs, path));
|
|
7251
7484
|
case "mkdir":
|
|
7252
|
-
await fs.mkdir(path,
|
|
7485
|
+
await fs.mkdir(path, mkdirOptions(entry, req.mode));
|
|
7253
7486
|
return done;
|
|
7254
7487
|
case "rm":
|
|
7255
7488
|
await fs.rm(path, { recursive: true });
|
|
@@ -7270,10 +7503,10 @@ async function run(entry, path, req) {
|
|
|
7270
7503
|
await fs.rm(path, { recursive: true });
|
|
7271
7504
|
return done;
|
|
7272
7505
|
case "symlink":
|
|
7273
|
-
await fs.symlink(req.arg2 ?? "", path);
|
|
7506
|
+
await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
|
|
7274
7507
|
return done;
|
|
7275
7508
|
case "create":
|
|
7276
|
-
await createExclusive(fs, path);
|
|
7509
|
+
await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
|
|
7277
7510
|
return done;
|
|
7278
7511
|
case "readlink":
|
|
7279
7512
|
return json2(await fs.readlink(path));
|
|
@@ -7286,6 +7519,9 @@ async function run(entry, path, req) {
|
|
|
7286
7519
|
case "lutimes":
|
|
7287
7520
|
await lutimesOf(fs, path, new Date(req.atimeMs ?? 0), new Date(req.mtimeMs ?? 0));
|
|
7288
7521
|
return done;
|
|
7522
|
+
case "chown":
|
|
7523
|
+
case "lchown":
|
|
7524
|
+
return chown(entry, path, req);
|
|
7289
7525
|
case "pread":
|
|
7290
7526
|
case "pwrite":
|
|
7291
7527
|
case "truncate":
|
|
@@ -7294,14 +7530,14 @@ async function run(entry, path, req) {
|
|
|
7294
7530
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
7295
7531
|
}
|
|
7296
7532
|
}
|
|
7297
|
-
async function createExclusive(fs, path) {
|
|
7298
|
-
if (fs.createExclusive) return fs.createExclusive(path);
|
|
7533
|
+
async function createExclusive(fs, path, owner) {
|
|
7534
|
+
if (fs.createExclusive) return fs.createExclusive(path, owner);
|
|
7299
7535
|
if (await fs.lstat(path).then(
|
|
7300
7536
|
() => true,
|
|
7301
7537
|
() => false
|
|
7302
7538
|
))
|
|
7303
7539
|
throw syncError("EEXIST", path);
|
|
7304
|
-
await fs.writeFile(path, new Uint8Array(0));
|
|
7540
|
+
await fs.writeFile(path, new Uint8Array(0), owner);
|
|
7305
7541
|
}
|
|
7306
7542
|
async function ranged(fs, path, req) {
|
|
7307
7543
|
const ops = rangedOps(fs);
|
|
@@ -9496,12 +9732,12 @@ var VfsNodes = class {
|
|
|
9496
9732
|
}
|
|
9497
9733
|
return walk();
|
|
9498
9734
|
}
|
|
9499
|
-
createExclusive(path) {
|
|
9735
|
+
createExclusive(path, owner) {
|
|
9500
9736
|
return this.onEntry(path, async () => {
|
|
9501
9737
|
const node = this.byPath.get(path);
|
|
9502
9738
|
const held = node ? await node.serial(async () => node.holds()) : false;
|
|
9503
9739
|
if (held || await present(this.fs, path)) throw fsError("EEXIST", path);
|
|
9504
|
-
await this.fs.writeFile(path, new Uint8Array(0));
|
|
9740
|
+
await this.fs.writeFile(path, new Uint8Array(0), owner);
|
|
9505
9741
|
});
|
|
9506
9742
|
}
|
|
9507
9743
|
open(path, pin, writable = false) {
|
|
@@ -9631,6 +9867,11 @@ var MAX_LINKS5 = 40;
|
|
|
9631
9867
|
function parentOf6(path) {
|
|
9632
9868
|
return path.slice(0, path.lastIndexOf("/")) || "/";
|
|
9633
9869
|
}
|
|
9870
|
+
async function mustBeDir(fs, path) {
|
|
9871
|
+
if (!fs.lstat) return;
|
|
9872
|
+
const st = await fs.lstat(path);
|
|
9873
|
+
if (st.isDirectory !== true) throw fsError("ENOTDIR", path);
|
|
9874
|
+
}
|
|
9634
9875
|
async function linkOf(fs, path) {
|
|
9635
9876
|
return fs.readlink?.(path).catch(() => void 0);
|
|
9636
9877
|
}
|
|
@@ -9647,6 +9888,7 @@ async function realDir(fs, dir, budget = { hops: 0 }) {
|
|
|
9647
9888
|
const next2 = at === "/" ? `/${part}` : `${at}/${part}`;
|
|
9648
9889
|
const link2 = await linkOf(fs, next2);
|
|
9649
9890
|
if (link2 === void 0) {
|
|
9891
|
+
if (queue.find((p) => p !== ".") === "..") await mustBeDir(fs, next2);
|
|
9650
9892
|
at = next2;
|
|
9651
9893
|
continue;
|
|
9652
9894
|
}
|
|
@@ -9712,9 +9954,9 @@ function keepingOpen(fs, nodes) {
|
|
|
9712
9954
|
nodes.renamed(a, b);
|
|
9713
9955
|
});
|
|
9714
9956
|
},
|
|
9715
|
-
writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
|
|
9716
|
-
createExclusive: async (path) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path))),
|
|
9717
|
-
symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
|
|
9957
|
+
writeFile: (path, content, owner) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content, owner)),
|
|
9958
|
+
createExclusive: async (path, owner) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path)), owner),
|
|
9959
|
+
symlink: (target, path, owner) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path, owner)),
|
|
9718
9960
|
mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
|
|
9719
9961
|
};
|
|
9720
9962
|
}
|
|
@@ -9985,9 +10227,9 @@ var WasmProcess = class {
|
|
|
9985
10227
|
return "deliver";
|
|
9986
10228
|
}
|
|
9987
10229
|
async spawn(req) {
|
|
9988
|
-
const { file, argv, env, cwd, stdio, inherit, exec } = req;
|
|
10230
|
+
const { file, argv, env, cwd, stdio, inherit: inherit2, exec } = req;
|
|
9989
10231
|
const spawned = { file, argv, env, cwd, ...exec ? { exec } : {} };
|
|
9990
|
-
const pid = await this.children.spawn(spawned, stdio,
|
|
10232
|
+
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
9991
10233
|
if (!exec) return pid;
|
|
9992
10234
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
9993
10235
|
else this.adoptExec(pid);
|
|
@@ -10152,12 +10394,14 @@ var WasmProcess = class {
|
|
|
10152
10394
|
}
|
|
10153
10395
|
const open = { ...req, path };
|
|
10154
10396
|
if (req.exclusive) {
|
|
10155
|
-
await nodes.createExclusive(path);
|
|
10397
|
+
await nodes.createExclusive(path, this.newOwner());
|
|
10156
10398
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
10157
10399
|
} else if (req.create) {
|
|
10158
10400
|
await nodes.onEntry(path, async () => {
|
|
10401
|
+
const fresh = this.options.owners && !await present(this.options.fs, path, true);
|
|
10159
10402
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
10160
10403
|
await this.fds.get(fd).file.stat?.();
|
|
10404
|
+
if (fresh) await this.options.fs.chown?.(path, { ...this.newOwner(), kind: "new" });
|
|
10161
10405
|
});
|
|
10162
10406
|
} else {
|
|
10163
10407
|
this.fds.installAt(fd, this.openVfsFile(open));
|
|
@@ -10171,6 +10415,10 @@ var WasmProcess = class {
|
|
|
10171
10415
|
}
|
|
10172
10416
|
return fd;
|
|
10173
10417
|
}
|
|
10418
|
+
newOwner() {
|
|
10419
|
+
if (!this.options.owners) return void 0;
|
|
10420
|
+
return { uid: this.cred.euid, gid: this.cred.egid, mode: 438 & ~this.umask };
|
|
10421
|
+
}
|
|
10174
10422
|
async openProc(req, path) {
|
|
10175
10423
|
return this.fds.install(await this.procFile(req, path), 3);
|
|
10176
10424
|
}
|
|
@@ -10817,6 +11065,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
10817
11065
|
sab,
|
|
10818
11066
|
umask,
|
|
10819
11067
|
cred,
|
|
11068
|
+
...opts.owners ? { owners: true } : {},
|
|
10820
11069
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
10821
11070
|
};
|
|
10822
11071
|
if (opts.program.abi === "js") {
|
|
@@ -10840,8 +11089,9 @@ function inherited(opts) {
|
|
|
10840
11089
|
...opts.cred ? { cred: opts.cred } : {}
|
|
10841
11090
|
};
|
|
10842
11091
|
}
|
|
10843
|
-
function holdingToken(opts, holds) {
|
|
11092
|
+
function holdingToken(opts, holds, caller) {
|
|
10844
11093
|
return mintSyncFsToken({
|
|
11094
|
+
...opts.owners ? caller : {},
|
|
10845
11095
|
fs: opts.fs,
|
|
10846
11096
|
cwd: opts.cwd,
|
|
10847
11097
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
@@ -10857,6 +11107,7 @@ function holdingToken(opts, holds) {
|
|
|
10857
11107
|
function processOptions(opts, header3, hooks) {
|
|
10858
11108
|
return {
|
|
10859
11109
|
...inherited(opts),
|
|
11110
|
+
...opts.owners ? { owners: true } : {},
|
|
10860
11111
|
...opts.identity ? { identity: opts.identity } : {},
|
|
10861
11112
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
10862
11113
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -10901,7 +11152,10 @@ function spawnWasmProcess(opts) {
|
|
|
10901
11152
|
publishStops(process, header3);
|
|
10902
11153
|
const holds = new HeldPaths();
|
|
10903
11154
|
opts.held?.add(holds);
|
|
10904
|
-
const token = holdingToken(opts, holds
|
|
11155
|
+
const token = holdingToken(opts, holds, {
|
|
11156
|
+
cred: () => process.cred,
|
|
11157
|
+
umask: () => process.umask
|
|
11158
|
+
});
|
|
10905
11159
|
process.keptPath = (path) => holds.keptAt(path)?.hidden;
|
|
10906
11160
|
process.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
|
|
10907
11161
|
const worker = opts.createWorker();
|
|
@@ -11262,26 +11516,26 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
11262
11516
|
void entry.final.cancel().catch(() => void 0);
|
|
11263
11517
|
};
|
|
11264
11518
|
const keyOf2 = (owner, method, url) => `${owner} ${method} ${url}`;
|
|
11265
|
-
const hold = (key,
|
|
11519
|
+
const hold = (key, chain2) => {
|
|
11266
11520
|
drop(key);
|
|
11267
|
-
const mine = [...held.keys()].filter((k) => held.get(k)?.owner ===
|
|
11521
|
+
const mine = [...held.keys()].filter((k) => held.get(k)?.owner === chain2.owner);
|
|
11268
11522
|
if (mine.length >= HELD_PER_OWNER) drop(mine[0]);
|
|
11269
11523
|
if (held.size >= HELD_MAX) drop(held.keys().next().value);
|
|
11270
11524
|
const timer = setTimeout(() => drop(key), heldMs);
|
|
11271
11525
|
timer.unref?.();
|
|
11272
|
-
held.set(key, { ...
|
|
11526
|
+
held.set(key, { ...chain2, timer });
|
|
11273
11527
|
};
|
|
11274
|
-
const replay = (
|
|
11275
|
-
const [hop, ...rest2] =
|
|
11528
|
+
const replay = (chain2) => {
|
|
11529
|
+
const [hop, ...rest2] = chain2.hops;
|
|
11276
11530
|
const location = hop && header2(hop.headers, "location");
|
|
11277
|
-
if (!hop || location === void 0) return
|
|
11531
|
+
if (!hop || location === void 0) return chain2.final;
|
|
11278
11532
|
const target = new URL(location, hop.url);
|
|
11279
11533
|
target.hash = "";
|
|
11280
|
-
const method = followedWith(hop.status,
|
|
11534
|
+
const method = followedWith(hop.status, chain2.method);
|
|
11281
11535
|
const away = target.origin !== new URL(hop.url).origin;
|
|
11282
|
-
const print = away ? unauthorized(
|
|
11283
|
-
hold(keyOf2(
|
|
11284
|
-
...
|
|
11536
|
+
const print = away ? unauthorized(chain2.fingerprint) : chain2.fingerprint;
|
|
11537
|
+
hold(keyOf2(chain2.owner, method, target.href), {
|
|
11538
|
+
...chain2,
|
|
11285
11539
|
method,
|
|
11286
11540
|
fingerprint: print,
|
|
11287
11541
|
hops: rest2
|
|
@@ -12870,6 +13124,11 @@ var DECIDE_MS = 100;
|
|
|
12870
13124
|
var INIT_PID = 1;
|
|
12871
13125
|
var SHARED_DIRS = ["/tmp", "/home"];
|
|
12872
13126
|
var encoder3 = new TextEncoder();
|
|
13127
|
+
var USERS_MODES = ["off", "report", "enforce"];
|
|
13128
|
+
function usersMode(mode = "off") {
|
|
13129
|
+
if (USERS_MODES.includes(mode)) return mode;
|
|
13130
|
+
throw new Error(`users must be 'off', 'report' or 'enforce', not ${String(mode)}`);
|
|
13131
|
+
}
|
|
12873
13132
|
function baseName(path) {
|
|
12874
13133
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
12875
13134
|
}
|
|
@@ -12997,10 +13256,13 @@ var Launcher = class {
|
|
|
12997
13256
|
processMounts;
|
|
12998
13257
|
booting = new AbortController();
|
|
12999
13258
|
fstab = Promise.resolve([]);
|
|
13259
|
+
usersMode;
|
|
13000
13260
|
nextPid = 1e3;
|
|
13001
13261
|
boot = Date.now();
|
|
13002
13262
|
terminals = 0;
|
|
13003
13263
|
constructor(options) {
|
|
13264
|
+
this.usersMode = usersMode(options.users);
|
|
13265
|
+
if (this.owners) options.fs.trackOwners?.();
|
|
13004
13266
|
this.mounts = new MountTable({
|
|
13005
13267
|
open: (type, spec) => this.driver(type, spec),
|
|
13006
13268
|
busy: (target) => [...this.openFiles].some((nodes) => nodes.holds(target)) || heldUnder(this.held, target),
|
|
@@ -13054,7 +13316,7 @@ var Launcher = class {
|
|
|
13054
13316
|
}
|
|
13055
13317
|
);
|
|
13056
13318
|
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
13057
|
-
this.users = new UserDb(this.fs);
|
|
13319
|
+
this.users = new UserDb(this.fs, this.owners);
|
|
13058
13320
|
void this.unlinked.sweep("/");
|
|
13059
13321
|
this.watchers.watch(
|
|
13060
13322
|
[this.modulesDir, this.pnpmHome],
|
|
@@ -13066,6 +13328,9 @@ var Launcher = class {
|
|
|
13066
13328
|
this.resetCatalogs();
|
|
13067
13329
|
});
|
|
13068
13330
|
}
|
|
13331
|
+
get owners() {
|
|
13332
|
+
return this.usersMode !== "off";
|
|
13333
|
+
}
|
|
13069
13334
|
setRoutes(table) {
|
|
13070
13335
|
this.routes.set(table);
|
|
13071
13336
|
}
|
|
@@ -13324,6 +13589,7 @@ var Launcher = class {
|
|
|
13324
13589
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
13325
13590
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
13326
13591
|
cred: req.cred,
|
|
13592
|
+
...this.owners ? { owners: true } : {},
|
|
13327
13593
|
program: req.program,
|
|
13328
13594
|
argv0: req.argv0,
|
|
13329
13595
|
args: req.args,
|
|
@@ -13902,6 +14168,12 @@ function usersOp(l, req) {
|
|
|
13902
14168
|
if (req.op === "users-remove") return l.users.remove(req.name, req.options);
|
|
13903
14169
|
return l.users.list();
|
|
13904
14170
|
}
|
|
14171
|
+
function hostOptions(req) {
|
|
14172
|
+
return {
|
|
14173
|
+
...req.hostname !== void 0 ? { hostname: req.hostname } : {},
|
|
14174
|
+
...req.users !== void 0 ? { users: req.users } : {}
|
|
14175
|
+
};
|
|
14176
|
+
}
|
|
13905
14177
|
function serveKernel(port, deps) {
|
|
13906
14178
|
let launcher;
|
|
13907
14179
|
let remote;
|
|
@@ -13976,7 +14248,7 @@ function serveKernel(port, deps) {
|
|
|
13976
14248
|
...deps.createDriverWorker ? { createDriverWorker: deps.createDriverWorker } : {},
|
|
13977
14249
|
...req.modules ? { modules: req.modules } : {},
|
|
13978
14250
|
...req.env ? { env: req.env } : {},
|
|
13979
|
-
...req
|
|
14251
|
+
...hostOptions(req),
|
|
13980
14252
|
...net,
|
|
13981
14253
|
...media ? { media } : {},
|
|
13982
14254
|
onMountPending: (medium) => port.postMessage({ medium }),
|