@ai-ecoverse/slicc-kernel 1.91.0 → 1.93.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 +18 -12
- package/dist/driver-worker.js +9 -7
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +40 -7
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +851 -199
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js.map +2 -2
- package/dist/node-driver-worker.js +150 -11
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +912 -238
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +939 -208
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +2168 -1506
- package/dist/process-worker.js.map +4 -4
- package/package.json +6 -6
package/dist/kernel-worker.js
CHANGED
|
@@ -450,12 +450,36 @@ async function chownAs(fs, cred, path, change) {
|
|
|
450
450
|
}
|
|
451
451
|
|
|
452
452
|
// src/fs/integrity.ts
|
|
453
|
+
var SOURCE_SUFFIXES = [
|
|
454
|
+
".js",
|
|
455
|
+
".mjs",
|
|
456
|
+
".cjs",
|
|
457
|
+
".json",
|
|
458
|
+
".py",
|
|
459
|
+
".pyc",
|
|
460
|
+
".pth",
|
|
461
|
+
".zip",
|
|
462
|
+
".so",
|
|
463
|
+
".wasm",
|
|
464
|
+
".sh"
|
|
465
|
+
];
|
|
466
|
+
var EXEC_OPS = { failed: "exec-integrity", unknown: "exec-unverified" };
|
|
467
|
+
var READ_OPS = { failed: "read-integrity", unknown: "read-unverified" };
|
|
453
468
|
var KERNEL_CALLER = { pid: 0, uid: 0 };
|
|
454
469
|
function integrityOptions(options) {
|
|
455
470
|
if (options && typeof options.lookup !== "function") {
|
|
456
471
|
throw new TypeError("protect.integrity.lookup must be a function");
|
|
457
472
|
}
|
|
458
473
|
integrityUnknown(options);
|
|
474
|
+
integritySources(options);
|
|
475
|
+
}
|
|
476
|
+
function integritySources(options) {
|
|
477
|
+
const sources = options?.sources ?? SOURCE_SUFFIXES;
|
|
478
|
+
const suffix = (s) => typeof s === "string" && /^\.[^/]+$/.test(s);
|
|
479
|
+
if (!Array.isArray(sources) || !sources.every(suffix)) {
|
|
480
|
+
throw new TypeError("protect.integrity.sources must be a list of suffixes such as .js");
|
|
481
|
+
}
|
|
482
|
+
return [...sources];
|
|
459
483
|
}
|
|
460
484
|
function integrityUnknown(options) {
|
|
461
485
|
const unknown = options?.unknown ?? "allow";
|
|
@@ -477,16 +501,21 @@ var Integrity = class {
|
|
|
477
501
|
unknown;
|
|
478
502
|
report;
|
|
479
503
|
unverified = /* @__PURE__ */ new Set();
|
|
504
|
+
unread = /* @__PURE__ */ new Set();
|
|
505
|
+
sources;
|
|
506
|
+
passed = /* @__PURE__ */ new Set();
|
|
507
|
+
generation = 0;
|
|
480
508
|
constructor(prefixes2, root, options, report) {
|
|
481
509
|
this.prefixes = prefixes2;
|
|
482
510
|
this.root = root;
|
|
483
511
|
this.lookup = options.lookup;
|
|
484
512
|
this.unknown = integrityUnknown(options);
|
|
513
|
+
this.sources = integritySources(options);
|
|
485
514
|
this.report = report;
|
|
486
515
|
}
|
|
487
|
-
async real(path, asked) {
|
|
516
|
+
async real(path, asked, known) {
|
|
488
517
|
const at = normalizePath(path);
|
|
489
|
-
const real = await this.root.realpath?.(at, true).catch(() => void 0) ?? at;
|
|
518
|
+
const real = known ?? await this.root.realpath?.(at, true).catch(() => void 0) ?? at;
|
|
490
519
|
if (isProtected(this.prefixes, real)) return { real, name: real };
|
|
491
520
|
const names = asked === void 0 ? [] : await namesOf(this.root, asked);
|
|
492
521
|
if (real !== at) names.push(...await namesOf(this.root, at));
|
|
@@ -511,6 +540,51 @@ var Integrity = class {
|
|
|
511
540
|
const read = name2 !== real ? { bytes: await plain(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
|
|
512
541
|
const { bytes } = read;
|
|
513
542
|
const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
|
|
543
|
+
await this.verify(name2, bytes, caller, EXEC_OPS);
|
|
544
|
+
return keyed;
|
|
545
|
+
}
|
|
546
|
+
get readsChecked() {
|
|
547
|
+
return this.sources.length > 0;
|
|
548
|
+
}
|
|
549
|
+
async readSource(path, caller, plain) {
|
|
550
|
+
const found = await this.source(path);
|
|
551
|
+
return found === void 0 ? plain() : this.checked(found, caller, plain);
|
|
552
|
+
}
|
|
553
|
+
async openSource(path, caller, real) {
|
|
554
|
+
const found = await this.source(path, real);
|
|
555
|
+
if (found === void 0) return;
|
|
556
|
+
if (found.name === found.real && this.root.version) {
|
|
557
|
+
if (this.passed.has(`${found.real}\0${await this.root.version(found.real, true)}`)) return;
|
|
558
|
+
}
|
|
559
|
+
await this.checked(found, caller, () => this.root.readFileBuffer(found.real));
|
|
560
|
+
}
|
|
561
|
+
async checked(found, caller, plain) {
|
|
562
|
+
const { real, name: name2 } = found;
|
|
563
|
+
if (name2 !== real || !this.root.readVersioned) {
|
|
564
|
+
const bytes2 = await plain();
|
|
565
|
+
await this.verify(name2, bytes2, caller, READ_OPS);
|
|
566
|
+
return bytes2;
|
|
567
|
+
}
|
|
568
|
+
const { bytes, version } = await this.root.readVersioned(real, true);
|
|
569
|
+
await this.pass(`${real}\0${version}`, () => this.verify(name2, bytes, caller, READ_OPS));
|
|
570
|
+
return bytes;
|
|
571
|
+
}
|
|
572
|
+
async pass(key, check) {
|
|
573
|
+
if (this.passed.has(key)) return;
|
|
574
|
+
const generation = this.generation;
|
|
575
|
+
await check();
|
|
576
|
+
if (generation === this.generation) this.passed.add(key);
|
|
577
|
+
}
|
|
578
|
+
async source(path, known) {
|
|
579
|
+
if (this.sources.length === 0) return void 0;
|
|
580
|
+
const found = await this.real(path, void 0, known);
|
|
581
|
+
if (found === void 0) return void 0;
|
|
582
|
+
const suffixed = (p) => this.sources.some((s) => p.endsWith(s));
|
|
583
|
+
if (suffixed(found.real) || suffixed(found.name) || suffixed(normalizePath(path))) return found;
|
|
584
|
+
const st = await this.root.stat(found.real).catch(() => void 0);
|
|
585
|
+
return st?.isFile && ((st.mode ?? 0) & 73) !== 0 ? found : void 0;
|
|
586
|
+
}
|
|
587
|
+
async verify(name2, bytes, caller, ops) {
|
|
514
588
|
const actual = await sha256(bytes);
|
|
515
589
|
const denial = { pid: caller.pid, uid: caller.uid, path: name2, actual };
|
|
516
590
|
const tagged = caller.tag !== void 0 ? { tag: caller.tag } : {};
|
|
@@ -518,27 +592,33 @@ var Integrity = class {
|
|
|
518
592
|
try {
|
|
519
593
|
expected = await this.expected(name2);
|
|
520
594
|
} catch {
|
|
521
|
-
this.say({ ...denial, ...tagged, op:
|
|
595
|
+
this.say({ ...denial, ...tagged, op: ops.failed, errno: "EACCES" });
|
|
522
596
|
throw fsError("EACCES", `integrity lookup failed: ${name2}`);
|
|
523
597
|
}
|
|
524
|
-
if (expected ===
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
return keyed;
|
|
598
|
+
if (expected === actual) return;
|
|
599
|
+
if (expected === void 0 && this.unknown === "allow") {
|
|
600
|
+
const seen = ops === EXEC_OPS ? this.unverified : this.unread;
|
|
601
|
+
if (!seen.has(name2)) {
|
|
602
|
+
seen.add(name2);
|
|
603
|
+
this.say({ ...denial, ...tagged, op: ops.unknown, errno: "ENODATA" });
|
|
531
604
|
}
|
|
532
|
-
|
|
533
|
-
return keyed;
|
|
605
|
+
return;
|
|
534
606
|
}
|
|
535
607
|
const known = expected !== void 0 ? { expected } : {};
|
|
536
|
-
this.say({ ...denial, ...tagged, ...known, op:
|
|
608
|
+
this.say({ ...denial, ...tagged, ...known, op: ops.failed, errno: "EACCES" });
|
|
537
609
|
throw fsError("EACCES", `integrity check failed: ${name2}`);
|
|
538
610
|
}
|
|
539
611
|
forget(path) {
|
|
540
|
-
|
|
541
|
-
|
|
612
|
+
this.generation++;
|
|
613
|
+
for (const seen of [this.unverified, this.unread]) {
|
|
614
|
+
for (const name2 of [...seen]) {
|
|
615
|
+
if (path === void 0 || isProtected([path], name2)) seen.delete(name2);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
for (const key of [...this.passed]) {
|
|
619
|
+
if (path === void 0 || isProtected([path], key.slice(0, key.indexOf("\0")))) {
|
|
620
|
+
this.passed.delete(key);
|
|
621
|
+
}
|
|
542
622
|
}
|
|
543
623
|
}
|
|
544
624
|
async expected(path) {
|
|
@@ -560,9 +640,13 @@ function protectInit(protection) {
|
|
|
560
640
|
return {
|
|
561
641
|
paths: [...protection.paths],
|
|
562
642
|
...writers.length > 0 ? { writers } : {},
|
|
563
|
-
...integrity ? { integrity:
|
|
643
|
+
...integrity ? { integrity: integrityInit(integrity) } : {}
|
|
564
644
|
};
|
|
565
645
|
}
|
|
646
|
+
function integrityInit(integrity) {
|
|
647
|
+
const unknown = integrityUnknown(integrity);
|
|
648
|
+
return integrity.sources === void 0 ? { unknown } : { unknown, sources: integritySources(integrity) };
|
|
649
|
+
}
|
|
566
650
|
function writerTags(protection) {
|
|
567
651
|
const writers = protection?.writers ?? [];
|
|
568
652
|
if (!Array.isArray(writers) || writers.some((tag) => typeof tag !== "string" || tag === "")) {
|
|
@@ -746,15 +830,15 @@ var ProtectedFs = class {
|
|
|
746
830
|
}
|
|
747
831
|
} : {}
|
|
748
832
|
};
|
|
749
|
-
const
|
|
833
|
+
const view2 = {};
|
|
750
834
|
for (let at = fs; at && at !== Object.prototype; at = Object.getPrototypeOf(at)) {
|
|
751
835
|
for (const name2 of Object.getOwnPropertyNames(at)) {
|
|
752
|
-
if (name2 === "constructor" || Object.hasOwn(
|
|
836
|
+
if (name2 === "constructor" || Object.hasOwn(view2, name2)) continue;
|
|
753
837
|
const value = fs[name2];
|
|
754
|
-
|
|
838
|
+
view2[name2] = typeof value === "function" ? value.bind(fs) : value;
|
|
755
839
|
}
|
|
756
840
|
}
|
|
757
|
-
return Object.assign(
|
|
841
|
+
return Object.assign(view2, own);
|
|
758
842
|
}
|
|
759
843
|
};
|
|
760
844
|
|
|
@@ -873,6 +957,23 @@ var RemoteWatch = class {
|
|
|
873
957
|
}
|
|
874
958
|
};
|
|
875
959
|
|
|
960
|
+
// src/fs/view.ts
|
|
961
|
+
function view(target, overrides) {
|
|
962
|
+
const keys = new Set(Object.keys(overrides));
|
|
963
|
+
return new Proxy(target, {
|
|
964
|
+
get(t, prop, receiver) {
|
|
965
|
+
if (keys.has(prop)) return overrides[prop];
|
|
966
|
+
return Reflect.get(t, prop, receiver);
|
|
967
|
+
},
|
|
968
|
+
set(t, prop, value) {
|
|
969
|
+
return Reflect.set(t, prop, value);
|
|
970
|
+
},
|
|
971
|
+
getPrototypeOf(t) {
|
|
972
|
+
return Reflect.getPrototypeOf(t);
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
|
|
876
977
|
// src/fs/opfs.ts
|
|
877
978
|
var S_IFDIR = 16384;
|
|
878
979
|
var S_IFREG = 32768;
|
|
@@ -1012,11 +1113,16 @@ var OpfsFs = class {
|
|
|
1012
1113
|
remote;
|
|
1013
1114
|
ranged;
|
|
1014
1115
|
owners = false;
|
|
1116
|
+
rejectLinks = false;
|
|
1015
1117
|
mounts = {};
|
|
1118
|
+
locks;
|
|
1119
|
+
lockPrefix;
|
|
1016
1120
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
1017
1121
|
this.root = root;
|
|
1018
1122
|
this.meta = sidecar(meta);
|
|
1019
1123
|
this.ranged = options.ranged === true;
|
|
1124
|
+
this.locks = options.locks === void 0 ? lockManager() : options.locks ?? void 0;
|
|
1125
|
+
this.lockPrefix = `slicc-excl:${channel ?? ""}:`;
|
|
1020
1126
|
this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
|
|
1021
1127
|
this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`);
|
|
1022
1128
|
if (this.channel) {
|
|
@@ -1043,12 +1149,13 @@ var OpfsFs = class {
|
|
|
1043
1149
|
return this.remote?.announce(paths) ?? Promise.resolve();
|
|
1044
1150
|
}
|
|
1045
1151
|
committed(target) {
|
|
1152
|
+
this.fileTimes.delete(target);
|
|
1046
1153
|
if (this.remote?.watched()) this.remote.wrote(target);
|
|
1047
1154
|
}
|
|
1048
1155
|
counted = [];
|
|
1049
|
-
async stamp(path) {
|
|
1156
|
+
async stamp(path, cached = false) {
|
|
1050
1157
|
const paths = [path, "/"];
|
|
1051
|
-
const [entry, root] = this.meta.fresh ? await this.meta.fresh(paths) : await this.meta.get(paths);
|
|
1158
|
+
const [entry, root] = this.meta.fresh && !cached ? await this.meta.fresh(paths) : await this.meta.get(paths);
|
|
1052
1159
|
return `${entry?.writes ?? 0}:${root?.epoch ?? 0}`;
|
|
1053
1160
|
}
|
|
1054
1161
|
async epoch() {
|
|
@@ -1147,13 +1254,25 @@ var OpfsFs = class {
|
|
|
1147
1254
|
this.counted = versions ? prefixes2 : [];
|
|
1148
1255
|
}
|
|
1149
1256
|
unguarded() {
|
|
1150
|
-
return
|
|
1257
|
+
return view(this, { guarded: [] });
|
|
1258
|
+
}
|
|
1259
|
+
noLinks() {
|
|
1260
|
+
return view(this, { rejectLinks: true });
|
|
1151
1261
|
}
|
|
1152
1262
|
refuse(path, holding = false) {
|
|
1153
1263
|
if (isProtected(this.guarded, path) || holding && holdsProtected(this.guarded, path)) {
|
|
1154
1264
|
throw fsError("EROFS", path);
|
|
1155
1265
|
}
|
|
1156
1266
|
}
|
|
1267
|
+
async locked(physicalPath, op) {
|
|
1268
|
+
if (!this.locks) return op();
|
|
1269
|
+
const key = `${this.lockPrefix}${physicalPath}`;
|
|
1270
|
+
let result;
|
|
1271
|
+
await this.locks.request(key, async () => {
|
|
1272
|
+
result = await op();
|
|
1273
|
+
});
|
|
1274
|
+
return result;
|
|
1275
|
+
}
|
|
1157
1276
|
async chown(path, change) {
|
|
1158
1277
|
if (!this.owners) return;
|
|
1159
1278
|
if (change.kind === "new") {
|
|
@@ -1285,8 +1404,15 @@ var OpfsFs = class {
|
|
|
1285
1404
|
const link2 = await this.linkAlong(current);
|
|
1286
1405
|
if (!link2) throw err;
|
|
1287
1406
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
1407
|
+
if (this.rejectLinks) throw fsError("ELOOP", path);
|
|
1288
1408
|
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
1289
|
-
|
|
1409
|
+
if (target.split("/").includes("..")) {
|
|
1410
|
+
const resolved2 = await this.physical(parentOf3(link2.path), target, hops + 1, path);
|
|
1411
|
+
current = resolved2.path;
|
|
1412
|
+
hops = resolved2.hops;
|
|
1413
|
+
} else {
|
|
1414
|
+
current = resolvePath(parentOf3(link2.path), target);
|
|
1415
|
+
}
|
|
1290
1416
|
this.crossing(path, current);
|
|
1291
1417
|
}
|
|
1292
1418
|
}
|
|
@@ -1295,7 +1421,8 @@ var OpfsFs = class {
|
|
|
1295
1421
|
async physical(base, path, used, of) {
|
|
1296
1422
|
let done4 = [];
|
|
1297
1423
|
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
1298
|
-
|
|
1424
|
+
let hops = used;
|
|
1425
|
+
while (todo.length > 0) {
|
|
1299
1426
|
const part = todo.shift();
|
|
1300
1427
|
if (part === "..") done4.pop();
|
|
1301
1428
|
else if (!todo.includes("..")) done4.push(part);
|
|
@@ -1305,6 +1432,7 @@ var OpfsFs = class {
|
|
|
1305
1432
|
const st = await this.lstat(at);
|
|
1306
1433
|
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
1307
1434
|
if (!st.isSymbolicLink) done4.push(part);
|
|
1435
|
+
else if (this.rejectLinks) throw fsError("ELOOP", of);
|
|
1308
1436
|
else if (++hops > MAX_LINKS2) throw fsError("ELOOP", path);
|
|
1309
1437
|
else {
|
|
1310
1438
|
const link2 = await this.readlink(at);
|
|
@@ -1313,7 +1441,7 @@ var OpfsFs = class {
|
|
|
1313
1441
|
}
|
|
1314
1442
|
}
|
|
1315
1443
|
}
|
|
1316
|
-
return `/${done4.join("/")}
|
|
1444
|
+
return { path: `/${done4.join("/")}`, hops };
|
|
1317
1445
|
}
|
|
1318
1446
|
mode(path, directory, meta) {
|
|
1319
1447
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
@@ -1357,6 +1485,11 @@ var OpfsFs = class {
|
|
|
1357
1485
|
return entry.timesAt >= ms;
|
|
1358
1486
|
}
|
|
1359
1487
|
movePending(from, to) {
|
|
1488
|
+
if (to !== void 0) {
|
|
1489
|
+
for (const path of [...this.fileTimes.keys()]) {
|
|
1490
|
+
if (within2(path, to)) this.fileTimes.delete(path);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1360
1493
|
for (const [path, ms] of [...this.fileTimes]) {
|
|
1361
1494
|
if (!within2(path, from)) continue;
|
|
1362
1495
|
this.fileTimes.delete(path);
|
|
@@ -1364,8 +1497,7 @@ var OpfsFs = class {
|
|
|
1364
1497
|
}
|
|
1365
1498
|
}
|
|
1366
1499
|
flushing = {};
|
|
1367
|
-
touch(...dirs) {
|
|
1368
|
-
const now = Date.now();
|
|
1500
|
+
touch(now, ...dirs) {
|
|
1369
1501
|
for (const dir of dirs) {
|
|
1370
1502
|
this.dirTimes.set(dir, now);
|
|
1371
1503
|
this.dirDirty.add(dir);
|
|
@@ -1478,12 +1610,12 @@ var OpfsFs = class {
|
|
|
1478
1610
|
false
|
|
1479
1611
|
);
|
|
1480
1612
|
}
|
|
1481
|
-
async readVersioned(path) {
|
|
1613
|
+
async readVersioned(path, cached = false) {
|
|
1482
1614
|
const handle = await this.existing(path);
|
|
1483
1615
|
return this.retrying(
|
|
1484
1616
|
path,
|
|
1485
1617
|
async () => {
|
|
1486
|
-
const stamp = await this.stamp(path);
|
|
1618
|
+
const stamp = await this.stamp(path, cached);
|
|
1487
1619
|
const file = await handle.getFile();
|
|
1488
1620
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
1489
1621
|
return { bytes, version: `${file.lastModified}:${file.size}:${stamp}` };
|
|
@@ -1491,12 +1623,12 @@ var OpfsFs = class {
|
|
|
1491
1623
|
false
|
|
1492
1624
|
);
|
|
1493
1625
|
}
|
|
1494
|
-
async version(path) {
|
|
1626
|
+
async version(path, cached = false) {
|
|
1495
1627
|
const handle = await this.existing(path);
|
|
1496
1628
|
return this.retrying(
|
|
1497
1629
|
path,
|
|
1498
1630
|
async () => {
|
|
1499
|
-
const stamp = await this.stamp(path);
|
|
1631
|
+
const stamp = await this.stamp(path, cached);
|
|
1500
1632
|
const file = await handle.getFile();
|
|
1501
1633
|
return `${file.lastModified}:${file.size}:${stamp}`;
|
|
1502
1634
|
},
|
|
@@ -1581,7 +1713,7 @@ var OpfsFs = class {
|
|
|
1581
1713
|
dir,
|
|
1582
1714
|
(parent) => parent.getFileHandle(name2, { create: true })
|
|
1583
1715
|
);
|
|
1584
|
-
if (!existed) this.touch(parentOf3(target));
|
|
1716
|
+
if (!existed) this.touch(Date.now(), parentOf3(target));
|
|
1585
1717
|
return [handle, existed, target];
|
|
1586
1718
|
} catch (err) {
|
|
1587
1719
|
const code = err?.name === "TypeMismatchError" ? "EISDIR" : null;
|
|
@@ -1636,6 +1768,7 @@ var OpfsFs = class {
|
|
|
1636
1768
|
);
|
|
1637
1769
|
}
|
|
1638
1770
|
async mkdir(path, options = {}) {
|
|
1771
|
+
if (!options.recursive) return this.mkdirExcl(path, options.owner);
|
|
1639
1772
|
let found;
|
|
1640
1773
|
try {
|
|
1641
1774
|
found = await this.locate(path, true);
|
|
@@ -1644,28 +1777,75 @@ var OpfsFs = class {
|
|
|
1644
1777
|
}
|
|
1645
1778
|
if (found) {
|
|
1646
1779
|
const directory = found.handle?.kind === "directory";
|
|
1647
|
-
if (
|
|
1648
|
-
throw fsError(
|
|
1780
|
+
if (directory) return;
|
|
1781
|
+
throw fsError("ENOTDIR", path);
|
|
1649
1782
|
}
|
|
1650
1783
|
const [entry] = await this.meta.get([path]);
|
|
1651
1784
|
if (entry?.link !== void 0) throw fsError("EEXIST", path);
|
|
1652
1785
|
const { owner } = options;
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
await this.mkdir(parentOf3(path), { recursive: true, ...above ? { owner: above } : {} });
|
|
1661
|
-
}
|
|
1786
|
+
const mode = owner?.parents;
|
|
1787
|
+
const above = owner && {
|
|
1788
|
+
uid: owner.uid,
|
|
1789
|
+
gid: owner.gid,
|
|
1790
|
+
...mode !== void 0 ? { mode, parents: mode } : {}
|
|
1791
|
+
};
|
|
1792
|
+
await this.mkdir(parentOf3(path), { recursive: true, ...above ? { owner: above } : {} });
|
|
1662
1793
|
const parent = await this.locate(parentOf3(path), true);
|
|
1663
1794
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
1664
1795
|
this.refuse(resolvePath(parent.path, baseOf(path)));
|
|
1665
1796
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
1797
|
+
const now = Date.now();
|
|
1666
1798
|
const made2 = `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`;
|
|
1667
1799
|
await this.stampNew(made2, owner, true);
|
|
1668
|
-
this.touch(parent.path, made2);
|
|
1800
|
+
this.touch(now, parent.path, made2);
|
|
1801
|
+
}
|
|
1802
|
+
async mkdirExcl(path, owner) {
|
|
1803
|
+
const parent = await this.locate(parentOf3(path), true);
|
|
1804
|
+
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
1805
|
+
const dir = parent.handle;
|
|
1806
|
+
const name2 = baseOf(path);
|
|
1807
|
+
const physical = resolvePath(parent.path, name2);
|
|
1808
|
+
await this.locked(physical, async () => {
|
|
1809
|
+
if (await this.handleExists(dir, name2)) throw fsError("EEXIST", path);
|
|
1810
|
+
const freshMeta = this.meta.fresh ? await this.meta.fresh([path]) : await this.meta.get([path]);
|
|
1811
|
+
if (freshMeta[0]?.link !== void 0) throw fsError("EEXIST", path);
|
|
1812
|
+
this.forget(physical);
|
|
1813
|
+
this.refuse(physical);
|
|
1814
|
+
await dir.getDirectoryHandle(name2, { create: true });
|
|
1815
|
+
const now = Date.now();
|
|
1816
|
+
const made2 = `${parent.path === "/" ? "" : parent.path}/${name2}`;
|
|
1817
|
+
await this.stampNew(made2, owner, true);
|
|
1818
|
+
this.touch(now, parent.path, made2);
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
async createExclusive(path, owner) {
|
|
1822
|
+
const parent = await this.locate(parentOf3(path), true);
|
|
1823
|
+
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
1824
|
+
const dir = parent.handle;
|
|
1825
|
+
const name2 = baseOf(path);
|
|
1826
|
+
const physical = resolvePath(parent.path, name2);
|
|
1827
|
+
await this.locked(physical, async () => {
|
|
1828
|
+
if (await this.handleExists(dir, name2)) throw fsError("EEXIST", path);
|
|
1829
|
+
const freshMeta = this.meta.fresh ? await this.meta.fresh([path]) : await this.meta.get([path]);
|
|
1830
|
+
if (freshMeta[0] !== void 0) throw fsError("EEXIST", path);
|
|
1831
|
+
this.forget(physical);
|
|
1832
|
+
this.refuse(physical);
|
|
1833
|
+
await dir.getFileHandle(name2, { create: true });
|
|
1834
|
+
const now = Date.now();
|
|
1835
|
+
const made2 = `${parent.path === "/" ? "" : parent.path}/${name2}`;
|
|
1836
|
+
await this.stampNew(made2, owner, false);
|
|
1837
|
+
this.touch(now, parent.path, made2);
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
async handleExists(dir, name2) {
|
|
1841
|
+
try {
|
|
1842
|
+
await dir.getDirectoryHandle(name2);
|
|
1843
|
+
return true;
|
|
1844
|
+
} catch (err) {
|
|
1845
|
+
if (err?.name === "TypeMismatchError") return true;
|
|
1846
|
+
if (err?.name === "NotFoundError") return false;
|
|
1847
|
+
throw err;
|
|
1848
|
+
}
|
|
1669
1849
|
}
|
|
1670
1850
|
async rm(path, options = {}) {
|
|
1671
1851
|
let found;
|
|
@@ -1676,8 +1856,8 @@ var OpfsFs = class {
|
|
|
1676
1856
|
if (options.force && error.code === "ENOENT") return;
|
|
1677
1857
|
throw error;
|
|
1678
1858
|
}
|
|
1679
|
-
this.refuse(found.path, true);
|
|
1680
1859
|
if (options.file && found.handle?.kind === "directory") throw fsError("EISDIR", path);
|
|
1860
|
+
this.refuse(found.path, true);
|
|
1681
1861
|
if (found.handle) {
|
|
1682
1862
|
const [dir, name2] = await this.parent(found.path);
|
|
1683
1863
|
try {
|
|
@@ -1688,22 +1868,23 @@ var OpfsFs = class {
|
|
|
1688
1868
|
} catch (err) {
|
|
1689
1869
|
throw translate(err, path);
|
|
1690
1870
|
}
|
|
1871
|
+
const now = Date.now();
|
|
1691
1872
|
const file = found.handle.kind === "file";
|
|
1692
1873
|
if (!file || this.remote?.watched()) this.changed(found.path);
|
|
1693
1874
|
else this.forget(found.path);
|
|
1694
1875
|
this.movePending(found.path);
|
|
1695
1876
|
if (file && this.meta.absent?.(found.path)) {
|
|
1696
|
-
this.touch(parentOf3(found.path));
|
|
1877
|
+
this.touch(now, parentOf3(found.path));
|
|
1697
1878
|
return;
|
|
1698
1879
|
}
|
|
1699
1880
|
if (file && this.meta.removeFile) {
|
|
1700
1881
|
await this.meta.removeFile(found.path);
|
|
1701
|
-
this.touch(parentOf3(found.path));
|
|
1882
|
+
this.touch(now, parentOf3(found.path));
|
|
1702
1883
|
return;
|
|
1703
1884
|
}
|
|
1704
1885
|
}
|
|
1705
1886
|
await this.meta.remove([found.path]);
|
|
1706
|
-
this.touch(parentOf3(found.path));
|
|
1887
|
+
this.touch(Date.now(), parentOf3(found.path));
|
|
1707
1888
|
}
|
|
1708
1889
|
links() {
|
|
1709
1890
|
return false;
|
|
@@ -1711,11 +1892,14 @@ var OpfsFs = class {
|
|
|
1711
1892
|
async link(from, to, follow2) {
|
|
1712
1893
|
await (follow2 ? this.stat(from) : this.lstat(from));
|
|
1713
1894
|
if (!(await this.stat(parentOf3(to))).isDirectory) throw fsError("ENOTDIR", to);
|
|
1714
|
-
|
|
1895
|
+
const taken = await this.lstat(to).then(
|
|
1715
1896
|
() => true,
|
|
1716
|
-
() =>
|
|
1717
|
-
|
|
1718
|
-
|
|
1897
|
+
(err) => {
|
|
1898
|
+
if (missing2(err)) return false;
|
|
1899
|
+
throw err;
|
|
1900
|
+
}
|
|
1901
|
+
);
|
|
1902
|
+
if (taken) throw fsError("EEXIST", to);
|
|
1719
1903
|
throw fsError("EPERM", `${from}: this file system has no hard links`);
|
|
1720
1904
|
}
|
|
1721
1905
|
async rename(from, to) {
|
|
@@ -1755,7 +1939,7 @@ var OpfsFs = class {
|
|
|
1755
1939
|
if (source.link) {
|
|
1756
1940
|
if (target?.handle) await this.rm(destination);
|
|
1757
1941
|
await this.meta.move(source.path, destination, carry);
|
|
1758
|
-
this.touch(parentOf3(source.path), parent.path);
|
|
1942
|
+
this.touch(Date.now(), parentOf3(source.path), parent.path);
|
|
1759
1943
|
return;
|
|
1760
1944
|
}
|
|
1761
1945
|
const dir = parent.handle;
|
|
@@ -1778,7 +1962,7 @@ var OpfsFs = class {
|
|
|
1778
1962
|
}
|
|
1779
1963
|
if (copied) await this.restamp(destination, timed2);
|
|
1780
1964
|
this.changed(source.path, destination);
|
|
1781
|
-
this.touch(parentOf3(source.path), parent.path);
|
|
1965
|
+
this.touch(Date.now(), parentOf3(source.path), parent.path);
|
|
1782
1966
|
}
|
|
1783
1967
|
async modified(path) {
|
|
1784
1968
|
const handle = await this.handle(path);
|
|
@@ -1848,7 +2032,7 @@ var OpfsFs = class {
|
|
|
1848
2032
|
...fields
|
|
1849
2033
|
}))
|
|
1850
2034
|
);
|
|
1851
|
-
this.touch(parent.path);
|
|
2035
|
+
this.touch(Date.now(), parent.path);
|
|
1852
2036
|
}
|
|
1853
2037
|
async realpath(path, follow2) {
|
|
1854
2038
|
return (await this.locate(path, follow2)).path;
|
|
@@ -2280,6 +2464,9 @@ async function present(fs, path, directory) {
|
|
|
2280
2464
|
}
|
|
2281
2465
|
async function finalOf(fs, walked, want, options) {
|
|
2282
2466
|
const perm = walked.perm;
|
|
2467
|
+
if (options.follow === false && perm.link !== void 0) {
|
|
2468
|
+
return [{ ...perm, mode: 511 }, false];
|
|
2469
|
+
}
|
|
2283
2470
|
if ((want & X_OK) === 0 || options.directory !== void 0) {
|
|
2284
2471
|
return [perm, options.directory !== false];
|
|
2285
2472
|
}
|
|
@@ -2451,6 +2638,18 @@ async function chmodMode(g, path, mode) {
|
|
|
2451
2638
|
if (!g.dac.enforcing || !perm || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
|
|
2452
2639
|
return mode & ~S_ISGID3;
|
|
2453
2640
|
}
|
|
2641
|
+
function heldChmodMode(g, path, st, mode) {
|
|
2642
|
+
const perm = permOf(st);
|
|
2643
|
+
if (g.cred.euid !== 0 && perm.uid !== g.cred.euid) deny(g, "fchmod", path, "EPERM");
|
|
2644
|
+
if (!g.dac.enforcing || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
|
|
2645
|
+
return mode & ~S_ISGID3;
|
|
2646
|
+
}
|
|
2647
|
+
function heldRetimable(g, path, st, now) {
|
|
2648
|
+
const perm = permOf(st);
|
|
2649
|
+
if (g.cred.euid === 0 || perm.uid === g.cred.euid) return;
|
|
2650
|
+
if (!now) deny(g, "futimens", path, "EPERM");
|
|
2651
|
+
else if (!permits(g.cred, perm, W_OK, false)) deny(g, "futimens", path);
|
|
2652
|
+
}
|
|
2454
2653
|
async function retimable(g, op, path, now = false) {
|
|
2455
2654
|
const follow2 = op !== "lutimes";
|
|
2456
2655
|
if (!now) return void await ownerOnly(g, op, path, follow2);
|
|
@@ -2902,6 +3101,17 @@ var FdTable = class _FdTable {
|
|
|
2902
3101
|
this.status.delete(fd);
|
|
2903
3102
|
void Promise.resolve(previous?.release()).catch(() => void 0);
|
|
2904
3103
|
}
|
|
3104
|
+
async replaceAt(fd, file) {
|
|
3105
|
+
if (fd < 0 || fd >= _FdTable.MAX_FDS) {
|
|
3106
|
+
void Promise.resolve(file.release()).catch(() => void 0);
|
|
3107
|
+
throw new KernelError("EBADF");
|
|
3108
|
+
}
|
|
3109
|
+
const previous = this.fds.get(fd);
|
|
3110
|
+
this.fds.set(fd, file);
|
|
3111
|
+
this.cloexec.delete(fd);
|
|
3112
|
+
this.status.delete(fd);
|
|
3113
|
+
await Promise.resolve(previous?.release()).catch(() => void 0);
|
|
3114
|
+
}
|
|
2905
3115
|
dup(fd, min = 0) {
|
|
2906
3116
|
return this.install(this.get(fd).retain(), min);
|
|
2907
3117
|
}
|
|
@@ -2910,6 +3120,11 @@ var FdTable = class _FdTable {
|
|
|
2910
3120
|
if (oldFd !== newFd) this.installAt(newFd, file.retain());
|
|
2911
3121
|
return newFd;
|
|
2912
3122
|
}
|
|
3123
|
+
async dup2Clipboard(oldFd, newFd) {
|
|
3124
|
+
const file = this.get(oldFd);
|
|
3125
|
+
if (oldFd !== newFd) await this.replaceAt(newFd, file.retain());
|
|
3126
|
+
return newFd;
|
|
3127
|
+
}
|
|
2913
3128
|
close(fd) {
|
|
2914
3129
|
const file = this.get(fd);
|
|
2915
3130
|
this.fds.delete(fd);
|
|
@@ -3969,7 +4184,7 @@ function homeOf(home) {
|
|
|
3969
4184
|
if (typeof home !== "string" || !home.startsWith("/") || /[:\r\n]/.test(home)) {
|
|
3970
4185
|
throw fsError("EINVAL", `not a home directory: ${String(home)}`);
|
|
3971
4186
|
}
|
|
3972
|
-
return home;
|
|
4187
|
+
return normalizePath(home);
|
|
3973
4188
|
}
|
|
3974
4189
|
function freeId(users, groups) {
|
|
3975
4190
|
const taken = /* @__PURE__ */ new Set([...users.map((r) => r.uid), ...groups.map((r) => r.gid)]);
|
|
@@ -4750,6 +4965,7 @@ var ClipboardChannel = class {
|
|
|
4750
4965
|
size = 0;
|
|
4751
4966
|
wrote = false;
|
|
4752
4967
|
failed = false;
|
|
4968
|
+
aborted = false;
|
|
4753
4969
|
constructor(broker, access2, stamp) {
|
|
4754
4970
|
this.broker = broker;
|
|
4755
4971
|
this.access = access2;
|
|
@@ -4804,11 +5020,14 @@ var ClipboardChannel = class {
|
|
|
4804
5020
|
poll() {
|
|
4805
5021
|
return READY;
|
|
4806
5022
|
}
|
|
5023
|
+
abort() {
|
|
5024
|
+
this.aborted = true;
|
|
5025
|
+
}
|
|
4807
5026
|
async close() {
|
|
4808
5027
|
this.snapshot = void 0;
|
|
4809
5028
|
this.taken = void 0;
|
|
4810
5029
|
const commits = this.access === "write" || this.access === "both" && this.wrote;
|
|
4811
|
-
if (!commits || this.failed) return;
|
|
5030
|
+
if (!commits || this.failed || this.aborted) return;
|
|
4812
5031
|
const bytes = joined2(this.chunks, this.size);
|
|
4813
5032
|
this.chunks = [];
|
|
4814
5033
|
this.size = 0;
|
|
@@ -5273,15 +5492,15 @@ function frame(opcode, payload) {
|
|
|
5273
5492
|
const n = payload.length;
|
|
5274
5493
|
const size = n < 126 ? 2 : n < 65536 ? 4 : 10;
|
|
5275
5494
|
const out = new Uint8Array(size + n);
|
|
5276
|
-
const
|
|
5495
|
+
const view2 = new DataView(out.buffer);
|
|
5277
5496
|
out[0] = 128 | opcode;
|
|
5278
5497
|
if (n < 126) out[1] = n;
|
|
5279
5498
|
else if (n < 65536) {
|
|
5280
5499
|
out[1] = 126;
|
|
5281
|
-
|
|
5500
|
+
view2.setUint16(2, n);
|
|
5282
5501
|
} else {
|
|
5283
5502
|
out[1] = 127;
|
|
5284
|
-
|
|
5503
|
+
view2.setBigUint64(2, BigInt(n));
|
|
5285
5504
|
}
|
|
5286
5505
|
out.set(payload, size);
|
|
5287
5506
|
return out;
|
|
@@ -5403,9 +5622,9 @@ var WsReader = class {
|
|
|
5403
5622
|
if (short < 126) return short;
|
|
5404
5623
|
const ext = new Uint8Array(short === 126 ? 2 : 8);
|
|
5405
5624
|
await fill(this.incoming, ext, signal);
|
|
5406
|
-
const
|
|
5407
|
-
if (short === 126) return
|
|
5408
|
-
const long =
|
|
5625
|
+
const view2 = new DataView(ext.buffer);
|
|
5626
|
+
if (short === 126) return view2.getUint16(0);
|
|
5627
|
+
const long = view2.getBigUint64(0);
|
|
5409
5628
|
return long > BigInt(this.max) ? this.max + 1 : Number(long);
|
|
5410
5629
|
}
|
|
5411
5630
|
take(opcode, fin, payload) {
|
|
@@ -8944,6 +9163,15 @@ function parseSize(text) {
|
|
|
8944
9163
|
if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
|
|
8945
9164
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
8946
9165
|
}
|
|
9166
|
+
function linkedTo(mount, path) {
|
|
9167
|
+
const own = mount.attrs.get(path)?.value;
|
|
9168
|
+
const ino = own?.kind === "directory" ? void 0 : own?.ino;
|
|
9169
|
+
return (attr2) => {
|
|
9170
|
+
if (!attr2 || attr2.kind === "directory") return false;
|
|
9171
|
+
if (ino !== void 0) return attr2.ino === ino;
|
|
9172
|
+
return own?.kind !== "directory" && (attr2.nlink ?? 1) > 1;
|
|
9173
|
+
};
|
|
9174
|
+
}
|
|
8947
9175
|
var within6 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
8948
9176
|
var HeldSet = class extends Set {
|
|
8949
9177
|
idle;
|
|
@@ -9385,10 +9613,13 @@ var MountTable = class {
|
|
|
9385
9613
|
}
|
|
9386
9614
|
forget(mount, path) {
|
|
9387
9615
|
mount.epoch++;
|
|
9388
|
-
|
|
9616
|
+
const linked2 = mount.caps.links ? linkedTo(mount, path) : () => false;
|
|
9617
|
+
for (const [key, cached] of [...mount.attrs])
|
|
9618
|
+
if (within6(key, path) || linked2(cached.value)) mount.attrs.delete(key);
|
|
9389
9619
|
mount.lists.delete(path);
|
|
9390
9620
|
mount.lists.delete(parentOf7(path));
|
|
9391
|
-
for (const key of [...mount.lists
|
|
9621
|
+
for (const [key, cached] of [...mount.lists])
|
|
9622
|
+
if (within6(key, path) || cached.value.some((e) => linked2(e.attr))) mount.lists.delete(key);
|
|
9392
9623
|
}
|
|
9393
9624
|
async getattr(mount, path, rel2, settled = false) {
|
|
9394
9625
|
for (let round = 1; ; round++) {
|
|
@@ -9437,12 +9668,64 @@ function noteExtent(extents, from, to) {
|
|
|
9437
9668
|
last[1] = Math.max(last[1], to);
|
|
9438
9669
|
} else extents.push([from, to]);
|
|
9439
9670
|
}
|
|
9440
|
-
var
|
|
9671
|
+
var RELINKED = [
|
|
9672
|
+
["readFileBuffer", [0]],
|
|
9673
|
+
["writeFile", [0]],
|
|
9674
|
+
["pread", [0]],
|
|
9675
|
+
["pwrite", [0]],
|
|
9676
|
+
["truncate", [0]],
|
|
9677
|
+
["lstat", [0]],
|
|
9678
|
+
["stat", [0]],
|
|
9679
|
+
["readdir", [0]],
|
|
9680
|
+
["readdirStat", [0]],
|
|
9681
|
+
["mkdir", [0]],
|
|
9682
|
+
["rm", [0]],
|
|
9683
|
+
["rename", [0, 1]],
|
|
9684
|
+
["symlink", [1]],
|
|
9685
|
+
["readlink", [0]],
|
|
9686
|
+
["chown", [0]],
|
|
9687
|
+
["chmod", [0]],
|
|
9688
|
+
["utimes", [0]],
|
|
9689
|
+
["lutimes", [0]]
|
|
9690
|
+
];
|
|
9691
|
+
var MountFs = class _MountFs {
|
|
9441
9692
|
table;
|
|
9442
9693
|
base;
|
|
9443
|
-
|
|
9694
|
+
rejectLinks;
|
|
9695
|
+
constructor(table, base, rejectLinks = false) {
|
|
9444
9696
|
this.table = table;
|
|
9445
9697
|
this.base = base;
|
|
9698
|
+
this.rejectLinks = rejectLinks;
|
|
9699
|
+
}
|
|
9700
|
+
static {
|
|
9701
|
+
const proto = _MountFs.prototype;
|
|
9702
|
+
for (const [name2, at] of RELINKED) {
|
|
9703
|
+
const run2 = proto[name2];
|
|
9704
|
+
proto[name2] = async function(...args) {
|
|
9705
|
+
try {
|
|
9706
|
+
return await run2.apply(this, args);
|
|
9707
|
+
} catch (err) {
|
|
9708
|
+
const moved2 = await this.relinked(err, args, at);
|
|
9709
|
+
if (!moved2) throw err;
|
|
9710
|
+
return this[name2](...moved2);
|
|
9711
|
+
}
|
|
9712
|
+
};
|
|
9713
|
+
}
|
|
9714
|
+
}
|
|
9715
|
+
async relinked(err, args, at) {
|
|
9716
|
+
if (err?.code !== "ENOTDIR") return void 0;
|
|
9717
|
+
const moved2 = [...args];
|
|
9718
|
+
let changed = false;
|
|
9719
|
+
for (const i of at) {
|
|
9720
|
+
const path = args[i];
|
|
9721
|
+
if (typeof path !== "string" || !this.at(path)) continue;
|
|
9722
|
+
const named = await this.named(path).catch(() => void 0);
|
|
9723
|
+
if (named === void 0 || named === normalizePath(path)) continue;
|
|
9724
|
+
if (this.rejectLinks) throw errnoError("ELOOP", path);
|
|
9725
|
+
moved2[i] = named;
|
|
9726
|
+
changed = true;
|
|
9727
|
+
}
|
|
9728
|
+
return changed ? moved2 : void 0;
|
|
9446
9729
|
}
|
|
9447
9730
|
at(path) {
|
|
9448
9731
|
return this.table.locate(normalizePath(path));
|
|
@@ -9493,6 +9776,7 @@ var MountFs = class {
|
|
|
9493
9776
|
throw err;
|
|
9494
9777
|
}
|
|
9495
9778
|
if (attr2.kind !== "symlink") return real;
|
|
9779
|
+
if (this.rejectLinks) throw errnoError("ELOOP", path);
|
|
9496
9780
|
if (hops >= MAX_LINKS7) throw errnoError("ELOOP", path);
|
|
9497
9781
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
9498
9782
|
return this.follow(this.base.resolvePath(parentOf7(real), target), hops + 1, create);
|
|
@@ -9897,6 +10181,7 @@ var MountFs = class {
|
|
|
9897
10181
|
}
|
|
9898
10182
|
const { mount, rel: rel2 } = found;
|
|
9899
10183
|
const real = normalizePath(path);
|
|
10184
|
+
if (options.file && rel2 === "/") throw errnoError("EISDIR", real);
|
|
9900
10185
|
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
9901
10186
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
9902
10187
|
this.writable(mount, real);
|
|
@@ -10132,8 +10417,22 @@ var MountFs = class {
|
|
|
10132
10417
|
this.table.forget(found.mount, real);
|
|
10133
10418
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mtime: mtime.getTime() });
|
|
10134
10419
|
}
|
|
10420
|
+
noLinks() {
|
|
10421
|
+
const noLinkBase = this.base.noLinks.call(this.base);
|
|
10422
|
+
return view(this, { rejectLinks: true, base: noLinkBase });
|
|
10423
|
+
}
|
|
10135
10424
|
};
|
|
10136
10425
|
|
|
10426
|
+
// src/fs/dev-removal.ts
|
|
10427
|
+
function inDevTree(path) {
|
|
10428
|
+
return path === "/dev" || path.startsWith("/dev/");
|
|
10429
|
+
}
|
|
10430
|
+
function devRemoval(path, cred) {
|
|
10431
|
+
if (!inDevTree(path)) return void 0;
|
|
10432
|
+
if (cred && cred.euid !== 0) return "EACCES";
|
|
10433
|
+
return path === "/dev" ? "EBUSY" : "EPERM";
|
|
10434
|
+
}
|
|
10435
|
+
|
|
10137
10436
|
// src/realm/sync-fs-token-registry.ts
|
|
10138
10437
|
var registry = /* @__PURE__ */ new Map();
|
|
10139
10438
|
function mintSyncFsToken(entry) {
|
|
@@ -10231,6 +10530,7 @@ async function storageUsage() {
|
|
|
10231
10530
|
if (typeof estimate?.quota !== "number") return null;
|
|
10232
10531
|
return { quota: estimate.quota, usage: estimate.usage ?? 0 };
|
|
10233
10532
|
}
|
|
10533
|
+
var PLAIN_DIR_MODE = 493;
|
|
10234
10534
|
var done = { ok: true, kind: "void" };
|
|
10235
10535
|
function json2(value) {
|
|
10236
10536
|
return { ok: true, kind: "json", json: value };
|
|
@@ -10240,6 +10540,27 @@ function ownerFor2(entry, mode) {
|
|
|
10240
10540
|
if (!cred) return void 0;
|
|
10241
10541
|
return ownerOf(cred, mode === void 0 ? void 0 : mode & ~(entry.umask?.() ?? 18));
|
|
10242
10542
|
}
|
|
10543
|
+
function plainDirMode(entry, mode) {
|
|
10544
|
+
if (entry.cred || mode === void 0) return void 0;
|
|
10545
|
+
const wanted = mode & 4095 & ~(entry.umask?.() ?? 18);
|
|
10546
|
+
return wanted === PLAIN_DIR_MODE ? void 0 : wanted;
|
|
10547
|
+
}
|
|
10548
|
+
function plainParentsMode(entry) {
|
|
10549
|
+
if (entry.cred) return void 0;
|
|
10550
|
+
const wanted = 511 & ~(entry.umask?.() ?? 18) | 192;
|
|
10551
|
+
return wanted === PLAIN_DIR_MODE ? void 0 : wanted;
|
|
10552
|
+
}
|
|
10553
|
+
async function missingParents(fs, path, mode) {
|
|
10554
|
+
const parts2 = path.split("/").filter(Boolean);
|
|
10555
|
+
const dirs = [];
|
|
10556
|
+
for (let i = 1; i < parts2.length; i++) {
|
|
10557
|
+
const p = `/${parts2.slice(0, i).join("/")}`;
|
|
10558
|
+
if (!await fs.exists(p)) dirs.push(p);
|
|
10559
|
+
}
|
|
10560
|
+
return async () => {
|
|
10561
|
+
for (const p of dirs) await fs.chmod(p, mode);
|
|
10562
|
+
};
|
|
10563
|
+
}
|
|
10243
10564
|
function mkdirOptions(entry, mode = 511) {
|
|
10244
10565
|
const owner = ownerFor2(entry, mode);
|
|
10245
10566
|
if (!owner) return { recursive: true };
|
|
@@ -10251,23 +10572,39 @@ async function mkdirExclusive(entry, path, mode) {
|
|
|
10251
10572
|
await entry.fs.mkdir(path, owner ? { owner } : {});
|
|
10252
10573
|
}
|
|
10253
10574
|
async function chown(entry, path, req) {
|
|
10575
|
+
const real = req.handle !== void 0 ? await keptOr(entry, path, req.handle) : path;
|
|
10254
10576
|
const cred = entry.cred?.();
|
|
10255
10577
|
if (!cred) {
|
|
10256
|
-
await (req.op === "chown" ? entry.fs.stat(
|
|
10578
|
+
await (req.op === "chown" ? entry.fs.stat(real) : entry.fs.lstat(real));
|
|
10257
10579
|
return done;
|
|
10258
10580
|
}
|
|
10259
|
-
await chownAs(entry.fs, cred,
|
|
10581
|
+
await chownAs(entry.fs, cred, real, {
|
|
10260
10582
|
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
10261
10583
|
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
10262
10584
|
follow: req.op === "chown"
|
|
10263
10585
|
});
|
|
10264
10586
|
return done;
|
|
10265
10587
|
}
|
|
10588
|
+
async function runMkdir(entry, path, req) {
|
|
10589
|
+
const { fs } = entry;
|
|
10590
|
+
const plain = plainDirMode(entry, req.mode);
|
|
10591
|
+
const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
|
|
10592
|
+
const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
|
|
10593
|
+
const fresh2 = plain !== void 0 && !await fs.exists(path);
|
|
10594
|
+
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
10595
|
+
await fixParents?.();
|
|
10596
|
+
if (fresh2) await fs.chmod(path, plain);
|
|
10597
|
+
return done;
|
|
10598
|
+
}
|
|
10599
|
+
function readSource(entry, path) {
|
|
10600
|
+
const plain = () => entry.fs.readFileBuffer(path);
|
|
10601
|
+
return entry.source ? entry.source.read(path, plain) : plain();
|
|
10602
|
+
}
|
|
10266
10603
|
async function run(entry, path, req) {
|
|
10267
10604
|
const { fs, cwd } = entry;
|
|
10268
10605
|
switch (req.op) {
|
|
10269
10606
|
case "read":
|
|
10270
|
-
return { ok: true, kind: "bytes", bytes: await
|
|
10607
|
+
return { ok: true, kind: "bytes", bytes: await readSource(entry, path) };
|
|
10271
10608
|
case "write":
|
|
10272
10609
|
await fs.writeFile(path, req.body ?? new Uint8Array(0), ownerFor2(entry, 438));
|
|
10273
10610
|
return done;
|
|
@@ -10282,8 +10619,7 @@ async function run(entry, path, req) {
|
|
|
10282
10619
|
case "readdir-stat":
|
|
10283
10620
|
return json2(await readdirStat(fs, path));
|
|
10284
10621
|
case "mkdir":
|
|
10285
|
-
|
|
10286
|
-
return done;
|
|
10622
|
+
return runMkdir(entry, path, req);
|
|
10287
10623
|
case "rm":
|
|
10288
10624
|
await fs.rm(path, { recursive: true });
|
|
10289
10625
|
return done;
|
|
@@ -10309,7 +10645,7 @@ async function run(entry, path, req) {
|
|
|
10309
10645
|
return done;
|
|
10310
10646
|
case "create":
|
|
10311
10647
|
await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
|
|
10312
|
-
entry.created?.add(path);
|
|
10648
|
+
if (req.opening) entry.created?.add(path);
|
|
10313
10649
|
entry.fresh?.(path);
|
|
10314
10650
|
return done;
|
|
10315
10651
|
case "readlink":
|
|
@@ -10320,10 +10656,10 @@ async function run(entry, path, req) {
|
|
|
10320
10656
|
return done;
|
|
10321
10657
|
}
|
|
10322
10658
|
case "utimes":
|
|
10323
|
-
await fs.utimes(path,
|
|
10659
|
+
await fs.utimes(path, ...await timesOf(entry, path, req));
|
|
10324
10660
|
return done;
|
|
10325
10661
|
case "lutimes":
|
|
10326
|
-
await lutimesOf(fs, path,
|
|
10662
|
+
await lutimesOf(fs, path, ...await timesOf(entry, path, req));
|
|
10327
10663
|
return done;
|
|
10328
10664
|
case "chown":
|
|
10329
10665
|
case "lchown":
|
|
@@ -10336,6 +10672,17 @@ async function run(entry, path, req) {
|
|
|
10336
10672
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
10337
10673
|
}
|
|
10338
10674
|
}
|
|
10675
|
+
async function timesOf(entry, path, req) {
|
|
10676
|
+
const given = [new Date(req.atimeMs ?? 0), new Date(req.mtimeMs ?? 0)];
|
|
10677
|
+
const g = req.now === true ? guardOf(entry) : void 0;
|
|
10678
|
+
if (!g || g.cred.euid === 0) return given;
|
|
10679
|
+
const look = req.op === "lutimes" ? entry.fs.lstat : entry.fs.stat;
|
|
10680
|
+
const st = await look.call(entry.fs, path).catch(() => void 0);
|
|
10681
|
+
if (!st || (st.uid ?? 0) === g.cred.euid) return given;
|
|
10682
|
+
const now = /* @__PURE__ */ new Date();
|
|
10683
|
+
const kept = (ms, stored) => ms === stored.getTime() ? stored : now;
|
|
10684
|
+
return [kept(req.atimeMs, st.atime), kept(req.mtimeMs, st.mtime)];
|
|
10685
|
+
}
|
|
10339
10686
|
function guardOf(entry) {
|
|
10340
10687
|
const cred = entry.dac && entry.cred?.();
|
|
10341
10688
|
if (!cred || !entry.dac) return void 0;
|
|
@@ -10345,41 +10692,82 @@ function guardOf(entry) {
|
|
|
10345
10692
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
10346
10693
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
10347
10694
|
var NOT_FOLLOWING = /* @__PURE__ */ new Set(["lstat", "readlink", "lchown"]);
|
|
10695
|
+
async function walkSafe(g, path, follow2) {
|
|
10696
|
+
try {
|
|
10697
|
+
const walked = await walk(g.fs, g.cred, path, follow2, g.links);
|
|
10698
|
+
return walked.path;
|
|
10699
|
+
} catch {
|
|
10700
|
+
return path;
|
|
10701
|
+
}
|
|
10702
|
+
}
|
|
10348
10703
|
async function guard(g, path, req, cwd) {
|
|
10349
10704
|
const { op } = req;
|
|
10350
|
-
if (FOLLOWING.has(op) || NOT_FOLLOWING.has(op))
|
|
10705
|
+
if (FOLLOWING.has(op) || NOT_FOLLOWING.has(op)) {
|
|
10706
|
+
const walked = await need(g, op, path, 0, { follow: FOLLOWING.has(op) });
|
|
10707
|
+
return { path: walked.path };
|
|
10708
|
+
}
|
|
10351
10709
|
const other = () => g.fs.resolvePath(cwd, req.arg2 ?? "");
|
|
10352
10710
|
switch (op) {
|
|
10353
10711
|
case "readdir":
|
|
10354
|
-
case "readdir-stat":
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
return
|
|
10712
|
+
case "readdir-stat": {
|
|
10713
|
+
await listable(g, op, path);
|
|
10714
|
+
const w = await walkSafe(g, path, true);
|
|
10715
|
+
return { path: w };
|
|
10716
|
+
}
|
|
10717
|
+
case "mkdir": {
|
|
10718
|
+
await makeIn(g, op, path);
|
|
10719
|
+
return { path: await walkSafe(g, path, false) };
|
|
10720
|
+
}
|
|
10358
10721
|
case "create":
|
|
10359
10722
|
case "symlink":
|
|
10360
|
-
|
|
10723
|
+
await inParent(g, op, path);
|
|
10724
|
+
return { path: await walkSafe(g, path, op === "create") };
|
|
10361
10725
|
case "unlink":
|
|
10362
|
-
case "rmdir":
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
return
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10726
|
+
case "rmdir": {
|
|
10727
|
+
await inParent(g, op, path, true);
|
|
10728
|
+
const w = await walkSafe(g, path, false);
|
|
10729
|
+
return { path: w };
|
|
10730
|
+
}
|
|
10731
|
+
case "rm": {
|
|
10732
|
+
await removable(g, op, path);
|
|
10733
|
+
const w = await walkSafe(g, path, false);
|
|
10734
|
+
return { path: w };
|
|
10735
|
+
}
|
|
10736
|
+
case "rename": {
|
|
10737
|
+
const to = other();
|
|
10738
|
+
await renamable(g, path, to);
|
|
10739
|
+
const fromWalked = await walkSafe(g, path, false);
|
|
10740
|
+
const toWalked = await walkSafe(g, to, false);
|
|
10741
|
+
return { path: fromWalked, arg2: toWalked };
|
|
10742
|
+
}
|
|
10743
|
+
case "link": {
|
|
10744
|
+
const to = other();
|
|
10745
|
+
const follow2 = req.mode === 1;
|
|
10746
|
+
await linkable(g, path, to, follow2);
|
|
10747
|
+
const fromWalked = await walkSafe(g, path, follow2);
|
|
10748
|
+
const toWalked = await walkSafe(g, to, false);
|
|
10749
|
+
return { path: fromWalked, arg2: toWalked };
|
|
10750
|
+
}
|
|
10370
10751
|
case "utimes":
|
|
10371
|
-
case "lutimes":
|
|
10372
|
-
|
|
10752
|
+
case "lutimes": {
|
|
10753
|
+
await retimable(g, op, path, req.now === true);
|
|
10754
|
+
const follow2 = op === "utimes";
|
|
10755
|
+
const w = await walkSafe(g, path, follow2);
|
|
10756
|
+
return { path: w };
|
|
10757
|
+
}
|
|
10373
10758
|
case "read":
|
|
10374
10759
|
case "pread":
|
|
10375
|
-
|
|
10760
|
+
if (req.handle === void 0) await readable(g, op, path);
|
|
10761
|
+
return { path: await walkSafe(g, path, true) };
|
|
10376
10762
|
case "pwrite":
|
|
10377
10763
|
case "truncate":
|
|
10378
|
-
|
|
10764
|
+
if (req.handle === void 0) await fileWritable(g, op, path);
|
|
10765
|
+
return { path: await walkSafe(g, path, true) };
|
|
10379
10766
|
case "write":
|
|
10380
|
-
|
|
10767
|
+
if (req.handle === void 0 && req.mode !== 1) await writable(g, op, path);
|
|
10768
|
+
return { path: await walkSafe(g, path, true) };
|
|
10381
10769
|
default:
|
|
10382
|
-
return
|
|
10770
|
+
return { path: await walkSafe(g, path, true) };
|
|
10383
10771
|
}
|
|
10384
10772
|
}
|
|
10385
10773
|
async function opening(entry, path, mode) {
|
|
@@ -10396,6 +10784,7 @@ async function holdOp(entry, path, req) {
|
|
|
10396
10784
|
if (on && open) {
|
|
10397
10785
|
await opening(entry, path, mode);
|
|
10398
10786
|
const real = await entry.fs.realpath?.(path, true).catch(() => path);
|
|
10787
|
+
await entry.source?.open(path, real);
|
|
10399
10788
|
return json2(entry.hold?.(path, on, open, real) ?? null);
|
|
10400
10789
|
}
|
|
10401
10790
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
@@ -10448,15 +10837,16 @@ async function mayChange(entry, path, req) {
|
|
|
10448
10837
|
}
|
|
10449
10838
|
async function guarded(entry, path, req) {
|
|
10450
10839
|
const g = guardOf(entry);
|
|
10451
|
-
if (!g) return
|
|
10452
|
-
if (LOOKS.has(req.op) && await entry.holdsKept?.(path)) return
|
|
10840
|
+
if (!g) return {};
|
|
10841
|
+
if (LOOKS.has(req.op) && await entry.holdsKept?.(path)) return {};
|
|
10453
10842
|
try {
|
|
10454
10843
|
await mayChange(entry, path, req);
|
|
10455
|
-
await guard(g, path, req, entry.cwd);
|
|
10456
|
-
return
|
|
10844
|
+
const paths = await guard(g, path, req, entry.cwd);
|
|
10845
|
+
return { paths };
|
|
10457
10846
|
} catch (err) {
|
|
10458
10847
|
const refusal = err.code === "EACCES";
|
|
10459
|
-
|
|
10848
|
+
const refused2 = req.op === "exists" && refusal ? json2(false) : toErrno(err);
|
|
10849
|
+
return { refused: refused2 };
|
|
10460
10850
|
}
|
|
10461
10851
|
}
|
|
10462
10852
|
async function createExclusive(fs, path, owner) {
|
|
@@ -10482,6 +10872,7 @@ async function ranged(fs, path, req) {
|
|
|
10482
10872
|
else await ops.truncate(path, req.length ?? 0);
|
|
10483
10873
|
return done;
|
|
10484
10874
|
}
|
|
10875
|
+
var CHOWN_OPS = /* @__PURE__ */ new Set(["chown", "lchown"]);
|
|
10485
10876
|
var UNLINKED_OPS = /* @__PURE__ */ new Set(["read", "pread", "pwrite", "truncate"]);
|
|
10486
10877
|
var OWN_OPS = /* @__PURE__ */ new Set(["rm", "unlink", "rmdir", "rename", "link"]);
|
|
10487
10878
|
var TWO_PATHS = /* @__PURE__ */ new Set(["rename", "link"]);
|
|
@@ -10546,7 +10937,7 @@ async function rmPermitted(entry, path, req, refused2) {
|
|
|
10546
10937
|
const st = await entry.fs.lstat(path).catch(() => void 0);
|
|
10547
10938
|
if (!st?.isDirectory) return refused2;
|
|
10548
10939
|
const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
|
|
10549
|
-
if (unlisted) return unlisted;
|
|
10940
|
+
if ("refused" in unlisted) return unlisted.refused;
|
|
10550
10941
|
const names = await entry.fs.readdir(path).catch(() => void 0);
|
|
10551
10942
|
if (!names) return refused2;
|
|
10552
10943
|
let first;
|
|
@@ -10558,31 +10949,64 @@ async function rmPermitted(entry, path, req, refused2) {
|
|
|
10558
10949
|
if (!child.ok) first ??= child;
|
|
10559
10950
|
}
|
|
10560
10951
|
if (first) return first;
|
|
10561
|
-
const
|
|
10562
|
-
|
|
10952
|
+
const g = guardOf(entry);
|
|
10953
|
+
if (g) {
|
|
10954
|
+
try {
|
|
10955
|
+
await inParent(g, "rm", path, true);
|
|
10956
|
+
} catch (err) {
|
|
10957
|
+
return toErrno(err);
|
|
10958
|
+
}
|
|
10959
|
+
}
|
|
10960
|
+
return await run(entry, path, req);
|
|
10961
|
+
}
|
|
10962
|
+
async function byHandle(entry, path, req) {
|
|
10963
|
+
if (req.op === "kept") return json2(entry.keptFor?.(req.handle ?? -1) !== void 0);
|
|
10964
|
+
if (req.op === "stat" && req.handle !== void 0) return keptStat(entry, req);
|
|
10965
|
+
if (CHOWN_OPS.has(req.op) && entry.keptFor?.(req.handle ?? -1)) return chown(entry, path, req);
|
|
10966
|
+
return void 0;
|
|
10563
10967
|
}
|
|
10968
|
+
async function guardAndResolve(entry, path, req) {
|
|
10969
|
+
const result = await guarded(entry, path, req);
|
|
10970
|
+
if ("refused" in result) return result.refused;
|
|
10971
|
+
const { noLinks } = entry;
|
|
10972
|
+
const { paths } = result;
|
|
10973
|
+
if (entry.links === void 0 || !noLinks || !paths) return { path, entry };
|
|
10974
|
+
return {
|
|
10975
|
+
path: paths.path,
|
|
10976
|
+
...paths.arg2 ? { arg2: paths.arg2 } : {},
|
|
10977
|
+
entry: { ...entry, fs: noLinks }
|
|
10978
|
+
};
|
|
10979
|
+
}
|
|
10980
|
+
var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
|
|
10564
10981
|
async function dispatchOne(entry, req) {
|
|
10565
10982
|
const { fs, cwd } = entry;
|
|
10566
10983
|
try {
|
|
10567
10984
|
const path = fs.resolvePath(cwd, req.path);
|
|
10568
|
-
|
|
10569
|
-
if (
|
|
10985
|
+
const device = REMOVALS.has(req.op) ? devRemoval(path, entry.cred?.()) : void 0;
|
|
10986
|
+
if (device) return { ok: false, errno: device, message: `${path}: a device entry stays` };
|
|
10987
|
+
const held = await byHandle(entry, path, req);
|
|
10988
|
+
if (held) return held;
|
|
10570
10989
|
if (req.op === "access") return await accessOp(entry, path, req);
|
|
10571
10990
|
if (req.op === "hold") return await holdOp(entry, path, req);
|
|
10572
|
-
const
|
|
10573
|
-
if (
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10991
|
+
const resolved2 = await guardAndResolve(entry, path, req);
|
|
10992
|
+
if (!("entry" in resolved2)) {
|
|
10993
|
+
if (req.op === "rm" && !resolved2.ok && DENIED.has(resolved2.errno))
|
|
10994
|
+
return await rmPermitted(entry, path, req, resolved2);
|
|
10995
|
+
return resolved2;
|
|
10996
|
+
}
|
|
10997
|
+
const { path: resolvedPath, arg2: resolvedArg2, entry: opEntry } = resolved2;
|
|
10998
|
+
const opReq = resolvedArg2 ? { ...req, arg2: resolvedArg2 } : req;
|
|
10999
|
+
if (req.op === "statfs")
|
|
11000
|
+
return json2(await usageAt(entry, resolvedPath) ?? await storageUsage());
|
|
11001
|
+
if (entry.revoked?.(resolvedPath))
|
|
11002
|
+
return { ok: false, errno: "EIO", message: `${resolvedPath} was unmounted` };
|
|
10579
11003
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
10580
|
-
const serve = async () => run(
|
|
10581
|
-
return await (entry.gate ? entry.gate(
|
|
11004
|
+
const serve = async () => run(opEntry, await keptOr(opEntry, resolvedPath, req.handle), opReq);
|
|
11005
|
+
return await (entry.gate ? entry.gate(resolvedPath, serve) : serve());
|
|
10582
11006
|
}
|
|
10583
|
-
if (!entry.own || !OWN_OPS.has(req.op)) return await run(
|
|
10584
|
-
const target = TWO_PATHS.has(req.op) ? fs.resolvePath(cwd, req.arg2 ?? "") :
|
|
10585
|
-
return await owned2(
|
|
11007
|
+
if (!entry.own || !OWN_OPS.has(req.op)) return await run(opEntry, resolvedPath, opReq);
|
|
11008
|
+
const target = resolvedArg2 ?? (TWO_PATHS.has(req.op) ? fs.resolvePath(cwd, req.arg2 ?? "") : resolvedPath);
|
|
11009
|
+
return await owned2(opEntry, entry.own, opReq, resolvedPath, target);
|
|
10586
11010
|
} catch (err) {
|
|
10587
11011
|
return toErrno(err);
|
|
10588
11012
|
}
|
|
@@ -10610,6 +11034,15 @@ var SAB_I_KILLED = 13;
|
|
|
10610
11034
|
var SAB_I_ASYNC = 14;
|
|
10611
11035
|
var SAB_I_STOP = 15;
|
|
10612
11036
|
var SAB_I_BLOCKED = 16;
|
|
11037
|
+
var SAB_I_BLOCKED_HI = 17;
|
|
11038
|
+
function loadBlocked(header3) {
|
|
11039
|
+
return [Atomics.load(header3, SAB_I_BLOCKED), Atomics.load(header3, SAB_I_BLOCKED_HI)];
|
|
11040
|
+
}
|
|
11041
|
+
function storeBlocked(header3, [low, high]) {
|
|
11042
|
+
Atomics.store(header3, SAB_I_BLOCKED_HI, high);
|
|
11043
|
+
Atomics.store(header3, SAB_I_BLOCKED, low);
|
|
11044
|
+
}
|
|
11045
|
+
var anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
|
|
10613
11046
|
var U32 = 2 ** 32;
|
|
10614
11047
|
function storeU53(header3, lo, hi, value) {
|
|
10615
11048
|
Atomics.store(header3, hi, Math.floor(value / U32));
|
|
@@ -11136,7 +11569,7 @@ function mountTable(mounts = []) {
|
|
|
11136
11569
|
}
|
|
11137
11570
|
|
|
11138
11571
|
// src/version.ts
|
|
11139
|
-
var KERNEL_VERSION = true ? "1.
|
|
11572
|
+
var KERNEL_VERSION = true ? "1.93.0" : "0.0.0-dev";
|
|
11140
11573
|
var OS_RELEASE = "6.0.0-slicc";
|
|
11141
11574
|
function procVersion() {
|
|
11142
11575
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11836,21 +12269,28 @@ function bodyOf(incoming, head, method, signal) {
|
|
|
11836
12269
|
var KernelLoopback = class {
|
|
11837
12270
|
net;
|
|
11838
12271
|
cred;
|
|
11839
|
-
|
|
12272
|
+
stamp;
|
|
12273
|
+
constructor(net, cred, stamp) {
|
|
11840
12274
|
this.net = net;
|
|
11841
12275
|
this.cred = cred;
|
|
12276
|
+
this.stamp = stamp;
|
|
11842
12277
|
}
|
|
11843
12278
|
port(url) {
|
|
11844
12279
|
return kernelLoopbackPort(url);
|
|
11845
12280
|
}
|
|
11846
|
-
connect(url, port, signal) {
|
|
12281
|
+
async connect(url, port, signal) {
|
|
11847
12282
|
if (url.protocol === "https:" || url.protocol === "wss:") {
|
|
11848
12283
|
throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
|
|
11849
12284
|
}
|
|
11850
12285
|
signal.throwIfAborted();
|
|
11851
12286
|
const socket = this.net.socket("inet");
|
|
11852
12287
|
try {
|
|
11853
|
-
void socket.connect(
|
|
12288
|
+
void socket.connect(
|
|
12289
|
+
{ family: "inet", host: "127.0.0.1", port },
|
|
12290
|
+
false,
|
|
12291
|
+
this.cred(),
|
|
12292
|
+
this.stamp ? await this.stamp() : void 0
|
|
12293
|
+
);
|
|
11854
12294
|
} catch (err) {
|
|
11855
12295
|
socket.close();
|
|
11856
12296
|
const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
@@ -11864,7 +12304,7 @@ var KernelLoopback = class {
|
|
|
11864
12304
|
const body = req.body ?? (/^(POST|PUT|PATCH)$/i.test(req.method) ? new Uint8Array(0) : void 0);
|
|
11865
12305
|
const length2 = body ? [["Content-Length", String(body.length)]] : [];
|
|
11866
12306
|
const head = requestHead(req.method, url, req.headers, [...length2, ["Connection", "close"]]);
|
|
11867
|
-
const socket = this.connect(url, port, req.signal);
|
|
12307
|
+
const socket = await this.connect(url, port, req.signal);
|
|
11868
12308
|
try {
|
|
11869
12309
|
await writeAll2(socket, body ? concat([head, body]) : head, req.signal);
|
|
11870
12310
|
const incoming = new Incoming(socket);
|
|
@@ -11885,7 +12325,7 @@ var KernelLoopback = class {
|
|
|
11885
12325
|
}
|
|
11886
12326
|
async websocket(req, port) {
|
|
11887
12327
|
const url = new URL(req.url);
|
|
11888
|
-
const socket = this.connect(url, port, req.signal);
|
|
12328
|
+
const socket = await this.connect(url, port, req.signal);
|
|
11889
12329
|
try {
|
|
11890
12330
|
const key = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))));
|
|
11891
12331
|
const extra = [
|
|
@@ -11910,6 +12350,9 @@ var KernelLoopback = class {
|
|
|
11910
12350
|
if (!upgraded || accept2 !== await acceptFor(key)) {
|
|
11911
12351
|
throw errno("EPROTO", "the server did not accept the WebSocket key");
|
|
11912
12352
|
}
|
|
12353
|
+
if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
|
|
12354
|
+
throw errno("EPROTO", "the server offered an unsolicited extension");
|
|
12355
|
+
}
|
|
11913
12356
|
const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
|
|
11914
12357
|
return new LoopbackWebSocket(socket, incoming, protocol);
|
|
11915
12358
|
} catch (err) {
|
|
@@ -12009,7 +12452,7 @@ var LoopbackWebSocket = class {
|
|
|
12009
12452
|
})();
|
|
12010
12453
|
}
|
|
12011
12454
|
async pump(reader, deliver) {
|
|
12012
|
-
let close = { code: 1006, reason: "" };
|
|
12455
|
+
let close = { code: 1006, reason: "", wasClean: false };
|
|
12013
12456
|
try {
|
|
12014
12457
|
for (; ; ) {
|
|
12015
12458
|
await this.space();
|
|
@@ -12019,14 +12462,14 @@ var LoopbackWebSocket = class {
|
|
|
12019
12462
|
else if (event.kind === "binary") deliver(event.bytes);
|
|
12020
12463
|
else if (event.kind === "ping") this.write(clientFrame(OP_PONG, event.payload));
|
|
12021
12464
|
else {
|
|
12022
|
-
close = { code: event.code, reason: event.reason };
|
|
12465
|
+
close = { code: event.code, reason: event.reason, wasClean: true };
|
|
12023
12466
|
if (!this.sentClose) this.sendClose(event.code === 1005 ? 1e3 : event.code, "");
|
|
12024
12467
|
break;
|
|
12025
12468
|
}
|
|
12026
12469
|
}
|
|
12027
12470
|
} catch (err) {
|
|
12028
12471
|
if (err instanceof WsError) this.sendClose(err.code, err.message);
|
|
12029
|
-
close = { code:
|
|
12472
|
+
close = { code: 1006, reason: "", wasClean: false };
|
|
12030
12473
|
} finally {
|
|
12031
12474
|
const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
|
|
12032
12475
|
await this.writes;
|
|
@@ -12152,14 +12595,22 @@ var WsHandles = class {
|
|
|
12152
12595
|
return typeof next2.value === "string" ? { ok: true, kind: "json", json: { text: next2.value } } : { ok: true, kind: "bytes", bytes: next2.value };
|
|
12153
12596
|
}
|
|
12154
12597
|
const closed = await socket.closed;
|
|
12155
|
-
return {
|
|
12598
|
+
return {
|
|
12599
|
+
ok: true,
|
|
12600
|
+
kind: "json",
|
|
12601
|
+
json: { code: closed.code, reason: closed.reason, wasClean: closed.wasClean === true }
|
|
12602
|
+
};
|
|
12156
12603
|
} catch (e) {
|
|
12157
12604
|
return fail("ECONNRESET", message(e));
|
|
12158
12605
|
}
|
|
12159
12606
|
}
|
|
12160
12607
|
async closed(socket) {
|
|
12161
|
-
const
|
|
12162
|
-
return {
|
|
12608
|
+
const closed = await socket.closed;
|
|
12609
|
+
return {
|
|
12610
|
+
ok: true,
|
|
12611
|
+
kind: "json",
|
|
12612
|
+
json: { code: closed.code, reason: closed.reason, wasClean: closed.wasClean === true }
|
|
12613
|
+
};
|
|
12163
12614
|
}
|
|
12164
12615
|
send(socket, req, entry) {
|
|
12165
12616
|
const data = req.text ?? req.body;
|
|
@@ -12199,7 +12650,7 @@ function message2(e) {
|
|
|
12199
12650
|
}
|
|
12200
12651
|
function codeOf2(e) {
|
|
12201
12652
|
const code = e?.code;
|
|
12202
|
-
return typeof code === "string" && /^E[A-Z]+$/.test(code) ? code : "EIO";
|
|
12653
|
+
return typeof code === "string" && /^E[A-Z]+$|^EAI_[A-Z]+$/.test(code) ? code : "EIO";
|
|
12203
12654
|
}
|
|
12204
12655
|
async function* once(bytes) {
|
|
12205
12656
|
yield bytes;
|
|
@@ -12282,7 +12733,8 @@ var HttpHandles = class {
|
|
|
12282
12733
|
if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
|
|
12283
12734
|
const status = e.status;
|
|
12284
12735
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
12285
|
-
const
|
|
12736
|
+
const code = codeOf2(e);
|
|
12737
|
+
const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
12286
12738
|
return { ok: false, errno: errno2, message: text };
|
|
12287
12739
|
}
|
|
12288
12740
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
@@ -13752,6 +14204,7 @@ function aborted(signal) {
|
|
|
13752
14204
|
signal.addEventListener("abort", () => reject(new KernelError("EINTR")), { once: true });
|
|
13753
14205
|
});
|
|
13754
14206
|
}
|
|
14207
|
+
var PLAIN_FILE_MODE = 420;
|
|
13755
14208
|
var JOB_OPS = /* @__PURE__ */ new Set([
|
|
13756
14209
|
"proc-setpgid",
|
|
13757
14210
|
"proc-getpgid",
|
|
@@ -13774,7 +14227,7 @@ function isPtySyscall(req) {
|
|
|
13774
14227
|
return req.op.startsWith("pty-");
|
|
13775
14228
|
}
|
|
13776
14229
|
function isVfsSyscall(req) {
|
|
13777
|
-
return req.op.startsWith("fd-path-") || req.op === "fd-pread" || req.op === "fd-pwrite" || req.op === "fd-resize" || req.op === "fd-vfs-stat";
|
|
14230
|
+
return req.op.startsWith("fd-path-") || req.op === "fd-pread" || req.op === "fd-pwrite" || req.op === "fd-resize" || req.op === "fd-vfs-stat" || req.op === "fd-chmod" || req.op === "fd-chown" || req.op === "fd-utimes";
|
|
13778
14231
|
}
|
|
13779
14232
|
function isFdSyscall(req) {
|
|
13780
14233
|
return req.op.startsWith("fd-");
|
|
@@ -13794,6 +14247,9 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
13794
14247
|
"fd-pwrite",
|
|
13795
14248
|
"fd-resize",
|
|
13796
14249
|
"fd-vfs-stat",
|
|
14250
|
+
"fd-chmod",
|
|
14251
|
+
"fd-chown",
|
|
14252
|
+
"fd-utimes",
|
|
13797
14253
|
"fd-path-flush",
|
|
13798
14254
|
"fd-path-unlinking",
|
|
13799
14255
|
"fd-path-unlinked",
|
|
@@ -13824,6 +14280,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
13824
14280
|
"fd-tty-owner",
|
|
13825
14281
|
"fd-open-sealed",
|
|
13826
14282
|
"fd-open-clipboard",
|
|
14283
|
+
"fd-clipboard-abort",
|
|
13827
14284
|
"tty-get",
|
|
13828
14285
|
"tty-set",
|
|
13829
14286
|
"tty-winsz",
|
|
@@ -14169,7 +14626,11 @@ var WasmProcess = class {
|
|
|
14169
14626
|
if (!stderr?.write || stderr.clipboard) return;
|
|
14170
14627
|
const line = `${name2}: /dev/clipboard: ${clipboardLine(err.detail)}
|
|
14171
14628
|
`;
|
|
14172
|
-
|
|
14629
|
+
const timeout = new Promise((r) => setTimeout(() => r(0), 1e3));
|
|
14630
|
+
await Promise.race([
|
|
14631
|
+
stderr.write(new TextEncoder().encode(line), AbortSignal.timeout(1e3)).catch(() => 0),
|
|
14632
|
+
timeout
|
|
14633
|
+
]);
|
|
14173
14634
|
}
|
|
14174
14635
|
async write(fd, body, nonblock = false, cancelled) {
|
|
14175
14636
|
const file = this.fds.get(fd).file;
|
|
@@ -14196,30 +14657,39 @@ var WasmProcess = class {
|
|
|
14196
14657
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
14197
14658
|
if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
|
|
14198
14659
|
await this.mayOpen(req);
|
|
14660
|
+
const marked = await this.markedPath(req);
|
|
14661
|
+
await this.sourceOpen(marked === void 0 ? req : { ...req, path: marked });
|
|
14662
|
+
const fs = marked === void 0 ? this.options.fs : this.options.noLinks;
|
|
14199
14663
|
const fd = this.fds.install(heldFile(), 3);
|
|
14200
14664
|
try {
|
|
14201
14665
|
const nodes = this.nodes;
|
|
14202
|
-
const path =
|
|
14666
|
+
const path = await this.openPath(req, marked);
|
|
14203
14667
|
if (inProc(path)) {
|
|
14204
14668
|
this.fds.installAt(fd, await this.procFile(req, path));
|
|
14205
14669
|
return fd;
|
|
14206
14670
|
}
|
|
14207
14671
|
if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
|
|
14208
14672
|
const open = { ...req, path };
|
|
14673
|
+
const plain = this.plainMode(req.mode);
|
|
14209
14674
|
if (req.exclusive) {
|
|
14210
|
-
await nodes.createExclusive(path, this.newOwner());
|
|
14211
|
-
|
|
14675
|
+
await nodes.createExclusive(path, this.newOwner(req.mode));
|
|
14676
|
+
if (plain !== void 0) await fs.chmod?.(path, plain);
|
|
14677
|
+
this.fds.installAt(fd, this.openVfsFile(open, void 0, fs));
|
|
14212
14678
|
} else if (req.create) {
|
|
14213
14679
|
await nodes.onEntry(path, async () => {
|
|
14214
|
-
const
|
|
14215
|
-
|
|
14680
|
+
const marks = this.options.owners || plain !== void 0;
|
|
14681
|
+
const fresh2 = marks && !await present2(fs, path, true);
|
|
14682
|
+
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
14216
14683
|
await this.fds.get(fd).file.stat?.();
|
|
14217
|
-
if (fresh2) await
|
|
14684
|
+
if (fresh2 && plain !== void 0) await fs.chmod?.(path, plain);
|
|
14685
|
+
else if (fresh2) {
|
|
14686
|
+
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
14687
|
+
}
|
|
14218
14688
|
});
|
|
14219
14689
|
} else {
|
|
14220
|
-
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path)));
|
|
14690
|
+
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
14221
14691
|
}
|
|
14222
|
-
if (req.existing && !await present2(
|
|
14692
|
+
if (req.existing && !await present2(fs, path, true)) {
|
|
14223
14693
|
throw new KernelError("ENOENT");
|
|
14224
14694
|
}
|
|
14225
14695
|
} catch (err) {
|
|
@@ -14253,6 +14723,27 @@ var WasmProcess = class {
|
|
|
14253
14723
|
writesAt(req) {
|
|
14254
14724
|
return (req.flags & WRITE_ACCESS) !== 0 || req.truncate === true || req.create === true || req.exclusive === true;
|
|
14255
14725
|
}
|
|
14726
|
+
async sourceOpen(req) {
|
|
14727
|
+
const { source } = this.options;
|
|
14728
|
+
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
14729
|
+
if (!source || inherited2 || req.pin !== void 0 || req.exclusive) return;
|
|
14730
|
+
await source.open(req.path);
|
|
14731
|
+
}
|
|
14732
|
+
async markedPath(req) {
|
|
14733
|
+
const { guard: guard2, noLinks } = this.options;
|
|
14734
|
+
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
14735
|
+
if (guard2?.links === void 0 || !noLinks || inherited2 || req.pin !== void 0)
|
|
14736
|
+
return void 0;
|
|
14737
|
+
return (await walk(guard2.fs, this.cred, req.path, !req.exclusive, guard2.links)).path;
|
|
14738
|
+
}
|
|
14739
|
+
async openPath(req, marked) {
|
|
14740
|
+
const nodes = this.nodes;
|
|
14741
|
+
if (req.orphan) return req.path;
|
|
14742
|
+
if (req.exclusive) return nodes.entryKey(marked ?? req.path);
|
|
14743
|
+
if (marked !== void 0) return marked;
|
|
14744
|
+
if (req.create) return nodes.targetKey(req.path);
|
|
14745
|
+
return this.keptOr(await nodes.targetKey(req.path), req.handle);
|
|
14746
|
+
}
|
|
14256
14747
|
async mayOpen(req) {
|
|
14257
14748
|
const { guard: guard2 } = this.options;
|
|
14258
14749
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
@@ -14327,9 +14818,14 @@ var WasmProcess = class {
|
|
|
14327
14818
|
if (!tty) throw new KernelError("ENOENT");
|
|
14328
14819
|
return tty;
|
|
14329
14820
|
}
|
|
14330
|
-
|
|
14821
|
+
plainMode(mode) {
|
|
14822
|
+
if (this.options.owners || mode === void 0) return void 0;
|
|
14823
|
+
const wanted = mode & 4095 & ~this.umask;
|
|
14824
|
+
return wanted === PLAIN_FILE_MODE ? void 0 : wanted;
|
|
14825
|
+
}
|
|
14826
|
+
newOwner(mode = 438) {
|
|
14331
14827
|
if (!this.options.owners) return void 0;
|
|
14332
|
-
return { uid: this.cred.euid, gid: this.cred.egid, mode:
|
|
14828
|
+
return { uid: this.cred.euid, gid: this.cred.egid, mode: mode & 4095 & ~this.umask };
|
|
14333
14829
|
}
|
|
14334
14830
|
async openProc(req, path) {
|
|
14335
14831
|
return this.fds.install(await this.procFile(req, path), 3);
|
|
@@ -14347,9 +14843,9 @@ var WasmProcess = class {
|
|
|
14347
14843
|
);
|
|
14348
14844
|
return memoryFile(tree2.read(path), path, req.position);
|
|
14349
14845
|
}
|
|
14350
|
-
openVfsFile(req, id2) {
|
|
14846
|
+
openVfsFile(req, id2, fs = this.options.fs) {
|
|
14351
14847
|
return vfsFile(
|
|
14352
|
-
|
|
14848
|
+
fs,
|
|
14353
14849
|
{
|
|
14354
14850
|
path: req.path,
|
|
14355
14851
|
flags: req.flags,
|
|
@@ -14432,7 +14928,7 @@ var WasmProcess = class {
|
|
|
14432
14928
|
return { ok: true, kind: "void" };
|
|
14433
14929
|
case "fd-renumber":
|
|
14434
14930
|
if (req.from !== req.to) {
|
|
14435
|
-
this.fds.
|
|
14931
|
+
await this.fds.dup2Clipboard(req.from, req.to);
|
|
14436
14932
|
if (!req.keep) await Promise.resolve(this.fds.close(req.from));
|
|
14437
14933
|
}
|
|
14438
14934
|
return { ok: true, kind: "void" };
|
|
@@ -14444,6 +14940,11 @@ var WasmProcess = class {
|
|
|
14444
14940
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
14445
14941
|
case "fd-open-clipboard":
|
|
14446
14942
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
14943
|
+
case "fd-clipboard-abort": {
|
|
14944
|
+
const file = this.fds.get(req.fd);
|
|
14945
|
+
file.file.clipboard?.abort();
|
|
14946
|
+
return { ok: true, kind: "void" };
|
|
14947
|
+
}
|
|
14447
14948
|
case "fd-tty-owner":
|
|
14448
14949
|
return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
|
|
14449
14950
|
case "fd-select": {
|
|
@@ -14496,12 +14997,23 @@ var WasmProcess = class {
|
|
|
14496
14997
|
case "fd-resize":
|
|
14497
14998
|
await file.resize(req.size);
|
|
14498
14999
|
return { ok: true, kind: "void" };
|
|
14499
|
-
case "fd-vfs-stat":
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
-
|
|
14504
|
-
|
|
15000
|
+
case "fd-vfs-stat": {
|
|
15001
|
+
if (req.identity) {
|
|
15002
|
+
return {
|
|
15003
|
+
ok: true,
|
|
15004
|
+
kind: "json",
|
|
15005
|
+
json: await this.identified(file.stat.bind(file), file.known?.bind(file))
|
|
15006
|
+
};
|
|
15007
|
+
}
|
|
15008
|
+
const vfs = await file.stat();
|
|
15009
|
+
if (!req.full) return { ok: true, kind: "json", json: vfs };
|
|
15010
|
+
const st = await this.heldStat(vfs).catch(() => void 0);
|
|
15011
|
+
return { ok: true, kind: "json", json: { ...vfs, ...st ? { stat: st } : {} } };
|
|
15012
|
+
}
|
|
15013
|
+
case "fd-chmod":
|
|
15014
|
+
case "fd-chown":
|
|
15015
|
+
case "fd-utimes":
|
|
15016
|
+
return this.fdMetadata(await file.stat(), req);
|
|
14505
15017
|
}
|
|
14506
15018
|
}
|
|
14507
15019
|
keptPath;
|
|
@@ -14522,7 +15034,7 @@ var WasmProcess = class {
|
|
|
14522
15034
|
async promote(req) {
|
|
14523
15035
|
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
14524
15036
|
if (req.share !== void 0) {
|
|
14525
|
-
this.fds.
|
|
15037
|
+
await this.fds.dup2Clipboard(req.share, req.fd);
|
|
14526
15038
|
return;
|
|
14527
15039
|
}
|
|
14528
15040
|
if (req.path === void 0) throw new KernelError("EINVAL");
|
|
@@ -14551,6 +15063,46 @@ var WasmProcess = class {
|
|
|
14551
15063
|
this.fds.installAt(fd, heldFile(meta));
|
|
14552
15064
|
return fd;
|
|
14553
15065
|
}
|
|
15066
|
+
heldPath(vfs) {
|
|
15067
|
+
if (!vfs.path) throw new KernelError("EBADF");
|
|
15068
|
+
if (vfs.orphan) throw new KernelError("EOPNOTSUPP");
|
|
15069
|
+
return vfs.path;
|
|
15070
|
+
}
|
|
15071
|
+
heldFs() {
|
|
15072
|
+
return this.options.guard?.fs ?? this.options.fs;
|
|
15073
|
+
}
|
|
15074
|
+
async heldStat(vfs) {
|
|
15075
|
+
const stat = this.heldFs().stat;
|
|
15076
|
+
if (!stat) throw new KernelError("ENOSYS");
|
|
15077
|
+
return stat.call(this.heldFs(), this.heldPath(vfs));
|
|
15078
|
+
}
|
|
15079
|
+
async fdMetadata(vfs, req) {
|
|
15080
|
+
const path = this.heldPath(vfs);
|
|
15081
|
+
const fs = this.heldFs();
|
|
15082
|
+
const g = this.guarded();
|
|
15083
|
+
if (req.op === "fd-chown") {
|
|
15084
|
+
const ids = {
|
|
15085
|
+
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
15086
|
+
...req.gid !== void 0 ? { gid: req.gid } : {}
|
|
15087
|
+
};
|
|
15088
|
+
if (!this.options.owners || !fs.chown || !fs.stat) await this.heldStat(vfs);
|
|
15089
|
+
else await chownAs(fs, this.cred, path, { ...ids, follow: true });
|
|
15090
|
+
return { ok: true, kind: "void" };
|
|
15091
|
+
}
|
|
15092
|
+
const st = await this.heldStat(vfs);
|
|
15093
|
+
if (req.op === "fd-chmod") {
|
|
15094
|
+
if (!fs.chmod) throw new KernelError("ENOSYS");
|
|
15095
|
+
await fs.chmod(path, g ? heldChmodMode(g, path, st, req.mode) : req.mode);
|
|
15096
|
+
return { ok: true, kind: "void" };
|
|
15097
|
+
}
|
|
15098
|
+
if (!fs.utimes) throw new KernelError("ENOSYS");
|
|
15099
|
+
if (g) heldRetimable(g, path, st, req.now === true);
|
|
15100
|
+
const at = (ms, kept) => ms === null ? kept : req.now ? /* @__PURE__ */ new Date() : new Date(ms);
|
|
15101
|
+
const atime = at(req.atimeMs, st.atime);
|
|
15102
|
+
const mtime = at(req.mtimeMs, st.mtime);
|
|
15103
|
+
await fs.utimes(path, atime, mtime);
|
|
15104
|
+
return { ok: true, kind: "void" };
|
|
15105
|
+
}
|
|
14554
15106
|
fdInfo(fd) {
|
|
14555
15107
|
const file = this.fds.get(fd).file;
|
|
14556
15108
|
const flags2 = this.fds.statusFlags(fd);
|
|
@@ -14769,7 +15321,10 @@ var WasmProcess = class {
|
|
|
14769
15321
|
const { file, argv, env, cwd, cred, caller } = answer.grant;
|
|
14770
15322
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
14771
15323
|
return {
|
|
14772
|
-
pid: await this.children.spawn({ file, argv, env, cwd }, stdio, [], {
|
|
15324
|
+
pid: await this.children.spawn({ file, argv, env, cwd, pgid: 0 }, stdio, [], {
|
|
15325
|
+
cred,
|
|
15326
|
+
caller
|
|
15327
|
+
})
|
|
14773
15328
|
};
|
|
14774
15329
|
}
|
|
14775
15330
|
async mountSyscall(req, cancelled) {
|
|
@@ -15069,11 +15624,13 @@ function inherited(opts) {
|
|
|
15069
15624
|
}
|
|
15070
15625
|
function holdingToken(opts, holds, caller) {
|
|
15071
15626
|
return mintSyncFsToken({
|
|
15072
|
-
...opts.owners ? caller : {},
|
|
15627
|
+
...opts.owners ? caller : { umask: caller.umask },
|
|
15073
15628
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
15074
15629
|
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
15075
15630
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
15631
|
+
...opts.source ? { source: opts.source } : {},
|
|
15076
15632
|
fs: opts.fs,
|
|
15633
|
+
noLinks: opts.noLinks,
|
|
15077
15634
|
cwd: opts.cwd,
|
|
15078
15635
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
15079
15636
|
hold: (path, on, open, real, handle) => holds.hold(path, on, open, real, handle),
|
|
@@ -15099,6 +15656,8 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
15099
15656
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
15100
15657
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
15101
15658
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
15659
|
+
...opts.source ? { source: opts.source } : {},
|
|
15660
|
+
noLinks: opts.noLinks,
|
|
15102
15661
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
15103
15662
|
...opts.identity ? { identity: opts.identity } : {},
|
|
15104
15663
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
@@ -15154,8 +15713,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
15154
15713
|
function spawnWasmProcess(opts) {
|
|
15155
15714
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15156
15715
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
15157
|
-
|
|
15158
|
-
|
|
15716
|
+
const blocked = opts.fork?.wasi?.blocked ?? opts.blocked;
|
|
15717
|
+
if (blocked && anyBlocked(blocked) && opts.program.abi === "wasi") storeBlocked(header3, blocked);
|
|
15159
15718
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
15160
15719
|
const created3 = new Created();
|
|
15161
15720
|
const process = new WasmProcess(
|
|
@@ -15170,7 +15729,7 @@ function spawnWasmProcess(opts) {
|
|
|
15170
15729
|
...opts.program.abi === "js" ? {
|
|
15171
15730
|
exitNow: (code) => exitNow(code),
|
|
15172
15731
|
exitSignal: (sig) => queueMicrotask(() => finish(128 + sig, sig))
|
|
15173
|
-
} : {}
|
|
15732
|
+
} : { exitSignal: (sig) => terminate(128 + sig, sig) }
|
|
15174
15733
|
},
|
|
15175
15734
|
created3
|
|
15176
15735
|
)
|
|
@@ -15256,7 +15815,7 @@ function spawnWasmProcess(opts) {
|
|
|
15256
15815
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15257
15816
|
const tw = opts.createWorker();
|
|
15258
15817
|
const tsignals = threadSignalsOf(tsab);
|
|
15259
|
-
if (thread.blocked)
|
|
15818
|
+
if (thread.blocked) storeBlocked(tsignals.header, thread.blocked);
|
|
15260
15819
|
threadSignals.set(thread.tid, tsignals);
|
|
15261
15820
|
const tdispatch = (req) => dying.serving(
|
|
15262
15821
|
() => isWasmSyscall(req) ? process.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -15284,12 +15843,13 @@ function spawnWasmProcess(opts) {
|
|
|
15284
15843
|
processInit(opts, sab, process.umask, copyCred(process.cred), lane?.lane),
|
|
15285
15844
|
transferOf(opts, lane?.lane)
|
|
15286
15845
|
);
|
|
15287
|
-
const
|
|
15288
|
-
if (process.signal(sig) !== "terminate") return;
|
|
15289
|
-
const code = sig === SIG.KILL ? 137 : 128 + sig;
|
|
15846
|
+
const terminate = (code, sig) => {
|
|
15290
15847
|
if (opts.program.abi !== "wasi" || done4) finish(code, sig);
|
|
15291
15848
|
else dying.start(code, sig, header3, process, () => finish(code, sig));
|
|
15292
15849
|
};
|
|
15850
|
+
const signal = (sig) => {
|
|
15851
|
+
if (process.signal(sig) === "terminate") terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
|
|
15852
|
+
};
|
|
15293
15853
|
const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
|
|
15294
15854
|
return {
|
|
15295
15855
|
pid: opts.pid,
|
|
@@ -15300,7 +15860,7 @@ function spawnWasmProcess(opts) {
|
|
|
15300
15860
|
onState: (listener) => process.onState(listener),
|
|
15301
15861
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
15302
15862
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
15303
|
-
blockedSignals: () => opts.program.abi === "wasi" ?
|
|
15863
|
+
blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header3) : [0, 0],
|
|
15304
15864
|
signalMasks: () => process.signalMasks(),
|
|
15305
15865
|
umask: () => process.umask,
|
|
15306
15866
|
cred: () => copyCred(process.cred),
|
|
@@ -18406,14 +18966,16 @@ var SUDO_COMMAND = {
|
|
|
18406
18966
|
var SUDO_SOURCE = [
|
|
18407
18967
|
"export default async function sudo(ctx) {",
|
|
18408
18968
|
" const say = (fd, text) => ctx.write(fd, text).catch(() => undefined);",
|
|
18969
|
+
' const RELAYED = ["SIGTERM", "SIGHUP", "SIGINT", "SIGQUIT", "SIGUSR1", "SIGUSR2", "SIGALRM"];',
|
|
18970
|
+
" const NUMBER = { SIGTERM: 15, SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGUSR1: 10, SIGUSR2: 12, SIGALRM: 14 };",
|
|
18409
18971
|
" let pid;",
|
|
18410
18972
|
" let held;",
|
|
18411
18973
|
" const relay = (sig) => {",
|
|
18412
18974
|
" if (pid === undefined) held = sig;",
|
|
18413
|
-
" else return ctx.kill(pid, sig).catch(() => undefined);",
|
|
18975
|
+
" else return ctx.kill(-pid, sig).catch(() => undefined);",
|
|
18414
18976
|
" };",
|
|
18415
|
-
|
|
18416
|
-
" const failed = () => (held === undefined ? 1 : 128 + held);",
|
|
18977
|
+
" for (const sig of RELAYED) await ctx.signals.on(sig, () => relay(sig));",
|
|
18978
|
+
" const failed = () => (held === undefined ? 1 : 128 + NUMBER[held]);",
|
|
18417
18979
|
" let answer;",
|
|
18418
18980
|
" try {",
|
|
18419
18981
|
" answer = await ctx.sudo(ctx.argv.slice(1));",
|
|
@@ -18429,18 +18991,41 @@ var SUDO_SOURCE = [
|
|
|
18429
18991
|
" await say(1, answer.list);",
|
|
18430
18992
|
" return 0;",
|
|
18431
18993
|
" }",
|
|
18432
|
-
' for (const sig of ["SIGINT", "SIGQUIT"]) await ctx.signals.on(sig, () => undefined);',
|
|
18433
18994
|
" if (answer.run !== undefined) {",
|
|
18434
18995
|
" try {",
|
|
18435
|
-
" pid = (await ctx.spawn({ argv: answer.run })).pid;",
|
|
18996
|
+
" pid = (await ctx.spawn({ argv: answer.run, pgid: 0 })).pid;",
|
|
18436
18997
|
" } catch (err) {",
|
|
18437
18998
|
' const why = err && err.code === "ENOENT" ? "command not found" : String(err && err.code);',
|
|
18438
18999
|
' await say(2, "sudo: " + answer.run[0] + ": " + why + "\\n");',
|
|
18439
19000
|
" return failed();",
|
|
18440
19001
|
" }",
|
|
18441
19002
|
" } else pid = answer.pid;",
|
|
19003
|
+
' const stat = () => new TextDecoder().decode(ctx.sync.fs.readFile("/proc/" + ctx.pid + "/stat"));',
|
|
19004
|
+
' const mine = Number(stat().replace(/^.*\\) /, "").split(" ")[2]);',
|
|
19005
|
+
" const foreground = () => ctx.tty.foreground(0).catch(() => undefined);",
|
|
19006
|
+
" const owned = (await foreground()) === mine;",
|
|
19007
|
+
" const handOver = async () => {",
|
|
19008
|
+
" if ((await foreground()) === mine) await ctx.tty.setForeground(0, pid).catch(() => undefined);",
|
|
19009
|
+
" };",
|
|
19010
|
+
" const takeBack = async () => {",
|
|
19011
|
+
" if (owned && (await foreground()) === pid) await ctx.tty.setForeground(0, mine).catch(() => undefined);",
|
|
19012
|
+
" };",
|
|
19013
|
+
" if (owned) await handOver();",
|
|
18442
19014
|
" if (held !== undefined) await relay(held);",
|
|
18443
|
-
"
|
|
19015
|
+
" for (;;) {",
|
|
19016
|
+
" const ended = await ctx.wait(pid, { untraced: true });",
|
|
19017
|
+
" if (!ended.stopped) {",
|
|
19018
|
+
" await takeBack();",
|
|
19019
|
+
" return ended.status;",
|
|
19020
|
+
" }",
|
|
19021
|
+
" const reading = ended.signal === 21 || ended.signal === 22;",
|
|
19022
|
+
" if (!(reading && (await foreground()) === mine)) {",
|
|
19023
|
+
" await takeBack();",
|
|
19024
|
+
' ctx.sync.kill(ctx.pid, ended.signal === 19 ? "SIGTSTP" : ended.signal);',
|
|
19025
|
+
" }",
|
|
19026
|
+
" await handOver();",
|
|
19027
|
+
' await ctx.kill(-pid, "SIGCONT").catch(() => undefined);',
|
|
19028
|
+
" }",
|
|
18444
19029
|
"}",
|
|
18445
19030
|
""
|
|
18446
19031
|
].join("\n");
|
|
@@ -18456,6 +19041,7 @@ var WASM_MAGIC = [0, 97, 115, 109];
|
|
|
18456
19041
|
var SHEBANG_MAX = 256;
|
|
18457
19042
|
var MAX_INTERPRETERS = 4;
|
|
18458
19043
|
var NOT_FOUND = 127;
|
|
19044
|
+
var NOT_EXECUTABLE = 126;
|
|
18459
19045
|
var DECIDE_MS = 100;
|
|
18460
19046
|
var INIT_PID = 1;
|
|
18461
19047
|
var SHARED_DIRS = ["/tmp", "/home"];
|
|
@@ -18605,6 +19191,9 @@ function addTimes(into, pid, t) {
|
|
|
18605
19191
|
var Launcher = class {
|
|
18606
19192
|
fs;
|
|
18607
19193
|
processFs;
|
|
19194
|
+
noLinksFs;
|
|
19195
|
+
mounted;
|
|
19196
|
+
protection;
|
|
18608
19197
|
prefixes;
|
|
18609
19198
|
writerTags;
|
|
18610
19199
|
unguardedRoot;
|
|
@@ -18713,8 +19302,8 @@ var Launcher = class {
|
|
|
18713
19302
|
changed: this.watchers.changed.bind(this.watchers),
|
|
18714
19303
|
owners: this.owners
|
|
18715
19304
|
});
|
|
18716
|
-
|
|
18717
|
-
this.base = this.
|
|
19305
|
+
this.mounted = this.mounts.wrap(options.fs);
|
|
19306
|
+
this.base = this.rooted(this.mounted);
|
|
18718
19307
|
this.createWorker = options.createWorker;
|
|
18719
19308
|
this.createDriverWorker = options.createDriverWorker;
|
|
18720
19309
|
this.media = options.media ?? memoryMedia();
|
|
@@ -18751,12 +19340,7 @@ var Launcher = class {
|
|
|
18751
19340
|
});
|
|
18752
19341
|
enableCdp(this.net, this.cdp);
|
|
18753
19342
|
this.facades.enable(this.net);
|
|
18754
|
-
const fs =
|
|
18755
|
-
this.base,
|
|
18756
|
-
async () => new Set((await this.commands()).keys()),
|
|
18757
|
-
(dir) => this.userCommandDir(dir),
|
|
18758
|
-
this.owners
|
|
18759
|
-
);
|
|
19343
|
+
const fs = this.commandFs(this.base);
|
|
18760
19344
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
18761
19345
|
this.nodes.keepsOnDisk = true;
|
|
18762
19346
|
this.openFiles.add(this.nodes);
|
|
@@ -18772,15 +19356,23 @@ var Launcher = class {
|
|
|
18772
19356
|
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
18773
19357
|
}
|
|
18774
19358
|
);
|
|
18775
|
-
this.fs = this.
|
|
19359
|
+
this.fs = this.processChain(fs, this.nodes, this.unlinked);
|
|
18776
19360
|
this.writerTags = writerTags(options.protect);
|
|
18777
19361
|
this.unlinkOwnerOption = options.unlinkOwner;
|
|
18778
19362
|
if (this.writerTags.size > 0 && options.fs.protect && !options.fs.unguarded) {
|
|
18779
19363
|
throw new TypeError("protect.writers needs a root file system with an unguarded view");
|
|
18780
19364
|
}
|
|
19365
|
+
if (!options.fs.noLinks) throw new TypeError("the root file system needs a noLinks view");
|
|
18781
19366
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
18782
19367
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
18783
|
-
this.
|
|
19368
|
+
this.protection = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes) : void 0;
|
|
19369
|
+
this.processFs = this.protection?.view(this.fs) ?? this.fs;
|
|
19370
|
+
const noLinks = this.processChain(
|
|
19371
|
+
this.commandFs(this.rooted(this.noLinksOf(this.mounted))),
|
|
19372
|
+
this.nodes,
|
|
19373
|
+
this.unlinked
|
|
19374
|
+
);
|
|
19375
|
+
this.noLinksFs = this.protection?.view(noLinks) ?? noLinks;
|
|
18784
19376
|
const integrity = options.protect?.integrity;
|
|
18785
19377
|
integrityOptions(integrity);
|
|
18786
19378
|
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
@@ -19192,10 +19784,15 @@ var Launcher = class {
|
|
|
19192
19784
|
}
|
|
19193
19785
|
async unrunnable(file, cwd, scope) {
|
|
19194
19786
|
const path = this.fs.resolvePath(cwd, file);
|
|
19787
|
+
if (await this.directory(file, path)) return "EACCES";
|
|
19195
19788
|
const head = await this.base.readFileBuffer(path).catch(() => null);
|
|
19196
19789
|
if (!head || head[0] === 35 && head[1] === 33) return "ENOENT";
|
|
19197
19790
|
return binfmtOf(await this.interpreters(scope), path) ? "ENOENT" : "ENOEXEC";
|
|
19198
19791
|
}
|
|
19792
|
+
async directory(file, path) {
|
|
19793
|
+
if (!file.includes("/") || COMMAND2.test(file)) return false;
|
|
19794
|
+
return (await this.base.stat(path).catch(() => void 0))?.isDirectory === true;
|
|
19795
|
+
}
|
|
19199
19796
|
verifiedFs(fs) {
|
|
19200
19797
|
const read = (path) => this.verified(path, KERNEL_CALLER, fs);
|
|
19201
19798
|
return Object.assign(Object.create(fs), {
|
|
@@ -19335,10 +19932,29 @@ var Launcher = class {
|
|
|
19335
19932
|
return this.jobs.sessionOf(pgid);
|
|
19336
19933
|
}
|
|
19337
19934
|
loopbackFor(pid) {
|
|
19338
|
-
return new KernelLoopback(
|
|
19339
|
-
|
|
19340
|
-
|
|
19935
|
+
return new KernelLoopback(
|
|
19936
|
+
this.net,
|
|
19937
|
+
() => {
|
|
19938
|
+
const cred = this.credOf(pid);
|
|
19939
|
+
return { pid, uid: cred.euid, gid: cred.egid };
|
|
19940
|
+
},
|
|
19941
|
+
() => this.connectorStamp(pid)
|
|
19942
|
+
);
|
|
19943
|
+
}
|
|
19944
|
+
sourceCheck(pid, writer) {
|
|
19945
|
+
const { integrity } = this;
|
|
19946
|
+
if (!integrity?.readsChecked || writer) return {};
|
|
19947
|
+
const caller = () => ({
|
|
19948
|
+
pid,
|
|
19949
|
+
uid: this.credOf(pid).euid,
|
|
19950
|
+
tag: this.tagOf(pid)
|
|
19341
19951
|
});
|
|
19952
|
+
return {
|
|
19953
|
+
source: {
|
|
19954
|
+
read: (path, plain) => integrity.readSource(path, caller(), plain),
|
|
19955
|
+
open: (path, real) => integrity.openSource(path, caller(), real)
|
|
19956
|
+
}
|
|
19957
|
+
};
|
|
19342
19958
|
}
|
|
19343
19959
|
treeScrubs(req) {
|
|
19344
19960
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
@@ -19375,11 +19991,12 @@ var Launcher = class {
|
|
|
19375
19991
|
},
|
|
19376
19992
|
settling: () => this.settling.isSettling(pid),
|
|
19377
19993
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
19378
|
-
...req.blocked ? { blocked: req.blocked } : {},
|
|
19994
|
+
...anyBlocked(req.blocked) ? { blocked: req.blocked } : {},
|
|
19379
19995
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
19380
19996
|
cred: req.cred,
|
|
19381
19997
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
19382
19998
|
...this.owners ? { owners: true } : {},
|
|
19999
|
+
...this.sourceCheck(pid, stack.writer),
|
|
19383
20000
|
...linksOf2(req),
|
|
19384
20001
|
sealed: this.sealed,
|
|
19385
20002
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
@@ -19392,6 +20009,7 @@ var Launcher = class {
|
|
|
19392
20009
|
cwd: req.cwd,
|
|
19393
20010
|
fds: req.fds,
|
|
19394
20011
|
fs: stack.fs,
|
|
20012
|
+
noLinks: stack.noLinks,
|
|
19395
20013
|
...this.prefixes.length > 0 && !stack.writer ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
19396
20014
|
createWorker: this.createWorker,
|
|
19397
20015
|
onError: req.report,
|
|
@@ -19469,6 +20087,11 @@ var Launcher = class {
|
|
|
19469
20087
|
return { shownPid: this.jobs.shown(req.ppid), ...ppid !== void 0 ? { ppid } : {} };
|
|
19470
20088
|
}
|
|
19471
20089
|
forget(pid) {
|
|
20090
|
+
const image = this.jobs.list().find((m) => m.pid === pid)?.execParent;
|
|
20091
|
+
const described2 = this.described.get(pid);
|
|
20092
|
+
if (image !== void 0 && described2 && this.described.has(image)) {
|
|
20093
|
+
this.described.set(image, described2);
|
|
20094
|
+
}
|
|
19472
20095
|
this.jobs.remove(pid);
|
|
19473
20096
|
this.described.delete(pid);
|
|
19474
20097
|
const spent = this.spent.get(pid);
|
|
@@ -19584,10 +20207,11 @@ var Launcher = class {
|
|
|
19584
20207
|
const root = member && rootOf(member).pid;
|
|
19585
20208
|
return root !== void 0 && this.running(root) ? root : INIT_PID;
|
|
19586
20209
|
};
|
|
20210
|
+
const superseded = new Set([...members.values()].map((m) => m.execParent));
|
|
19587
20211
|
const listed = [];
|
|
19588
20212
|
for (const member of members.values()) {
|
|
19589
20213
|
const described2 = this.described.get(member.pid);
|
|
19590
|
-
if (member.execed || !described2) continue;
|
|
20214
|
+
if (member.execed && superseded.has(member.pid) || !described2) continue;
|
|
19591
20215
|
const cred = this.credOf(member.pid);
|
|
19592
20216
|
if (!maySee(viewer, cred)) continue;
|
|
19593
20217
|
const root = rootOf(member);
|
|
@@ -19772,7 +20396,7 @@ var Launcher = class {
|
|
|
19772
20396
|
}
|
|
19773
20397
|
signalMasksOf(pid) {
|
|
19774
20398
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
19775
|
-
const blocked = this.blockedBy(pid);
|
|
20399
|
+
const [blocked] = this.blockedBy(pid);
|
|
19776
20400
|
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
19777
20401
|
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
19778
20402
|
}
|
|
@@ -19780,14 +20404,14 @@ var Launcher = class {
|
|
|
19780
20404
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
19781
20405
|
}
|
|
19782
20406
|
blockedBy(pid) {
|
|
19783
|
-
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
20407
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? [0, 0];
|
|
19784
20408
|
}
|
|
19785
20409
|
ignoredBy(pid, fork = false) {
|
|
19786
20410
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
19787
20411
|
}
|
|
19788
20412
|
kill(pid, sig, sender, from) {
|
|
19789
20413
|
const session = from === void 0 ? void 0 : this.jobs.sidOf(from);
|
|
19790
|
-
const may = (target) => !sender || maySignal(sender, this.credOf(target)) || sig === SIG.CONT && session !== void 0 && this.jobs.sidOf(target) === session || from !== void 0 && this.imageOf(from) === this.imageOf(target) || from !== void 0 && this.granted.get(this.jobs.shown(target)) === from;
|
|
20414
|
+
const may = (target) => !sender || maySignal(sender, this.credOf(target)) || sig === SIG.CONT && session !== void 0 && this.jobs.sidOf(target) === session || from !== void 0 && this.imageOf(from) === this.imageOf(target) || from !== void 0 && this.granted.get(this.jobs.shown(target)) === from || from !== void 0 && this.granted.get(this.jobs.pgidOf(target) ?? 0) === from;
|
|
19791
20415
|
if (pid === -1) {
|
|
19792
20416
|
const sender2 = from === void 0 ? void 0 : this.imageOf(from);
|
|
19793
20417
|
return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may);
|
|
@@ -20150,19 +20774,20 @@ var Launcher = class {
|
|
|
20150
20774
|
}
|
|
20151
20775
|
stackFor(tag) {
|
|
20152
20776
|
if (!this.isWriter(tag)) {
|
|
20153
|
-
return {
|
|
20777
|
+
return {
|
|
20778
|
+
fs: this.processFs,
|
|
20779
|
+
noLinks: this.noLinksFs,
|
|
20780
|
+
nodes: this.nodes,
|
|
20781
|
+
unlinked: this.unlinked,
|
|
20782
|
+
writer: false
|
|
20783
|
+
};
|
|
20154
20784
|
}
|
|
20155
20785
|
this.writers ??= this.writerStack();
|
|
20156
20786
|
return this.writers;
|
|
20157
20787
|
}
|
|
20158
20788
|
writerStack() {
|
|
20159
|
-
const
|
|
20160
|
-
const fs =
|
|
20161
|
-
this.owners ? this.freshModules.wrap(watched) : watched,
|
|
20162
|
-
async () => new Set((await this.commands()).keys()),
|
|
20163
|
-
(dir) => this.userCommandDir(dir),
|
|
20164
|
-
this.owners
|
|
20165
|
-
);
|
|
20789
|
+
const mounted = this.mounts.wrap(this.unguardedRoot);
|
|
20790
|
+
const fs = this.commandFs(this.rooted(mounted));
|
|
20166
20791
|
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
20167
20792
|
nodes.keepsOnDisk = true;
|
|
20168
20793
|
this.openFiles.add(nodes);
|
|
@@ -20177,7 +20802,32 @@ var Launcher = class {
|
|
|
20177
20802
|
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
20178
20803
|
}
|
|
20179
20804
|
);
|
|
20180
|
-
|
|
20805
|
+
const noLinks = this.commandFs(this.rooted(this.noLinksOf(mounted)));
|
|
20806
|
+
return {
|
|
20807
|
+
fs: this.processChain(fs, nodes, unlinked),
|
|
20808
|
+
noLinks: this.processChain(noLinks, nodes, unlinked),
|
|
20809
|
+
nodes,
|
|
20810
|
+
unlinked,
|
|
20811
|
+
writer: true
|
|
20812
|
+
};
|
|
20813
|
+
}
|
|
20814
|
+
noLinksOf(mounted) {
|
|
20815
|
+
return mounted.noLinks.call(mounted);
|
|
20816
|
+
}
|
|
20817
|
+
rooted(mounted) {
|
|
20818
|
+
const watched = this.watchers.wrap(mounted);
|
|
20819
|
+
return this.owners ? this.freshModules.wrap(watched) : watched;
|
|
20820
|
+
}
|
|
20821
|
+
commandFs(root) {
|
|
20822
|
+
return withCommandDirs(
|
|
20823
|
+
root,
|
|
20824
|
+
async () => new Set((await this.commands()).keys()),
|
|
20825
|
+
(dir) => this.userCommandDir(dir),
|
|
20826
|
+
this.owners
|
|
20827
|
+
);
|
|
20828
|
+
}
|
|
20829
|
+
processChain(fs, nodes, unlinked) {
|
|
20830
|
+
return unlinked.wrap(keepingOpen(fs, nodes));
|
|
20181
20831
|
}
|
|
20182
20832
|
async starting(argv, dir, account, tag) {
|
|
20183
20833
|
this.resetCatalogs();
|
|
@@ -20259,8 +20909,10 @@ var Launcher = class {
|
|
|
20259
20909
|
const report = (message3) => stderr(encoder7.encode(`${message3}
|
|
20260
20910
|
`));
|
|
20261
20911
|
if (!planned) {
|
|
20262
|
-
|
|
20263
|
-
|
|
20912
|
+
const directory = await this.directory(file, this.fs.resolvePath(cwd, file));
|
|
20913
|
+
report(`${file}: ${directory ? "Is a directory" : "command not found"}`);
|
|
20914
|
+
const status2 = directory ? NOT_EXECUTABLE : NOT_FOUND;
|
|
20915
|
+
return { status: status2, stdout: concat6(out), stderr: concat6(err) };
|
|
20264
20916
|
}
|
|
20265
20917
|
const fds = new FdTable();
|
|
20266
20918
|
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|