@ai-ecoverse/slicc-kernel 1.92.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 +15 -11
- package/dist/index.js +40 -7
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +832 -202
- 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 +832 -213
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +920 -211
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1899 -1292
- 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) {
|
|
@@ -10246,6 +10545,22 @@ function plainDirMode(entry, mode) {
|
|
|
10246
10545
|
const wanted = mode & 4095 & ~(entry.umask?.() ?? 18);
|
|
10247
10546
|
return wanted === PLAIN_DIR_MODE ? void 0 : wanted;
|
|
10248
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
|
+
}
|
|
10249
10564
|
function mkdirOptions(entry, mode = 511) {
|
|
10250
10565
|
const owner = ownerFor2(entry, mode);
|
|
10251
10566
|
if (!owner) return { recursive: true };
|
|
@@ -10257,23 +10572,39 @@ async function mkdirExclusive(entry, path, mode) {
|
|
|
10257
10572
|
await entry.fs.mkdir(path, owner ? { owner } : {});
|
|
10258
10573
|
}
|
|
10259
10574
|
async function chown(entry, path, req) {
|
|
10575
|
+
const real = req.handle !== void 0 ? await keptOr(entry, path, req.handle) : path;
|
|
10260
10576
|
const cred = entry.cred?.();
|
|
10261
10577
|
if (!cred) {
|
|
10262
|
-
await (req.op === "chown" ? entry.fs.stat(
|
|
10578
|
+
await (req.op === "chown" ? entry.fs.stat(real) : entry.fs.lstat(real));
|
|
10263
10579
|
return done;
|
|
10264
10580
|
}
|
|
10265
|
-
await chownAs(entry.fs, cred,
|
|
10581
|
+
await chownAs(entry.fs, cred, real, {
|
|
10266
10582
|
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
10267
10583
|
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
10268
10584
|
follow: req.op === "chown"
|
|
10269
10585
|
});
|
|
10270
10586
|
return done;
|
|
10271
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
|
+
}
|
|
10272
10603
|
async function run(entry, path, req) {
|
|
10273
10604
|
const { fs, cwd } = entry;
|
|
10274
10605
|
switch (req.op) {
|
|
10275
10606
|
case "read":
|
|
10276
|
-
return { ok: true, kind: "bytes", bytes: await
|
|
10607
|
+
return { ok: true, kind: "bytes", bytes: await readSource(entry, path) };
|
|
10277
10608
|
case "write":
|
|
10278
10609
|
await fs.writeFile(path, req.body ?? new Uint8Array(0), ownerFor2(entry, 438));
|
|
10279
10610
|
return done;
|
|
@@ -10287,13 +10618,8 @@ async function run(entry, path, req) {
|
|
|
10287
10618
|
return json2(await fs.readdir(path));
|
|
10288
10619
|
case "readdir-stat":
|
|
10289
10620
|
return json2(await readdirStat(fs, path));
|
|
10290
|
-
case "mkdir":
|
|
10291
|
-
|
|
10292
|
-
const fresh2 = plain !== void 0 && !await fs.exists(path);
|
|
10293
|
-
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
10294
|
-
if (fresh2) await fs.chmod(path, plain);
|
|
10295
|
-
return done;
|
|
10296
|
-
}
|
|
10621
|
+
case "mkdir":
|
|
10622
|
+
return runMkdir(entry, path, req);
|
|
10297
10623
|
case "rm":
|
|
10298
10624
|
await fs.rm(path, { recursive: true });
|
|
10299
10625
|
return done;
|
|
@@ -10319,7 +10645,7 @@ async function run(entry, path, req) {
|
|
|
10319
10645
|
return done;
|
|
10320
10646
|
case "create":
|
|
10321
10647
|
await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
|
|
10322
|
-
entry.created?.add(path);
|
|
10648
|
+
if (req.opening) entry.created?.add(path);
|
|
10323
10649
|
entry.fresh?.(path);
|
|
10324
10650
|
return done;
|
|
10325
10651
|
case "readlink":
|
|
@@ -10330,10 +10656,10 @@ async function run(entry, path, req) {
|
|
|
10330
10656
|
return done;
|
|
10331
10657
|
}
|
|
10332
10658
|
case "utimes":
|
|
10333
|
-
await fs.utimes(path,
|
|
10659
|
+
await fs.utimes(path, ...await timesOf(entry, path, req));
|
|
10334
10660
|
return done;
|
|
10335
10661
|
case "lutimes":
|
|
10336
|
-
await lutimesOf(fs, path,
|
|
10662
|
+
await lutimesOf(fs, path, ...await timesOf(entry, path, req));
|
|
10337
10663
|
return done;
|
|
10338
10664
|
case "chown":
|
|
10339
10665
|
case "lchown":
|
|
@@ -10346,6 +10672,17 @@ async function run(entry, path, req) {
|
|
|
10346
10672
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
10347
10673
|
}
|
|
10348
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
|
+
}
|
|
10349
10686
|
function guardOf(entry) {
|
|
10350
10687
|
const cred = entry.dac && entry.cred?.();
|
|
10351
10688
|
if (!cred || !entry.dac) return void 0;
|
|
@@ -10355,41 +10692,82 @@ function guardOf(entry) {
|
|
|
10355
10692
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
10356
10693
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
10357
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
|
+
}
|
|
10358
10703
|
async function guard(g, path, req, cwd) {
|
|
10359
10704
|
const { op } = req;
|
|
10360
|
-
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
|
+
}
|
|
10361
10709
|
const other = () => g.fs.resolvePath(cwd, req.arg2 ?? "");
|
|
10362
10710
|
switch (op) {
|
|
10363
10711
|
case "readdir":
|
|
10364
|
-
case "readdir-stat":
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
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
|
+
}
|
|
10368
10721
|
case "create":
|
|
10369
10722
|
case "symlink":
|
|
10370
|
-
|
|
10723
|
+
await inParent(g, op, path);
|
|
10724
|
+
return { path: await walkSafe(g, path, op === "create") };
|
|
10371
10725
|
case "unlink":
|
|
10372
|
-
case "rmdir":
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
return
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
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
|
+
}
|
|
10380
10751
|
case "utimes":
|
|
10381
|
-
case "lutimes":
|
|
10382
|
-
|
|
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
|
+
}
|
|
10383
10758
|
case "read":
|
|
10384
10759
|
case "pread":
|
|
10385
|
-
|
|
10760
|
+
if (req.handle === void 0) await readable(g, op, path);
|
|
10761
|
+
return { path: await walkSafe(g, path, true) };
|
|
10386
10762
|
case "pwrite":
|
|
10387
10763
|
case "truncate":
|
|
10388
|
-
|
|
10764
|
+
if (req.handle === void 0) await fileWritable(g, op, path);
|
|
10765
|
+
return { path: await walkSafe(g, path, true) };
|
|
10389
10766
|
case "write":
|
|
10390
|
-
|
|
10767
|
+
if (req.handle === void 0 && req.mode !== 1) await writable(g, op, path);
|
|
10768
|
+
return { path: await walkSafe(g, path, true) };
|
|
10391
10769
|
default:
|
|
10392
|
-
return
|
|
10770
|
+
return { path: await walkSafe(g, path, true) };
|
|
10393
10771
|
}
|
|
10394
10772
|
}
|
|
10395
10773
|
async function opening(entry, path, mode) {
|
|
@@ -10406,6 +10784,7 @@ async function holdOp(entry, path, req) {
|
|
|
10406
10784
|
if (on && open) {
|
|
10407
10785
|
await opening(entry, path, mode);
|
|
10408
10786
|
const real = await entry.fs.realpath?.(path, true).catch(() => path);
|
|
10787
|
+
await entry.source?.open(path, real);
|
|
10409
10788
|
return json2(entry.hold?.(path, on, open, real) ?? null);
|
|
10410
10789
|
}
|
|
10411
10790
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
@@ -10458,15 +10837,16 @@ async function mayChange(entry, path, req) {
|
|
|
10458
10837
|
}
|
|
10459
10838
|
async function guarded(entry, path, req) {
|
|
10460
10839
|
const g = guardOf(entry);
|
|
10461
|
-
if (!g) return
|
|
10462
|
-
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 {};
|
|
10463
10842
|
try {
|
|
10464
10843
|
await mayChange(entry, path, req);
|
|
10465
|
-
await guard(g, path, req, entry.cwd);
|
|
10466
|
-
return
|
|
10844
|
+
const paths = await guard(g, path, req, entry.cwd);
|
|
10845
|
+
return { paths };
|
|
10467
10846
|
} catch (err) {
|
|
10468
10847
|
const refusal = err.code === "EACCES";
|
|
10469
|
-
|
|
10848
|
+
const refused2 = req.op === "exists" && refusal ? json2(false) : toErrno(err);
|
|
10849
|
+
return { refused: refused2 };
|
|
10470
10850
|
}
|
|
10471
10851
|
}
|
|
10472
10852
|
async function createExclusive(fs, path, owner) {
|
|
@@ -10492,6 +10872,7 @@ async function ranged(fs, path, req) {
|
|
|
10492
10872
|
else await ops.truncate(path, req.length ?? 0);
|
|
10493
10873
|
return done;
|
|
10494
10874
|
}
|
|
10875
|
+
var CHOWN_OPS = /* @__PURE__ */ new Set(["chown", "lchown"]);
|
|
10495
10876
|
var UNLINKED_OPS = /* @__PURE__ */ new Set(["read", "pread", "pwrite", "truncate"]);
|
|
10496
10877
|
var OWN_OPS = /* @__PURE__ */ new Set(["rm", "unlink", "rmdir", "rename", "link"]);
|
|
10497
10878
|
var TWO_PATHS = /* @__PURE__ */ new Set(["rename", "link"]);
|
|
@@ -10556,7 +10937,7 @@ async function rmPermitted(entry, path, req, refused2) {
|
|
|
10556
10937
|
const st = await entry.fs.lstat(path).catch(() => void 0);
|
|
10557
10938
|
if (!st?.isDirectory) return refused2;
|
|
10558
10939
|
const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
|
|
10559
|
-
if (unlisted) return unlisted;
|
|
10940
|
+
if ("refused" in unlisted) return unlisted.refused;
|
|
10560
10941
|
const names = await entry.fs.readdir(path).catch(() => void 0);
|
|
10561
10942
|
if (!names) return refused2;
|
|
10562
10943
|
let first;
|
|
@@ -10568,31 +10949,64 @@ async function rmPermitted(entry, path, req, refused2) {
|
|
|
10568
10949
|
if (!child.ok) first ??= child;
|
|
10569
10950
|
}
|
|
10570
10951
|
if (first) return first;
|
|
10571
|
-
const
|
|
10572
|
-
|
|
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);
|
|
10573
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;
|
|
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"]);
|
|
10574
10981
|
async function dispatchOne(entry, req) {
|
|
10575
10982
|
const { fs, cwd } = entry;
|
|
10576
10983
|
try {
|
|
10577
10984
|
const path = fs.resolvePath(cwd, req.path);
|
|
10578
|
-
|
|
10579
|
-
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;
|
|
10580
10989
|
if (req.op === "access") return await accessOp(entry, path, req);
|
|
10581
10990
|
if (req.op === "hold") return await holdOp(entry, path, req);
|
|
10582
|
-
const
|
|
10583
|
-
if (
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
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` };
|
|
10589
11003
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
10590
|
-
const serve = async () => run(
|
|
10591
|
-
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());
|
|
10592
11006
|
}
|
|
10593
|
-
if (!entry.own || !OWN_OPS.has(req.op)) return await run(
|
|
10594
|
-
const target = TWO_PATHS.has(req.op) ? fs.resolvePath(cwd, req.arg2 ?? "") :
|
|
10595
|
-
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);
|
|
10596
11010
|
} catch (err) {
|
|
10597
11011
|
return toErrno(err);
|
|
10598
11012
|
}
|
|
@@ -10620,6 +11034,15 @@ var SAB_I_KILLED = 13;
|
|
|
10620
11034
|
var SAB_I_ASYNC = 14;
|
|
10621
11035
|
var SAB_I_STOP = 15;
|
|
10622
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);
|
|
10623
11046
|
var U32 = 2 ** 32;
|
|
10624
11047
|
function storeU53(header3, lo, hi, value) {
|
|
10625
11048
|
Atomics.store(header3, hi, Math.floor(value / U32));
|
|
@@ -11146,7 +11569,7 @@ function mountTable(mounts = []) {
|
|
|
11146
11569
|
}
|
|
11147
11570
|
|
|
11148
11571
|
// src/version.ts
|
|
11149
|
-
var KERNEL_VERSION = true ? "1.
|
|
11572
|
+
var KERNEL_VERSION = true ? "1.93.0" : "0.0.0-dev";
|
|
11150
11573
|
var OS_RELEASE = "6.0.0-slicc";
|
|
11151
11574
|
function procVersion() {
|
|
11152
11575
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11846,21 +12269,28 @@ function bodyOf(incoming, head, method, signal) {
|
|
|
11846
12269
|
var KernelLoopback = class {
|
|
11847
12270
|
net;
|
|
11848
12271
|
cred;
|
|
11849
|
-
|
|
12272
|
+
stamp;
|
|
12273
|
+
constructor(net, cred, stamp) {
|
|
11850
12274
|
this.net = net;
|
|
11851
12275
|
this.cred = cred;
|
|
12276
|
+
this.stamp = stamp;
|
|
11852
12277
|
}
|
|
11853
12278
|
port(url) {
|
|
11854
12279
|
return kernelLoopbackPort(url);
|
|
11855
12280
|
}
|
|
11856
|
-
connect(url, port, signal) {
|
|
12281
|
+
async connect(url, port, signal) {
|
|
11857
12282
|
if (url.protocol === "https:" || url.protocol === "wss:") {
|
|
11858
12283
|
throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
|
|
11859
12284
|
}
|
|
11860
12285
|
signal.throwIfAborted();
|
|
11861
12286
|
const socket = this.net.socket("inet");
|
|
11862
12287
|
try {
|
|
11863
|
-
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
|
+
);
|
|
11864
12294
|
} catch (err) {
|
|
11865
12295
|
socket.close();
|
|
11866
12296
|
const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
@@ -11874,7 +12304,7 @@ var KernelLoopback = class {
|
|
|
11874
12304
|
const body = req.body ?? (/^(POST|PUT|PATCH)$/i.test(req.method) ? new Uint8Array(0) : void 0);
|
|
11875
12305
|
const length2 = body ? [["Content-Length", String(body.length)]] : [];
|
|
11876
12306
|
const head = requestHead(req.method, url, req.headers, [...length2, ["Connection", "close"]]);
|
|
11877
|
-
const socket = this.connect(url, port, req.signal);
|
|
12307
|
+
const socket = await this.connect(url, port, req.signal);
|
|
11878
12308
|
try {
|
|
11879
12309
|
await writeAll2(socket, body ? concat([head, body]) : head, req.signal);
|
|
11880
12310
|
const incoming = new Incoming(socket);
|
|
@@ -11895,7 +12325,7 @@ var KernelLoopback = class {
|
|
|
11895
12325
|
}
|
|
11896
12326
|
async websocket(req, port) {
|
|
11897
12327
|
const url = new URL(req.url);
|
|
11898
|
-
const socket = this.connect(url, port, req.signal);
|
|
12328
|
+
const socket = await this.connect(url, port, req.signal);
|
|
11899
12329
|
try {
|
|
11900
12330
|
const key = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(16))));
|
|
11901
12331
|
const extra = [
|
|
@@ -11920,6 +12350,9 @@ var KernelLoopback = class {
|
|
|
11920
12350
|
if (!upgraded || accept2 !== await acceptFor(key)) {
|
|
11921
12351
|
throw errno("EPROTO", "the server did not accept the WebSocket key");
|
|
11922
12352
|
}
|
|
12353
|
+
if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
|
|
12354
|
+
throw errno("EPROTO", "the server offered an unsolicited extension");
|
|
12355
|
+
}
|
|
11923
12356
|
const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
|
|
11924
12357
|
return new LoopbackWebSocket(socket, incoming, protocol);
|
|
11925
12358
|
} catch (err) {
|
|
@@ -12019,7 +12452,7 @@ var LoopbackWebSocket = class {
|
|
|
12019
12452
|
})();
|
|
12020
12453
|
}
|
|
12021
12454
|
async pump(reader, deliver) {
|
|
12022
|
-
let close = { code: 1006, reason: "" };
|
|
12455
|
+
let close = { code: 1006, reason: "", wasClean: false };
|
|
12023
12456
|
try {
|
|
12024
12457
|
for (; ; ) {
|
|
12025
12458
|
await this.space();
|
|
@@ -12029,14 +12462,14 @@ var LoopbackWebSocket = class {
|
|
|
12029
12462
|
else if (event.kind === "binary") deliver(event.bytes);
|
|
12030
12463
|
else if (event.kind === "ping") this.write(clientFrame(OP_PONG, event.payload));
|
|
12031
12464
|
else {
|
|
12032
|
-
close = { code: event.code, reason: event.reason };
|
|
12465
|
+
close = { code: event.code, reason: event.reason, wasClean: true };
|
|
12033
12466
|
if (!this.sentClose) this.sendClose(event.code === 1005 ? 1e3 : event.code, "");
|
|
12034
12467
|
break;
|
|
12035
12468
|
}
|
|
12036
12469
|
}
|
|
12037
12470
|
} catch (err) {
|
|
12038
12471
|
if (err instanceof WsError) this.sendClose(err.code, err.message);
|
|
12039
|
-
close = { code:
|
|
12472
|
+
close = { code: 1006, reason: "", wasClean: false };
|
|
12040
12473
|
} finally {
|
|
12041
12474
|
const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
|
|
12042
12475
|
await this.writes;
|
|
@@ -12162,14 +12595,22 @@ var WsHandles = class {
|
|
|
12162
12595
|
return typeof next2.value === "string" ? { ok: true, kind: "json", json: { text: next2.value } } : { ok: true, kind: "bytes", bytes: next2.value };
|
|
12163
12596
|
}
|
|
12164
12597
|
const closed = await socket.closed;
|
|
12165
|
-
return {
|
|
12598
|
+
return {
|
|
12599
|
+
ok: true,
|
|
12600
|
+
kind: "json",
|
|
12601
|
+
json: { code: closed.code, reason: closed.reason, wasClean: closed.wasClean === true }
|
|
12602
|
+
};
|
|
12166
12603
|
} catch (e) {
|
|
12167
12604
|
return fail("ECONNRESET", message(e));
|
|
12168
12605
|
}
|
|
12169
12606
|
}
|
|
12170
12607
|
async closed(socket) {
|
|
12171
|
-
const
|
|
12172
|
-
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
|
+
};
|
|
12173
12614
|
}
|
|
12174
12615
|
send(socket, req, entry) {
|
|
12175
12616
|
const data = req.text ?? req.body;
|
|
@@ -12209,7 +12650,7 @@ function message2(e) {
|
|
|
12209
12650
|
}
|
|
12210
12651
|
function codeOf2(e) {
|
|
12211
12652
|
const code = e?.code;
|
|
12212
|
-
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";
|
|
12213
12654
|
}
|
|
12214
12655
|
async function* once(bytes) {
|
|
12215
12656
|
yield bytes;
|
|
@@ -12292,7 +12733,8 @@ var HttpHandles = class {
|
|
|
12292
12733
|
if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
|
|
12293
12734
|
const status = e.status;
|
|
12294
12735
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
12295
|
-
const
|
|
12736
|
+
const code = codeOf2(e);
|
|
12737
|
+
const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
12296
12738
|
return { ok: false, errno: errno2, message: text };
|
|
12297
12739
|
}
|
|
12298
12740
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
@@ -13785,7 +14227,7 @@ function isPtySyscall(req) {
|
|
|
13785
14227
|
return req.op.startsWith("pty-");
|
|
13786
14228
|
}
|
|
13787
14229
|
function isVfsSyscall(req) {
|
|
13788
|
-
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";
|
|
13789
14231
|
}
|
|
13790
14232
|
function isFdSyscall(req) {
|
|
13791
14233
|
return req.op.startsWith("fd-");
|
|
@@ -13805,6 +14247,9 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
13805
14247
|
"fd-pwrite",
|
|
13806
14248
|
"fd-resize",
|
|
13807
14249
|
"fd-vfs-stat",
|
|
14250
|
+
"fd-chmod",
|
|
14251
|
+
"fd-chown",
|
|
14252
|
+
"fd-utimes",
|
|
13808
14253
|
"fd-path-flush",
|
|
13809
14254
|
"fd-path-unlinking",
|
|
13810
14255
|
"fd-path-unlinked",
|
|
@@ -13835,6 +14280,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
13835
14280
|
"fd-tty-owner",
|
|
13836
14281
|
"fd-open-sealed",
|
|
13837
14282
|
"fd-open-clipboard",
|
|
14283
|
+
"fd-clipboard-abort",
|
|
13838
14284
|
"tty-get",
|
|
13839
14285
|
"tty-set",
|
|
13840
14286
|
"tty-winsz",
|
|
@@ -14180,7 +14626,11 @@ var WasmProcess = class {
|
|
|
14180
14626
|
if (!stderr?.write || stderr.clipboard) return;
|
|
14181
14627
|
const line = `${name2}: /dev/clipboard: ${clipboardLine(err.detail)}
|
|
14182
14628
|
`;
|
|
14183
|
-
|
|
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
|
+
]);
|
|
14184
14634
|
}
|
|
14185
14635
|
async write(fd, body, nonblock = false, cancelled) {
|
|
14186
14636
|
const file = this.fds.get(fd).file;
|
|
@@ -14207,10 +14657,13 @@ var WasmProcess = class {
|
|
|
14207
14657
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
14208
14658
|
if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
|
|
14209
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;
|
|
14210
14663
|
const fd = this.fds.install(heldFile(), 3);
|
|
14211
14664
|
try {
|
|
14212
14665
|
const nodes = this.nodes;
|
|
14213
|
-
const path =
|
|
14666
|
+
const path = await this.openPath(req, marked);
|
|
14214
14667
|
if (inProc(path)) {
|
|
14215
14668
|
this.fds.installAt(fd, await this.procFile(req, path));
|
|
14216
14669
|
return fd;
|
|
@@ -14220,23 +14673,23 @@ var WasmProcess = class {
|
|
|
14220
14673
|
const plain = this.plainMode(req.mode);
|
|
14221
14674
|
if (req.exclusive) {
|
|
14222
14675
|
await nodes.createExclusive(path, this.newOwner(req.mode));
|
|
14223
|
-
if (plain !== void 0) await
|
|
14224
|
-
this.fds.installAt(fd, this.openVfsFile(open));
|
|
14676
|
+
if (plain !== void 0) await fs.chmod?.(path, plain);
|
|
14677
|
+
this.fds.installAt(fd, this.openVfsFile(open, void 0, fs));
|
|
14225
14678
|
} else if (req.create) {
|
|
14226
14679
|
await nodes.onEntry(path, async () => {
|
|
14227
14680
|
const marks = this.options.owners || plain !== void 0;
|
|
14228
|
-
const fresh2 = marks && !await present2(
|
|
14229
|
-
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path)));
|
|
14681
|
+
const fresh2 = marks && !await present2(fs, path, true);
|
|
14682
|
+
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
14230
14683
|
await this.fds.get(fd).file.stat?.();
|
|
14231
|
-
if (fresh2 && plain !== void 0) await
|
|
14684
|
+
if (fresh2 && plain !== void 0) await fs.chmod?.(path, plain);
|
|
14232
14685
|
else if (fresh2) {
|
|
14233
|
-
await
|
|
14686
|
+
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
14234
14687
|
}
|
|
14235
14688
|
});
|
|
14236
14689
|
} else {
|
|
14237
|
-
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path)));
|
|
14690
|
+
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
14238
14691
|
}
|
|
14239
|
-
if (req.existing && !await present2(
|
|
14692
|
+
if (req.existing && !await present2(fs, path, true)) {
|
|
14240
14693
|
throw new KernelError("ENOENT");
|
|
14241
14694
|
}
|
|
14242
14695
|
} catch (err) {
|
|
@@ -14270,6 +14723,27 @@ var WasmProcess = class {
|
|
|
14270
14723
|
writesAt(req) {
|
|
14271
14724
|
return (req.flags & WRITE_ACCESS) !== 0 || req.truncate === true || req.create === true || req.exclusive === true;
|
|
14272
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
|
+
}
|
|
14273
14747
|
async mayOpen(req) {
|
|
14274
14748
|
const { guard: guard2 } = this.options;
|
|
14275
14749
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
@@ -14369,9 +14843,9 @@ var WasmProcess = class {
|
|
|
14369
14843
|
);
|
|
14370
14844
|
return memoryFile(tree2.read(path), path, req.position);
|
|
14371
14845
|
}
|
|
14372
|
-
openVfsFile(req, id2) {
|
|
14846
|
+
openVfsFile(req, id2, fs = this.options.fs) {
|
|
14373
14847
|
return vfsFile(
|
|
14374
|
-
|
|
14848
|
+
fs,
|
|
14375
14849
|
{
|
|
14376
14850
|
path: req.path,
|
|
14377
14851
|
flags: req.flags,
|
|
@@ -14454,7 +14928,7 @@ var WasmProcess = class {
|
|
|
14454
14928
|
return { ok: true, kind: "void" };
|
|
14455
14929
|
case "fd-renumber":
|
|
14456
14930
|
if (req.from !== req.to) {
|
|
14457
|
-
this.fds.
|
|
14931
|
+
await this.fds.dup2Clipboard(req.from, req.to);
|
|
14458
14932
|
if (!req.keep) await Promise.resolve(this.fds.close(req.from));
|
|
14459
14933
|
}
|
|
14460
14934
|
return { ok: true, kind: "void" };
|
|
@@ -14466,6 +14940,11 @@ var WasmProcess = class {
|
|
|
14466
14940
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
14467
14941
|
case "fd-open-clipboard":
|
|
14468
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
|
+
}
|
|
14469
14948
|
case "fd-tty-owner":
|
|
14470
14949
|
return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
|
|
14471
14950
|
case "fd-select": {
|
|
@@ -14518,12 +14997,23 @@ var WasmProcess = class {
|
|
|
14518
14997
|
case "fd-resize":
|
|
14519
14998
|
await file.resize(req.size);
|
|
14520
14999
|
return { ok: true, kind: "void" };
|
|
14521
|
-
case "fd-vfs-stat":
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
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);
|
|
14527
15017
|
}
|
|
14528
15018
|
}
|
|
14529
15019
|
keptPath;
|
|
@@ -14544,7 +15034,7 @@ var WasmProcess = class {
|
|
|
14544
15034
|
async promote(req) {
|
|
14545
15035
|
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
14546
15036
|
if (req.share !== void 0) {
|
|
14547
|
-
this.fds.
|
|
15037
|
+
await this.fds.dup2Clipboard(req.share, req.fd);
|
|
14548
15038
|
return;
|
|
14549
15039
|
}
|
|
14550
15040
|
if (req.path === void 0) throw new KernelError("EINVAL");
|
|
@@ -14573,6 +15063,46 @@ var WasmProcess = class {
|
|
|
14573
15063
|
this.fds.installAt(fd, heldFile(meta));
|
|
14574
15064
|
return fd;
|
|
14575
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
|
+
}
|
|
14576
15106
|
fdInfo(fd) {
|
|
14577
15107
|
const file = this.fds.get(fd).file;
|
|
14578
15108
|
const flags2 = this.fds.statusFlags(fd);
|
|
@@ -14791,7 +15321,10 @@ var WasmProcess = class {
|
|
|
14791
15321
|
const { file, argv, env, cwd, cred, caller } = answer.grant;
|
|
14792
15322
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
14793
15323
|
return {
|
|
14794
|
-
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
|
+
})
|
|
14795
15328
|
};
|
|
14796
15329
|
}
|
|
14797
15330
|
async mountSyscall(req, cancelled) {
|
|
@@ -15095,7 +15628,9 @@ function holdingToken(opts, holds, caller) {
|
|
|
15095
15628
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
15096
15629
|
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
15097
15630
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
15631
|
+
...opts.source ? { source: opts.source } : {},
|
|
15098
15632
|
fs: opts.fs,
|
|
15633
|
+
noLinks: opts.noLinks,
|
|
15099
15634
|
cwd: opts.cwd,
|
|
15100
15635
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
15101
15636
|
hold: (path, on, open, real, handle) => holds.hold(path, on, open, real, handle),
|
|
@@ -15121,6 +15656,8 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
15121
15656
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
15122
15657
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
15123
15658
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
15659
|
+
...opts.source ? { source: opts.source } : {},
|
|
15660
|
+
noLinks: opts.noLinks,
|
|
15124
15661
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
15125
15662
|
...opts.identity ? { identity: opts.identity } : {},
|
|
15126
15663
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
@@ -15176,8 +15713,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
15176
15713
|
function spawnWasmProcess(opts) {
|
|
15177
15714
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15178
15715
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
15179
|
-
|
|
15180
|
-
|
|
15716
|
+
const blocked = opts.fork?.wasi?.blocked ?? opts.blocked;
|
|
15717
|
+
if (blocked && anyBlocked(blocked) && opts.program.abi === "wasi") storeBlocked(header3, blocked);
|
|
15181
15718
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
15182
15719
|
const created3 = new Created();
|
|
15183
15720
|
const process = new WasmProcess(
|
|
@@ -15192,7 +15729,7 @@ function spawnWasmProcess(opts) {
|
|
|
15192
15729
|
...opts.program.abi === "js" ? {
|
|
15193
15730
|
exitNow: (code) => exitNow(code),
|
|
15194
15731
|
exitSignal: (sig) => queueMicrotask(() => finish(128 + sig, sig))
|
|
15195
|
-
} : {}
|
|
15732
|
+
} : { exitSignal: (sig) => terminate(128 + sig, sig) }
|
|
15196
15733
|
},
|
|
15197
15734
|
created3
|
|
15198
15735
|
)
|
|
@@ -15278,7 +15815,7 @@ function spawnWasmProcess(opts) {
|
|
|
15278
15815
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15279
15816
|
const tw = opts.createWorker();
|
|
15280
15817
|
const tsignals = threadSignalsOf(tsab);
|
|
15281
|
-
if (thread.blocked)
|
|
15818
|
+
if (thread.blocked) storeBlocked(tsignals.header, thread.blocked);
|
|
15282
15819
|
threadSignals.set(thread.tid, tsignals);
|
|
15283
15820
|
const tdispatch = (req) => dying.serving(
|
|
15284
15821
|
() => isWasmSyscall(req) ? process.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -15306,12 +15843,13 @@ function spawnWasmProcess(opts) {
|
|
|
15306
15843
|
processInit(opts, sab, process.umask, copyCred(process.cred), lane?.lane),
|
|
15307
15844
|
transferOf(opts, lane?.lane)
|
|
15308
15845
|
);
|
|
15309
|
-
const
|
|
15310
|
-
if (process.signal(sig) !== "terminate") return;
|
|
15311
|
-
const code = sig === SIG.KILL ? 137 : 128 + sig;
|
|
15846
|
+
const terminate = (code, sig) => {
|
|
15312
15847
|
if (opts.program.abi !== "wasi" || done4) finish(code, sig);
|
|
15313
15848
|
else dying.start(code, sig, header3, process, () => finish(code, sig));
|
|
15314
15849
|
};
|
|
15850
|
+
const signal = (sig) => {
|
|
15851
|
+
if (process.signal(sig) === "terminate") terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
|
|
15852
|
+
};
|
|
15315
15853
|
const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
|
|
15316
15854
|
return {
|
|
15317
15855
|
pid: opts.pid,
|
|
@@ -15322,7 +15860,7 @@ function spawnWasmProcess(opts) {
|
|
|
15322
15860
|
onState: (listener) => process.onState(listener),
|
|
15323
15861
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
15324
15862
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
15325
|
-
blockedSignals: () => opts.program.abi === "wasi" ?
|
|
15863
|
+
blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header3) : [0, 0],
|
|
15326
15864
|
signalMasks: () => process.signalMasks(),
|
|
15327
15865
|
umask: () => process.umask,
|
|
15328
15866
|
cred: () => copyCred(process.cred),
|
|
@@ -18428,14 +18966,16 @@ var SUDO_COMMAND = {
|
|
|
18428
18966
|
var SUDO_SOURCE = [
|
|
18429
18967
|
"export default async function sudo(ctx) {",
|
|
18430
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 };",
|
|
18431
18971
|
" let pid;",
|
|
18432
18972
|
" let held;",
|
|
18433
18973
|
" const relay = (sig) => {",
|
|
18434
18974
|
" if (pid === undefined) held = sig;",
|
|
18435
|
-
" else return ctx.kill(pid, sig).catch(() => undefined);",
|
|
18975
|
+
" else return ctx.kill(-pid, sig).catch(() => undefined);",
|
|
18436
18976
|
" };",
|
|
18437
|
-
|
|
18438
|
-
" 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]);",
|
|
18439
18979
|
" let answer;",
|
|
18440
18980
|
" try {",
|
|
18441
18981
|
" answer = await ctx.sudo(ctx.argv.slice(1));",
|
|
@@ -18451,18 +18991,41 @@ var SUDO_SOURCE = [
|
|
|
18451
18991
|
" await say(1, answer.list);",
|
|
18452
18992
|
" return 0;",
|
|
18453
18993
|
" }",
|
|
18454
|
-
' for (const sig of ["SIGINT", "SIGQUIT"]) await ctx.signals.on(sig, () => undefined);',
|
|
18455
18994
|
" if (answer.run !== undefined) {",
|
|
18456
18995
|
" try {",
|
|
18457
|
-
" pid = (await ctx.spawn({ argv: answer.run })).pid;",
|
|
18996
|
+
" pid = (await ctx.spawn({ argv: answer.run, pgid: 0 })).pid;",
|
|
18458
18997
|
" } catch (err) {",
|
|
18459
18998
|
' const why = err && err.code === "ENOENT" ? "command not found" : String(err && err.code);',
|
|
18460
18999
|
' await say(2, "sudo: " + answer.run[0] + ": " + why + "\\n");',
|
|
18461
19000
|
" return failed();",
|
|
18462
19001
|
" }",
|
|
18463
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();",
|
|
18464
19014
|
" if (held !== undefined) await relay(held);",
|
|
18465
|
-
"
|
|
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
|
+
" }",
|
|
18466
19029
|
"}",
|
|
18467
19030
|
""
|
|
18468
19031
|
].join("\n");
|
|
@@ -18478,6 +19041,7 @@ var WASM_MAGIC = [0, 97, 115, 109];
|
|
|
18478
19041
|
var SHEBANG_MAX = 256;
|
|
18479
19042
|
var MAX_INTERPRETERS = 4;
|
|
18480
19043
|
var NOT_FOUND = 127;
|
|
19044
|
+
var NOT_EXECUTABLE = 126;
|
|
18481
19045
|
var DECIDE_MS = 100;
|
|
18482
19046
|
var INIT_PID = 1;
|
|
18483
19047
|
var SHARED_DIRS = ["/tmp", "/home"];
|
|
@@ -18627,6 +19191,9 @@ function addTimes(into, pid, t) {
|
|
|
18627
19191
|
var Launcher = class {
|
|
18628
19192
|
fs;
|
|
18629
19193
|
processFs;
|
|
19194
|
+
noLinksFs;
|
|
19195
|
+
mounted;
|
|
19196
|
+
protection;
|
|
18630
19197
|
prefixes;
|
|
18631
19198
|
writerTags;
|
|
18632
19199
|
unguardedRoot;
|
|
@@ -18735,8 +19302,8 @@ var Launcher = class {
|
|
|
18735
19302
|
changed: this.watchers.changed.bind(this.watchers),
|
|
18736
19303
|
owners: this.owners
|
|
18737
19304
|
});
|
|
18738
|
-
|
|
18739
|
-
this.base = this.
|
|
19305
|
+
this.mounted = this.mounts.wrap(options.fs);
|
|
19306
|
+
this.base = this.rooted(this.mounted);
|
|
18740
19307
|
this.createWorker = options.createWorker;
|
|
18741
19308
|
this.createDriverWorker = options.createDriverWorker;
|
|
18742
19309
|
this.media = options.media ?? memoryMedia();
|
|
@@ -18773,12 +19340,7 @@ var Launcher = class {
|
|
|
18773
19340
|
});
|
|
18774
19341
|
enableCdp(this.net, this.cdp);
|
|
18775
19342
|
this.facades.enable(this.net);
|
|
18776
|
-
const fs =
|
|
18777
|
-
this.base,
|
|
18778
|
-
async () => new Set((await this.commands()).keys()),
|
|
18779
|
-
(dir) => this.userCommandDir(dir),
|
|
18780
|
-
this.owners
|
|
18781
|
-
);
|
|
19343
|
+
const fs = this.commandFs(this.base);
|
|
18782
19344
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
18783
19345
|
this.nodes.keepsOnDisk = true;
|
|
18784
19346
|
this.openFiles.add(this.nodes);
|
|
@@ -18794,15 +19356,23 @@ var Launcher = class {
|
|
|
18794
19356
|
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
18795
19357
|
}
|
|
18796
19358
|
);
|
|
18797
|
-
this.fs = this.
|
|
19359
|
+
this.fs = this.processChain(fs, this.nodes, this.unlinked);
|
|
18798
19360
|
this.writerTags = writerTags(options.protect);
|
|
18799
19361
|
this.unlinkOwnerOption = options.unlinkOwner;
|
|
18800
19362
|
if (this.writerTags.size > 0 && options.fs.protect && !options.fs.unguarded) {
|
|
18801
19363
|
throw new TypeError("protect.writers needs a root file system with an unguarded view");
|
|
18802
19364
|
}
|
|
19365
|
+
if (!options.fs.noLinks) throw new TypeError("the root file system needs a noLinks view");
|
|
18803
19366
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
18804
19367
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
18805
|
-
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;
|
|
18806
19376
|
const integrity = options.protect?.integrity;
|
|
18807
19377
|
integrityOptions(integrity);
|
|
18808
19378
|
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
@@ -19214,10 +19784,15 @@ var Launcher = class {
|
|
|
19214
19784
|
}
|
|
19215
19785
|
async unrunnable(file, cwd, scope) {
|
|
19216
19786
|
const path = this.fs.resolvePath(cwd, file);
|
|
19787
|
+
if (await this.directory(file, path)) return "EACCES";
|
|
19217
19788
|
const head = await this.base.readFileBuffer(path).catch(() => null);
|
|
19218
19789
|
if (!head || head[0] === 35 && head[1] === 33) return "ENOENT";
|
|
19219
19790
|
return binfmtOf(await this.interpreters(scope), path) ? "ENOENT" : "ENOEXEC";
|
|
19220
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
|
+
}
|
|
19221
19796
|
verifiedFs(fs) {
|
|
19222
19797
|
const read = (path) => this.verified(path, KERNEL_CALLER, fs);
|
|
19223
19798
|
return Object.assign(Object.create(fs), {
|
|
@@ -19357,10 +19932,29 @@ var Launcher = class {
|
|
|
19357
19932
|
return this.jobs.sessionOf(pgid);
|
|
19358
19933
|
}
|
|
19359
19934
|
loopbackFor(pid) {
|
|
19360
|
-
return new KernelLoopback(
|
|
19361
|
-
|
|
19362
|
-
|
|
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)
|
|
19363
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
|
+
};
|
|
19364
19958
|
}
|
|
19365
19959
|
treeScrubs(req) {
|
|
19366
19960
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
@@ -19397,11 +19991,12 @@ var Launcher = class {
|
|
|
19397
19991
|
},
|
|
19398
19992
|
settling: () => this.settling.isSettling(pid),
|
|
19399
19993
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
19400
|
-
...req.blocked ? { blocked: req.blocked } : {},
|
|
19994
|
+
...anyBlocked(req.blocked) ? { blocked: req.blocked } : {},
|
|
19401
19995
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
19402
19996
|
cred: req.cred,
|
|
19403
19997
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
19404
19998
|
...this.owners ? { owners: true } : {},
|
|
19999
|
+
...this.sourceCheck(pid, stack.writer),
|
|
19405
20000
|
...linksOf2(req),
|
|
19406
20001
|
sealed: this.sealed,
|
|
19407
20002
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
@@ -19414,6 +20009,7 @@ var Launcher = class {
|
|
|
19414
20009
|
cwd: req.cwd,
|
|
19415
20010
|
fds: req.fds,
|
|
19416
20011
|
fs: stack.fs,
|
|
20012
|
+
noLinks: stack.noLinks,
|
|
19417
20013
|
...this.prefixes.length > 0 && !stack.writer ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
19418
20014
|
createWorker: this.createWorker,
|
|
19419
20015
|
onError: req.report,
|
|
@@ -19491,6 +20087,11 @@ var Launcher = class {
|
|
|
19491
20087
|
return { shownPid: this.jobs.shown(req.ppid), ...ppid !== void 0 ? { ppid } : {} };
|
|
19492
20088
|
}
|
|
19493
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
|
+
}
|
|
19494
20095
|
this.jobs.remove(pid);
|
|
19495
20096
|
this.described.delete(pid);
|
|
19496
20097
|
const spent = this.spent.get(pid);
|
|
@@ -19606,10 +20207,11 @@ var Launcher = class {
|
|
|
19606
20207
|
const root = member && rootOf(member).pid;
|
|
19607
20208
|
return root !== void 0 && this.running(root) ? root : INIT_PID;
|
|
19608
20209
|
};
|
|
20210
|
+
const superseded = new Set([...members.values()].map((m) => m.execParent));
|
|
19609
20211
|
const listed = [];
|
|
19610
20212
|
for (const member of members.values()) {
|
|
19611
20213
|
const described2 = this.described.get(member.pid);
|
|
19612
|
-
if (member.execed || !described2) continue;
|
|
20214
|
+
if (member.execed && superseded.has(member.pid) || !described2) continue;
|
|
19613
20215
|
const cred = this.credOf(member.pid);
|
|
19614
20216
|
if (!maySee(viewer, cred)) continue;
|
|
19615
20217
|
const root = rootOf(member);
|
|
@@ -19794,7 +20396,7 @@ var Launcher = class {
|
|
|
19794
20396
|
}
|
|
19795
20397
|
signalMasksOf(pid) {
|
|
19796
20398
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
19797
|
-
const blocked = this.blockedBy(pid);
|
|
20399
|
+
const [blocked] = this.blockedBy(pid);
|
|
19798
20400
|
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
19799
20401
|
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
19800
20402
|
}
|
|
@@ -19802,14 +20404,14 @@ var Launcher = class {
|
|
|
19802
20404
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
19803
20405
|
}
|
|
19804
20406
|
blockedBy(pid) {
|
|
19805
|
-
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
20407
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? [0, 0];
|
|
19806
20408
|
}
|
|
19807
20409
|
ignoredBy(pid, fork = false) {
|
|
19808
20410
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
19809
20411
|
}
|
|
19810
20412
|
kill(pid, sig, sender, from) {
|
|
19811
20413
|
const session = from === void 0 ? void 0 : this.jobs.sidOf(from);
|
|
19812
|
-
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;
|
|
19813
20415
|
if (pid === -1) {
|
|
19814
20416
|
const sender2 = from === void 0 ? void 0 : this.imageOf(from);
|
|
19815
20417
|
return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may);
|
|
@@ -20172,19 +20774,20 @@ var Launcher = class {
|
|
|
20172
20774
|
}
|
|
20173
20775
|
stackFor(tag) {
|
|
20174
20776
|
if (!this.isWriter(tag)) {
|
|
20175
|
-
return {
|
|
20777
|
+
return {
|
|
20778
|
+
fs: this.processFs,
|
|
20779
|
+
noLinks: this.noLinksFs,
|
|
20780
|
+
nodes: this.nodes,
|
|
20781
|
+
unlinked: this.unlinked,
|
|
20782
|
+
writer: false
|
|
20783
|
+
};
|
|
20176
20784
|
}
|
|
20177
20785
|
this.writers ??= this.writerStack();
|
|
20178
20786
|
return this.writers;
|
|
20179
20787
|
}
|
|
20180
20788
|
writerStack() {
|
|
20181
|
-
const
|
|
20182
|
-
const fs =
|
|
20183
|
-
this.owners ? this.freshModules.wrap(watched) : watched,
|
|
20184
|
-
async () => new Set((await this.commands()).keys()),
|
|
20185
|
-
(dir) => this.userCommandDir(dir),
|
|
20186
|
-
this.owners
|
|
20187
|
-
);
|
|
20789
|
+
const mounted = this.mounts.wrap(this.unguardedRoot);
|
|
20790
|
+
const fs = this.commandFs(this.rooted(mounted));
|
|
20188
20791
|
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
20189
20792
|
nodes.keepsOnDisk = true;
|
|
20190
20793
|
this.openFiles.add(nodes);
|
|
@@ -20199,7 +20802,32 @@ var Launcher = class {
|
|
|
20199
20802
|
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
20200
20803
|
}
|
|
20201
20804
|
);
|
|
20202
|
-
|
|
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));
|
|
20203
20831
|
}
|
|
20204
20832
|
async starting(argv, dir, account, tag) {
|
|
20205
20833
|
this.resetCatalogs();
|
|
@@ -20281,8 +20909,10 @@ var Launcher = class {
|
|
|
20281
20909
|
const report = (message3) => stderr(encoder7.encode(`${message3}
|
|
20282
20910
|
`));
|
|
20283
20911
|
if (!planned) {
|
|
20284
|
-
|
|
20285
|
-
|
|
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) };
|
|
20286
20916
|
}
|
|
20287
20917
|
const fds = new FdTable();
|
|
20288
20918
|
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|