@ai-ecoverse/slicc-kernel 1.57.0 → 1.58.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 +4 -3
- package/dist/driver-worker.js +3 -0
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js +3 -0
- package/dist/driver.js.map +2 -2
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +290 -111
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +3 -0
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +459 -107
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +290 -111
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +459 -107
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
|
@@ -533,10 +533,26 @@ function pathInode(path) {
|
|
|
533
533
|
}
|
|
534
534
|
return h;
|
|
535
535
|
}
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
|
|
536
|
+
function inoKey(st) {
|
|
537
|
+
return "ino" in st && typeof st.ino === "number" ? st.ino % 4294967296 | 0 : 0;
|
|
538
|
+
}
|
|
539
|
+
function pathHash(path) {
|
|
540
|
+
let h = 2166136261;
|
|
541
|
+
for (let i = 0; i < path.length; i++) h = Math.imul(h ^ path.charCodeAt(i), 16777619);
|
|
542
|
+
return h === 0 ? 1 : h;
|
|
543
|
+
}
|
|
544
|
+
function index(map, key, path) {
|
|
545
|
+
const paths = map.get(key) ?? /* @__PURE__ */ new Set();
|
|
546
|
+
paths.add(path);
|
|
547
|
+
map.set(key, paths);
|
|
548
|
+
}
|
|
549
|
+
function cachingBridge(bridge, now = () => performance.now(), shared) {
|
|
550
|
+
const blind = shared !== void 0 && shared.length * 4 < SHARED_IDS_BYTES;
|
|
551
|
+
const cache = new StatCache(blind ? void 0 : shared);
|
|
552
|
+
const { stats, lstats } = cache;
|
|
539
553
|
const cached = (map, path, get) => {
|
|
554
|
+
if (blind) return get();
|
|
555
|
+
cache.fresh();
|
|
540
556
|
let hit = map.get(path);
|
|
541
557
|
if (hit === void 0 || "until" in hit && hit.until <= now()) {
|
|
542
558
|
try {
|
|
@@ -544,22 +560,29 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
544
560
|
} catch (e) {
|
|
545
561
|
hit = { error: e, until: now() + MISS_TTL_MS };
|
|
546
562
|
}
|
|
547
|
-
|
|
563
|
+
cache.put(map, path, hit);
|
|
548
564
|
}
|
|
549
565
|
if ("until" in hit) throw hit.error;
|
|
550
566
|
return hit;
|
|
551
567
|
};
|
|
552
|
-
const invalidate = () =>
|
|
553
|
-
|
|
554
|
-
|
|
568
|
+
const invalidate = () => cache.mutated([]);
|
|
569
|
+
const touched = (path, ino) => cache.changed(path, ino);
|
|
570
|
+
const mutating = (op, ...paths) => {
|
|
571
|
+
try {
|
|
572
|
+
return op();
|
|
573
|
+
} finally {
|
|
574
|
+
cache.mutated(paths);
|
|
575
|
+
}
|
|
555
576
|
};
|
|
556
|
-
const
|
|
577
|
+
const rewriting = (p, op, ...also) => {
|
|
578
|
+
const ino = cache.inoOf(p, () => bridge.stat(p));
|
|
557
579
|
try {
|
|
558
580
|
return op();
|
|
559
581
|
} finally {
|
|
560
|
-
|
|
582
|
+
cache.mutated([p, ...also], ino);
|
|
561
583
|
}
|
|
562
584
|
};
|
|
585
|
+
const entry = (p) => [p, p.slice(0, p.lastIndexOf("/")) || "/"];
|
|
563
586
|
return {
|
|
564
587
|
readFile: (p) => bridge.readFile(p),
|
|
565
588
|
readdir: (p) => bridge.readdir(p),
|
|
@@ -567,9 +590,9 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
567
590
|
const list = bridge.readdirStat(p);
|
|
568
591
|
const base = p === "/" ? "" : p;
|
|
569
592
|
for (const [name2, st] of list) {
|
|
570
|
-
if (!st) continue;
|
|
571
|
-
|
|
572
|
-
if (!st.isSymbolicLink)
|
|
593
|
+
if (!st || blind) continue;
|
|
594
|
+
cache.put(lstats, `${base}/${name2}`, st);
|
|
595
|
+
if (!st.isSymbolicLink) cache.put(stats, `${base}/${name2}`, st);
|
|
573
596
|
}
|
|
574
597
|
return list;
|
|
575
598
|
},
|
|
@@ -584,40 +607,42 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
584
607
|
return false;
|
|
585
608
|
}
|
|
586
609
|
},
|
|
587
|
-
writeFile: (p, bytes, open) =>
|
|
588
|
-
mkdir: (p) => mutating(() => bridge.mkdir(p)),
|
|
610
|
+
writeFile: (p, bytes, open) => rewriting(p, () => bridge.writeFile(p, bytes, open), ...entry(p).slice(1)),
|
|
611
|
+
mkdir: (p) => mutating(() => bridge.mkdir(p), ...entry(p)),
|
|
589
612
|
rm: (p) => mutating(() => bridge.rm(p)),
|
|
590
613
|
rename: (from, to) => mutating(() => bridge.rename(from, to)),
|
|
614
|
+
link: (from, to, follow2) => mutating(() => bridge.link(from, to, follow2)),
|
|
591
615
|
unlink: (p) => mutating(() => bridge.unlink(p)),
|
|
592
616
|
rmdir: (p) => mutating(() => bridge.rmdir(p)),
|
|
593
|
-
symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
|
|
594
|
-
chmod: (p, mode) =>
|
|
595
|
-
utimes: (p, a, m) =>
|
|
596
|
-
lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m)),
|
|
617
|
+
symlink: (target, link) => mutating(() => bridge.symlink(target, link), ...entry(link)),
|
|
618
|
+
chmod: (p, mode) => rewriting(p, () => bridge.chmod(p, mode)),
|
|
619
|
+
utimes: (p, a, m) => rewriting(p, () => bridge.utimes(p, a, m)),
|
|
620
|
+
lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m), p),
|
|
597
621
|
...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
|
|
598
622
|
...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
|
|
599
|
-
...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle,
|
|
600
|
-
...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p)) } : {},
|
|
623
|
+
...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle, rewriting) } : {},
|
|
624
|
+
...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p), ...entry(p)) } : {},
|
|
601
625
|
...bridge.pread && bridge.pwrite && bridge.truncate ? {
|
|
602
626
|
pread: bridge.pread.bind(bridge),
|
|
603
|
-
pwrite: (p, at, bytes, transfer) =>
|
|
604
|
-
truncate: (p, size) =>
|
|
627
|
+
pwrite: (p, at, bytes, transfer) => rewriting(p, () => bridge.pwrite?.(p, at, bytes, transfer)),
|
|
628
|
+
truncate: (p, size) => rewriting(p, () => bridge.truncate?.(p, size))
|
|
605
629
|
} : {},
|
|
606
|
-
invalidate
|
|
630
|
+
invalidate,
|
|
631
|
+
touched
|
|
607
632
|
};
|
|
608
633
|
}
|
|
609
|
-
function pinnedIo(bridge, handle,
|
|
634
|
+
function pinnedIo(bridge, handle, rewriting) {
|
|
610
635
|
const io = bridge.pinned(handle);
|
|
611
636
|
const { pread, pwrite, truncate } = io;
|
|
612
637
|
return {
|
|
613
638
|
readFile: (p) => io.readFile(p),
|
|
614
|
-
writeFile: (p, bytes, open) =>
|
|
639
|
+
writeFile: (p, bytes, open) => rewriting(p, () => io.writeFile(p, bytes, open)),
|
|
615
640
|
pread: (p, at, n, version) => pread(p, at, n, version),
|
|
616
|
-
pwrite: (p, at, bytes, transfer) =>
|
|
617
|
-
truncate: (p, size) =>
|
|
641
|
+
pwrite: (p, at, bytes, transfer) => rewriting(p, () => pwrite(p, at, bytes, transfer)),
|
|
642
|
+
truncate: (p, size) => rewriting(p, () => truncate(p, size))
|
|
618
643
|
};
|
|
619
644
|
}
|
|
620
|
-
var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS;
|
|
645
|
+
var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, RING, RING_SIZE, SLOT, SHARED_IDS_BYTES, StatCache;
|
|
621
646
|
var init_wasi_files = __esm({
|
|
622
647
|
"src/process/wasi/wasi-files.ts"() {
|
|
623
648
|
"use strict";
|
|
@@ -807,6 +832,110 @@ var init_wasi_files = __esm({
|
|
|
807
832
|
};
|
|
808
833
|
MAX_LINKS = 40;
|
|
809
834
|
MISS_TTL_MS = 20;
|
|
835
|
+
FS_GEN = 4;
|
|
836
|
+
RING = 8;
|
|
837
|
+
RING_SIZE = 64;
|
|
838
|
+
SLOT = 3;
|
|
839
|
+
SHARED_IDS_BYTES = (RING + RING_SIZE * SLOT) * 4;
|
|
840
|
+
StatCache = class {
|
|
841
|
+
stats = /* @__PURE__ */ new Map();
|
|
842
|
+
lstats = /* @__PURE__ */ new Map();
|
|
843
|
+
byHash = /* @__PURE__ */ new Map();
|
|
844
|
+
byIno = /* @__PURE__ */ new Map();
|
|
845
|
+
shared;
|
|
846
|
+
seen;
|
|
847
|
+
constructor(shared) {
|
|
848
|
+
this.shared = shared;
|
|
849
|
+
this.seen = shared ? Atomics.load(shared, FS_GEN) : 0;
|
|
850
|
+
}
|
|
851
|
+
put(map, path, entry) {
|
|
852
|
+
map.set(path, entry);
|
|
853
|
+
if (!this.shared) return;
|
|
854
|
+
index(this.byHash, pathHash(path), path);
|
|
855
|
+
const ino = inoKey(entry);
|
|
856
|
+
if (ino !== 0) index(this.byIno, ino, path);
|
|
857
|
+
}
|
|
858
|
+
fresh() {
|
|
859
|
+
if (!this.shared) return;
|
|
860
|
+
const now = Atomics.load(this.shared, FS_GEN);
|
|
861
|
+
if (now === this.seen) return;
|
|
862
|
+
this.replay(now);
|
|
863
|
+
this.seen = now;
|
|
864
|
+
}
|
|
865
|
+
changed(path, ino = 0) {
|
|
866
|
+
const key = ino % 4294967296 | 0;
|
|
867
|
+
if (this.shared) {
|
|
868
|
+
const g = this.publish(this.shared, path === void 0 ? 0 : pathHash(path), key);
|
|
869
|
+
this.replay(g - 1);
|
|
870
|
+
this.seen = g;
|
|
871
|
+
if (path === void 0) this.clear();
|
|
872
|
+
else this.drop(pathHash(path), key);
|
|
873
|
+
}
|
|
874
|
+
if (path === void 0) return;
|
|
875
|
+
this.stats.delete(path);
|
|
876
|
+
this.lstats.delete(path);
|
|
877
|
+
}
|
|
878
|
+
mutated(paths, ino = 0) {
|
|
879
|
+
this.clear();
|
|
880
|
+
if (!this.shared) return;
|
|
881
|
+
const key = ino % 4294967296 | 0;
|
|
882
|
+
for (const [i, hash] of (paths.length > 0 ? paths.map(pathHash) : [0]).entries()) {
|
|
883
|
+
this.seen = this.publish(this.shared, hash, i === 0 ? key : 0);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
inoOf(path, look) {
|
|
887
|
+
if (!this.shared) return 0;
|
|
888
|
+
this.fresh();
|
|
889
|
+
const hit = this.stats.get(path);
|
|
890
|
+
if (hit && "ino" in hit && typeof hit.ino === "number") return hit.ino;
|
|
891
|
+
try {
|
|
892
|
+
return look().ino ?? 0;
|
|
893
|
+
} catch {
|
|
894
|
+
return 0;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
publish(shared, hash, ino) {
|
|
898
|
+
const g = Atomics.add(shared, FS_GEN, 1) + 1;
|
|
899
|
+
const at = RING + g % RING_SIZE * SLOT;
|
|
900
|
+
Atomics.store(shared, at, 0);
|
|
901
|
+
Atomics.store(shared, at + 1, hash);
|
|
902
|
+
Atomics.store(shared, at + 2, ino);
|
|
903
|
+
Atomics.store(shared, at, g);
|
|
904
|
+
return g;
|
|
905
|
+
}
|
|
906
|
+
replay(upTo) {
|
|
907
|
+
const shared = this.shared;
|
|
908
|
+
const missed = [];
|
|
909
|
+
for (let g = this.seen + 1; g <= upTo && upTo - this.seen <= RING_SIZE; g++) {
|
|
910
|
+
const at = RING + g % RING_SIZE * SLOT;
|
|
911
|
+
const tag = Atomics.load(shared, at);
|
|
912
|
+
const hash = Atomics.load(shared, at + 1);
|
|
913
|
+
const ino = Atomics.load(shared, at + 2);
|
|
914
|
+
if (tag !== g || hash === 0 || Atomics.load(shared, at) !== g) break;
|
|
915
|
+
missed.push([hash, ino]);
|
|
916
|
+
}
|
|
917
|
+
if (missed.length < upTo - this.seen) this.clear();
|
|
918
|
+
else for (const [hash, ino] of missed) this.drop(hash, ino);
|
|
919
|
+
}
|
|
920
|
+
drop(hash, ino) {
|
|
921
|
+
const paths = [
|
|
922
|
+
...this.byHash.get(hash) ?? [],
|
|
923
|
+
...ino === 0 ? [] : this.byIno.get(ino) ?? []
|
|
924
|
+
];
|
|
925
|
+
for (const path of paths) {
|
|
926
|
+
this.stats.delete(path);
|
|
927
|
+
this.lstats.delete(path);
|
|
928
|
+
}
|
|
929
|
+
this.byHash.delete(hash);
|
|
930
|
+
if (ino !== 0) this.byIno.delete(ino);
|
|
931
|
+
}
|
|
932
|
+
clear() {
|
|
933
|
+
this.stats.clear();
|
|
934
|
+
this.lstats.clear();
|
|
935
|
+
this.byHash.clear();
|
|
936
|
+
this.byIno.clear();
|
|
937
|
+
}
|
|
938
|
+
};
|
|
810
939
|
}
|
|
811
940
|
});
|
|
812
941
|
|
|
@@ -836,6 +965,7 @@ var init_wasi_threads = __esm({
|
|
|
836
965
|
"src/process/wasi/wasi-threads.ts"() {
|
|
837
966
|
"use strict";
|
|
838
967
|
init_protocol();
|
|
968
|
+
init_wasi_files();
|
|
839
969
|
LAST_TID = 0;
|
|
840
970
|
RUNNING = 1;
|
|
841
971
|
MAIN_TID = 1;
|
|
@@ -858,7 +988,7 @@ var init_wasi_threads = __esm({
|
|
|
858
988
|
this.memory = memory;
|
|
859
989
|
this.cap = cap;
|
|
860
990
|
this.tid = tid;
|
|
861
|
-
this.ids = new Int32Array(ids ?? new SharedArrayBuffer(
|
|
991
|
+
this.ids = new Int32Array(ids ?? new SharedArrayBuffer(SHARED_IDS_BYTES));
|
|
862
992
|
if (!ids) Atomics.store(this.ids, LAST_TID, MAIN_TID);
|
|
863
993
|
}
|
|
864
994
|
spawn(arg) {
|
|
@@ -1089,6 +1219,8 @@ var init_wasi_fds = __esm({
|
|
|
1089
1219
|
WasiFds = class {
|
|
1090
1220
|
table = /* @__PURE__ */ new Map();
|
|
1091
1221
|
buffers = /* @__PURE__ */ new Map();
|
|
1222
|
+
byId = /* @__PURE__ */ new Map();
|
|
1223
|
+
ids = /* @__PURE__ */ new Map();
|
|
1092
1224
|
kernel;
|
|
1093
1225
|
fs;
|
|
1094
1226
|
constructor(kernel, fs) {
|
|
@@ -1327,11 +1459,18 @@ var init_wasi_fds = __esm({
|
|
|
1327
1459
|
handed.add(e.file.buffer);
|
|
1328
1460
|
promoted.set(e.file, fd);
|
|
1329
1461
|
}
|
|
1330
|
-
this.table.set(fd, {
|
|
1462
|
+
this.table.set(fd, {
|
|
1463
|
+
type: "kernel",
|
|
1464
|
+
kind: "file",
|
|
1465
|
+
nonblock: false,
|
|
1466
|
+
append: e.file.append,
|
|
1467
|
+
path: e.file.path,
|
|
1468
|
+
ino: this.inoOf(e.file.path)
|
|
1469
|
+
});
|
|
1331
1470
|
}
|
|
1332
1471
|
for (const file of promoted.keys()) {
|
|
1333
1472
|
if (--file.buffer.opens <= 0) {
|
|
1334
|
-
this.
|
|
1473
|
+
this.forget(file.buffer);
|
|
1335
1474
|
this.letGo(file.buffer);
|
|
1336
1475
|
}
|
|
1337
1476
|
}
|
|
@@ -1402,9 +1541,48 @@ var init_wasi_fds = __esm({
|
|
|
1402
1541
|
const { buffer } = e.file;
|
|
1403
1542
|
buffer.flush();
|
|
1404
1543
|
if (--buffer.opens > 0) return;
|
|
1405
|
-
|
|
1544
|
+
this.forget(buffer);
|
|
1406
1545
|
this.letGo(buffer);
|
|
1407
1546
|
}
|
|
1547
|
+
forget(buffer) {
|
|
1548
|
+
for (const [p, b] of [...this.buffers]) if (b === buffer) this.buffers.delete(p);
|
|
1549
|
+
const id = this.ids.get(buffer);
|
|
1550
|
+
if (id !== void 0 && this.byId.get(id) === buffer) this.byId.delete(id);
|
|
1551
|
+
this.ids.delete(buffer);
|
|
1552
|
+
}
|
|
1553
|
+
know(buffer, id) {
|
|
1554
|
+
if (this.ids.has(buffer)) return;
|
|
1555
|
+
this.ids.set(buffer, id);
|
|
1556
|
+
if (!this.byId.has(id)) this.byId.set(id, buffer);
|
|
1557
|
+
}
|
|
1558
|
+
identity(st) {
|
|
1559
|
+
if (!st || st.ino === void 0 || (st.nlink ?? 1) < 2) return void 0;
|
|
1560
|
+
return `${st.dev ?? 0}:${st.ino}`;
|
|
1561
|
+
}
|
|
1562
|
+
sharing(path, st) {
|
|
1563
|
+
if (st?.ino === void 0) return void 0;
|
|
1564
|
+
const id = `${st.dev ?? 0}:${st.ino}`;
|
|
1565
|
+
if (!this.byId.has(id) && this.identity(st) !== void 0) this.learn();
|
|
1566
|
+
const buffer = this.byId.get(id);
|
|
1567
|
+
if (!buffer) return void 0;
|
|
1568
|
+
this.buffers.set(path, buffer);
|
|
1569
|
+
return buffer;
|
|
1570
|
+
}
|
|
1571
|
+
learn() {
|
|
1572
|
+
for (const [p, buffer] of this.buffers) {
|
|
1573
|
+
if (this.ids.has(buffer) || buffer.isOrphan()) continue;
|
|
1574
|
+
const known = this.identity(this.statOrMissing(p));
|
|
1575
|
+
if (known !== void 0) this.know(buffer, known);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
linked(from, to) {
|
|
1579
|
+
const buffer = this.buffers.get(from);
|
|
1580
|
+
if (!buffer || buffer.isOrphan()) return;
|
|
1581
|
+
const id = this.identity(this.statOrMissing(to));
|
|
1582
|
+
if (id === void 0) return;
|
|
1583
|
+
this.know(buffer, id);
|
|
1584
|
+
if (!this.buffers.has(to)) this.buffers.set(to, buffer);
|
|
1585
|
+
}
|
|
1408
1586
|
letGo(buffer) {
|
|
1409
1587
|
this.fs.hold?.(buffer.path, false, true, buffer.handle);
|
|
1410
1588
|
}
|
|
@@ -1430,32 +1608,63 @@ var init_wasi_fds = __esm({
|
|
|
1430
1608
|
for (const [p, buffer] of this.buffers) if (within(p, path)) buffer.flush();
|
|
1431
1609
|
if (this.shared) this.kernel.call({ op: "fd-path-flush", path });
|
|
1432
1610
|
}
|
|
1433
|
-
|
|
1434
|
-
this.buffers.
|
|
1611
|
+
holdsUnder(path) {
|
|
1612
|
+
for (const p of this.buffers.keys()) if (within(p, path)) return true;
|
|
1613
|
+
return false;
|
|
1614
|
+
}
|
|
1615
|
+
unlinking(path, linked) {
|
|
1616
|
+
const buffer = this.buffers.get(path);
|
|
1617
|
+
if (buffer && this.survives(buffer, linked)) buffer.flush();
|
|
1618
|
+
else buffer?.keep();
|
|
1435
1619
|
if (this.shared) this.kernel.call({ op: "fd-path-unlinking", path });
|
|
1436
1620
|
}
|
|
1437
|
-
unlinked(path) {
|
|
1621
|
+
unlinked(path, linked) {
|
|
1438
1622
|
if (this.shared) this.kernel.call({ op: "fd-path-unlinked", path });
|
|
1439
1623
|
const buffer = this.buffers.get(path);
|
|
1440
1624
|
if (!buffer) return;
|
|
1441
|
-
|
|
1625
|
+
this.detach(buffer, linked);
|
|
1442
1626
|
this.buffers.delete(path);
|
|
1443
1627
|
}
|
|
1444
|
-
|
|
1628
|
+
inoOf(path) {
|
|
1629
|
+
try {
|
|
1630
|
+
return this.fs.stat(path).ino;
|
|
1631
|
+
} catch {
|
|
1632
|
+
return void 0;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
survives(buffer, linked) {
|
|
1636
|
+
return linked !== void 0 && buffer.handle !== void 0;
|
|
1637
|
+
}
|
|
1638
|
+
detach(buffer, linked) {
|
|
1639
|
+
if (this.survives(buffer, linked)) {
|
|
1640
|
+
const id = this.identity(linked);
|
|
1641
|
+
if (id !== void 0) this.know(buffer, id);
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
buffer.orphan();
|
|
1645
|
+
this.forget(buffer);
|
|
1646
|
+
}
|
|
1647
|
+
renamed(from, to, replacedLinked) {
|
|
1445
1648
|
if (from === to) return;
|
|
1446
1649
|
if (this.shared) this.kernel.call({ op: "fd-path-renamed", from, to });
|
|
1650
|
+
for (const e of this.table.values()) {
|
|
1651
|
+
if (e.type === "kernel" && e.path !== void 0 && within(e.path, from)) {
|
|
1652
|
+
e.path = to + e.path.slice(from.length);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1447
1655
|
const moved = [];
|
|
1448
1656
|
for (const [p, buffer] of this.buffers) {
|
|
1449
1657
|
if (within(p, from)) moved.push([p, buffer]);
|
|
1450
1658
|
else if (within(p, to)) {
|
|
1451
|
-
|
|
1659
|
+
this.detach(buffer, replacedLinked);
|
|
1452
1660
|
this.buffers.delete(p);
|
|
1453
1661
|
}
|
|
1454
1662
|
}
|
|
1663
|
+
for (const [p] of moved) this.buffers.delete(p);
|
|
1455
1664
|
for (const [p, buffer] of moved) {
|
|
1456
|
-
|
|
1457
|
-
buffer.path
|
|
1458
|
-
this.buffers.set(
|
|
1665
|
+
const next2 = to + p.slice(from.length);
|
|
1666
|
+
if (buffer.path === p) buffer.path = next2;
|
|
1667
|
+
this.buffers.set(next2, buffer);
|
|
1459
1668
|
}
|
|
1460
1669
|
}
|
|
1461
1670
|
resolve(dirfd, path) {
|
|
@@ -1498,6 +1707,7 @@ var init_wasi_fds = __esm({
|
|
|
1498
1707
|
this.buffers.delete(path);
|
|
1499
1708
|
buffer = void 0;
|
|
1500
1709
|
}
|
|
1710
|
+
buffer ??= this.sharing(path, existing);
|
|
1501
1711
|
if (buffer) {
|
|
1502
1712
|
if (oflags & OFLAGS.TRUNC) buffer.truncate(0);
|
|
1503
1713
|
} else {
|
|
@@ -1511,6 +1721,8 @@ var init_wasi_fds = __esm({
|
|
|
1511
1721
|
buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
|
|
1512
1722
|
buffer.handle = handle;
|
|
1513
1723
|
this.buffers.set(path, buffer);
|
|
1724
|
+
const id = this.identity(st);
|
|
1725
|
+
if (id !== void 0) this.know(buffer, id);
|
|
1514
1726
|
}
|
|
1515
1727
|
buffer.opens++;
|
|
1516
1728
|
return new LocalFile(buffer, readable2, writable2, (fdflags & FDFLAGS.APPEND) !== 0);
|
|
@@ -1522,7 +1734,10 @@ var init_wasi_fds = __esm({
|
|
|
1522
1734
|
const made = !existing && this.createNew(path, oflags);
|
|
1523
1735
|
const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
|
|
1524
1736
|
const fd = this.kernel.sys.openVfs(path, flags, 0, truncate ? { truncate } : {});
|
|
1525
|
-
|
|
1737
|
+
const was = existing && this.inoOf(path);
|
|
1738
|
+
if (truncate) this.fs.touched?.(path, was);
|
|
1739
|
+
const ino = existing ? was : this.inoOf(path);
|
|
1740
|
+
this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append, path, ino });
|
|
1526
1741
|
if (append) this.publishFlags(fd, { nonblock: false, append });
|
|
1527
1742
|
this.bump();
|
|
1528
1743
|
return fd;
|
|
@@ -1841,6 +2056,16 @@ var init_wasi_termios = __esm({
|
|
|
1841
2056
|
});
|
|
1842
2057
|
|
|
1843
2058
|
// src/process/wasi/wasi-host.ts
|
|
2059
|
+
function linkedOf(st) {
|
|
2060
|
+
return (st.nlink ?? 1) > 1 ? st : void 0;
|
|
2061
|
+
}
|
|
2062
|
+
function linkedElsewhere(fs, path) {
|
|
2063
|
+
try {
|
|
2064
|
+
return linkedOf(fs.lstat(path));
|
|
2065
|
+
} catch {
|
|
2066
|
+
return void 0;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
1844
2069
|
function filetypeOf(s) {
|
|
1845
2070
|
if (!s) return FILETYPE.UNKNOWN;
|
|
1846
2071
|
if (s.isSymbolicLink) return FILETYPE.SYMBOLIC_LINK;
|
|
@@ -1852,6 +2077,7 @@ function filestatOf(path, s) {
|
|
|
1852
2077
|
filetype: filetypeOf(s),
|
|
1853
2078
|
size: BigInt(s.size),
|
|
1854
2079
|
ino: s.ino !== void 0 ? BigInt(s.ino) : pathInode(path),
|
|
2080
|
+
...s.nlink !== void 0 ? { nlink: BigInt(s.nlink) } : {},
|
|
1855
2081
|
mtimeNs: BigInt(Math.round(s.mtimeMs ?? 0)) * NS_PER_MS
|
|
1856
2082
|
};
|
|
1857
2083
|
}
|
|
@@ -1902,6 +2128,7 @@ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, S_IFIFO, DEFAULT_UMASK, MONOT
|
|
|
1902
2128
|
var init_wasi_host = __esm({
|
|
1903
2129
|
"src/process/wasi/wasi-host.ts"() {
|
|
1904
2130
|
"use strict";
|
|
2131
|
+
init_physical_path();
|
|
1905
2132
|
init_cred();
|
|
1906
2133
|
init_wasi_abi();
|
|
1907
2134
|
init_wasi_fds();
|
|
@@ -2211,17 +2438,20 @@ var init_wasi_host = __esm({
|
|
|
2211
2438
|
path_remove_directory: (dirfd, p, l) => void o.fs.rmdir(at(dirfd, p, l)),
|
|
2212
2439
|
path_unlink_file: (dirfd, p, l) => {
|
|
2213
2440
|
const path = at(dirfd, p, l);
|
|
2214
|
-
|
|
2215
|
-
|
|
2441
|
+
const st = o.fs.lstat(path);
|
|
2442
|
+
if (st.isDirectory) throw new WasiError("EISDIR");
|
|
2443
|
+
const linked = linkedOf(st);
|
|
2444
|
+
fds.unlinking(path, linked);
|
|
2216
2445
|
o.fs.unlink(path);
|
|
2217
|
-
fds.unlinked(path);
|
|
2446
|
+
fds.unlinked(path, linked);
|
|
2218
2447
|
},
|
|
2219
2448
|
path_rename: (fd, p, l, fd2, p2, l2) => {
|
|
2220
2449
|
const from = at(fd, p, l);
|
|
2221
2450
|
const to = at(fd2, p2, l2);
|
|
2222
2451
|
fds.flushPath(from);
|
|
2452
|
+
const replaced = fds.holdsUnder(to) ? linkedElsewhere(o.fs, to) : void 0;
|
|
2223
2453
|
o.fs.rename(from, to);
|
|
2224
|
-
fds.renamed(from, to);
|
|
2454
|
+
fds.renamed(from, to, replaced);
|
|
2225
2455
|
},
|
|
2226
2456
|
path_symlink: (tp, tl, dirfd, p, l) => void o.fs.symlink(mem.string(tp, tl), at(dirfd, p, l)),
|
|
2227
2457
|
path_readlink: (dirfd, p, l, buf, len, used) => {
|
|
@@ -2230,7 +2460,17 @@ var init_wasi_host = __esm({
|
|
|
2230
2460
|
mem.bytes(buf, n).set(target.subarray(0, n));
|
|
2231
2461
|
mem.view().setUint32(used, n, true);
|
|
2232
2462
|
},
|
|
2233
|
-
path_link: () =>
|
|
2463
|
+
path_link: (fd, lookup, p, l, fd2, p2, l2) => {
|
|
2464
|
+
const from = at(fd, p, l);
|
|
2465
|
+
const to = at(fd2, p2, l2);
|
|
2466
|
+
const follow2 = (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0;
|
|
2467
|
+
const source = follow2 ? physicalPath(o.fs, from) : from;
|
|
2468
|
+
fds.flushPath(from);
|
|
2469
|
+
if (source !== from) fds.flushPath(source);
|
|
2470
|
+
o.fs.link(from, to, follow2);
|
|
2471
|
+
fds.linked(from, to);
|
|
2472
|
+
if (source !== from) fds.linked(source, to);
|
|
2473
|
+
}
|
|
2234
2474
|
};
|
|
2235
2475
|
}
|
|
2236
2476
|
socket(fd) {
|
|
@@ -2316,11 +2556,29 @@ var init_wasi_host = __esm({
|
|
|
2316
2556
|
if (!kernel.sys.pread) throw new WasiError("ESPIPE");
|
|
2317
2557
|
return kernel.sys.pread(fd, Math.min(max, MAX_READ), at);
|
|
2318
2558
|
},
|
|
2319
|
-
pwrite: (body, at) => kernel.call({ op: "fd-pwrite", fd, offset: at, body }),
|
|
2559
|
+
pwrite: (body, at) => this.changed(fd, e, kernel.call({ op: "fd-pwrite", fd, offset: at, body })),
|
|
2320
2560
|
size: () => this.kernelStat(fd).size,
|
|
2321
|
-
truncate: (size) => void kernel.call({ op: "fd-resize", fd, size })
|
|
2561
|
+
truncate: (size) => this.changed(fd, e, void kernel.call({ op: "fd-resize", fd, size }))
|
|
2322
2562
|
};
|
|
2323
2563
|
}
|
|
2564
|
+
unnamed = /* @__PURE__ */ new WeakSet();
|
|
2565
|
+
changed(fd, e, result) {
|
|
2566
|
+
if (e.path === void 0 && !this.unnamed.has(e)) this.learnPath(fd, e);
|
|
2567
|
+
this.o.fs.touched?.(e.path, e.ino);
|
|
2568
|
+
return result;
|
|
2569
|
+
}
|
|
2570
|
+
learnPath(fd, e) {
|
|
2571
|
+
this.unnamed.add(e);
|
|
2572
|
+
let path;
|
|
2573
|
+
try {
|
|
2574
|
+
const st = this.kernelStat(fd);
|
|
2575
|
+
path = st.orphan ? void 0 : st.path;
|
|
2576
|
+
if (path !== void 0) e.ino = this.o.fs.stat(path).ino;
|
|
2577
|
+
} catch {
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
e.path = path;
|
|
2581
|
+
}
|
|
2324
2582
|
kernelStat(fd) {
|
|
2325
2583
|
return this.o.kernel.call({ op: "fd-vfs-stat", fd });
|
|
2326
2584
|
}
|
|
@@ -2329,7 +2587,8 @@ var init_wasi_host = __esm({
|
|
|
2329
2587
|
const e = this.fds.get(fd);
|
|
2330
2588
|
if (e.type === "kernel") {
|
|
2331
2589
|
try {
|
|
2332
|
-
|
|
2590
|
+
const n = this.o.kernel.sys.write(fd, data, { nonblock: e.nonblock });
|
|
2591
|
+
return this.fds.kind(fd, e) === "file" ? this.changed(fd, e, n) : n;
|
|
2333
2592
|
} catch (err) {
|
|
2334
2593
|
const broken = err.code === "EPIPE";
|
|
2335
2594
|
if (broken && this.fds.kind(fd, e) !== "socket") throw new WasiExit(SIGPIPE_EXIT);
|
|
@@ -2415,7 +2674,7 @@ var init_wasi_host = __esm({
|
|
|
2415
2674
|
v.setBigUint64(ptr, 1n, true);
|
|
2416
2675
|
v.setBigUint64(ptr + 8, f.ino, true);
|
|
2417
2676
|
v.setUint8(ptr + 16, f.filetype);
|
|
2418
|
-
v.setBigUint64(ptr + 24, 1n, true);
|
|
2677
|
+
v.setBigUint64(ptr + 24, f.nlink ?? 1n, true);
|
|
2419
2678
|
v.setBigUint64(ptr + 32, f.size, true);
|
|
2420
2679
|
v.setBigUint64(ptr + 40, f.mtimeNs, true);
|
|
2421
2680
|
v.setBigUint64(ptr + 48, f.mtimeNs, true);
|
|
@@ -3025,8 +3284,8 @@ var init_sync_sab_wire = __esm({
|
|
|
3025
3284
|
});
|
|
3026
3285
|
|
|
3027
3286
|
// src/process/js/async-sab.ts
|
|
3028
|
-
async function changed(header,
|
|
3029
|
-
const waited = waitAsync(header,
|
|
3287
|
+
async function changed(header, index3, seen, waitAsync = defaultWaitAsync) {
|
|
3288
|
+
const waited = waitAsync(header, index3, seen);
|
|
3030
3289
|
if (waited.async) await waited.value;
|
|
3031
3290
|
}
|
|
3032
3291
|
function createAsyncSabTransport(sab, port3, waitAsync = defaultWaitAsync) {
|
|
@@ -3180,10 +3439,12 @@ function parseSyncFsStat(json) {
|
|
|
3180
3439
|
...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
|
|
3181
3440
|
...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
|
|
3182
3441
|
...typeof s.ino === "number" ? { ino: s.ino } : {},
|
|
3442
|
+
...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
|
|
3183
3443
|
...typeof s.dev === "number" ? { dev: s.dev } : {},
|
|
3184
3444
|
...s.readonly === true ? { readonly: true } : {},
|
|
3185
3445
|
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
|
|
3186
3446
|
...s.ranged === true ? { ranged: true } : {},
|
|
3447
|
+
...s.linkable === true ? { linkable: true } : {},
|
|
3187
3448
|
...typeof s.version === "string" ? { version: s.version } : {},
|
|
3188
3449
|
...typeof s.uid === "number" ? { uid: s.uid } : {},
|
|
3189
3450
|
...typeof s.gid === "number" ? { gid: s.gid } : {}
|
|
@@ -3204,6 +3465,7 @@ var init_sync_fs_wire = __esm({
|
|
|
3204
3465
|
"mkdir",
|
|
3205
3466
|
"rm",
|
|
3206
3467
|
"rename",
|
|
3468
|
+
"link",
|
|
3207
3469
|
"unlink",
|
|
3208
3470
|
"rmdir",
|
|
3209
3471
|
"symlink",
|
|
@@ -3920,7 +4182,7 @@ function openRequest(abs, o) {
|
|
|
3920
4182
|
...o.truncate ? { truncate: true } : {}
|
|
3921
4183
|
};
|
|
3922
4184
|
}
|
|
3923
|
-
function
|
|
4185
|
+
function index2(n, what) {
|
|
3924
4186
|
if (!Number.isSafeInteger(n) || n < 0) throw new JsCallError("EINVAL", what);
|
|
3925
4187
|
}
|
|
3926
4188
|
var CHUNK2, MAX_IO, O_WRONLY3, O_RDWR3, O_APPEND3;
|
|
@@ -4220,6 +4482,9 @@ function createSyncFsSabBridge(transport, opts = {}) {
|
|
|
4220
4482
|
rename: (from, to) => {
|
|
4221
4483
|
run({ op: "rename", path: from, arg2: to }, from);
|
|
4222
4484
|
},
|
|
4485
|
+
link: (from, to, follow2) => {
|
|
4486
|
+
run({ op: "link", path: from, arg2: to, ...follow2 ? { mode: 1 } : {} }, from);
|
|
4487
|
+
},
|
|
4223
4488
|
unlink: (path) => {
|
|
4224
4489
|
run({ op: "unlink", path }, path);
|
|
4225
4490
|
},
|
|
@@ -4284,7 +4549,7 @@ function syncOps(kernel, shared) {
|
|
|
4284
4549
|
return got;
|
|
4285
4550
|
};
|
|
4286
4551
|
const read2 = (fd, max = CHUNK2) => {
|
|
4287
|
-
|
|
4552
|
+
index2(max, "read");
|
|
4288
4553
|
const emulated = readDevice(info(fd), max, shared.random);
|
|
4289
4554
|
if (emulated) return emulated;
|
|
4290
4555
|
const r = kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
|
|
@@ -4362,8 +4627,8 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4362
4627
|
return kernel.json({ op: "fd-vfs-stat", fd }).size;
|
|
4363
4628
|
},
|
|
4364
4629
|
read(position, length) {
|
|
4365
|
-
|
|
4366
|
-
|
|
4630
|
+
index2(position, "read");
|
|
4631
|
+
index2(length, "read");
|
|
4367
4632
|
const parts = [];
|
|
4368
4633
|
let got = 0;
|
|
4369
4634
|
do {
|
|
@@ -4378,7 +4643,7 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4378
4643
|
return joined(parts, got);
|
|
4379
4644
|
},
|
|
4380
4645
|
write(position, data) {
|
|
4381
|
-
|
|
4646
|
+
index2(position, "write");
|
|
4382
4647
|
let at = 0;
|
|
4383
4648
|
do {
|
|
4384
4649
|
live();
|
|
@@ -4392,7 +4657,7 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4392
4657
|
},
|
|
4393
4658
|
truncate(size) {
|
|
4394
4659
|
live();
|
|
4395
|
-
|
|
4660
|
+
index2(size, "truncate");
|
|
4396
4661
|
kernel.call({ op: "fd-resize", fd, size });
|
|
4397
4662
|
},
|
|
4398
4663
|
sync() {
|
|
@@ -4423,6 +4688,7 @@ function syncPathOps(kernel, resolve, statOf, open) {
|
|
|
4423
4688
|
rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
|
|
4424
4689
|
unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
|
|
4425
4690
|
rename: (from, to) => void kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
|
|
4691
|
+
link: (from, to) => void kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
|
|
4426
4692
|
symlink: (target, path) => void kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
|
|
4427
4693
|
readlink: (path) => String(kernel.json({ op: "readlink", path: resolve(path) })),
|
|
4428
4694
|
readFile(path) {
|
|
@@ -4788,7 +5054,7 @@ function createContext(o) {
|
|
|
4788
5054
|
return got;
|
|
4789
5055
|
};
|
|
4790
5056
|
const read2 = async (fd, max = CHUNK2, signal) => {
|
|
4791
|
-
|
|
5057
|
+
index2(max, "read");
|
|
4792
5058
|
const emulated = readDevice(await info(fd), max, random);
|
|
4793
5059
|
if (emulated) return emulated;
|
|
4794
5060
|
return readPipe(kernel, fd, Math.min(max, MAX_IO), signal);
|
|
@@ -4935,8 +5201,8 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4935
5201
|
return s.size;
|
|
4936
5202
|
},
|
|
4937
5203
|
async read(position, length) {
|
|
4938
|
-
|
|
4939
|
-
|
|
5204
|
+
index2(position, "read");
|
|
5205
|
+
index2(length, "read");
|
|
4940
5206
|
const parts = [];
|
|
4941
5207
|
let got = 0;
|
|
4942
5208
|
do {
|
|
@@ -4951,7 +5217,7 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4951
5217
|
return joined(parts, got);
|
|
4952
5218
|
},
|
|
4953
5219
|
async write(position, data) {
|
|
4954
|
-
|
|
5220
|
+
index2(position, "write");
|
|
4955
5221
|
let at = 0;
|
|
4956
5222
|
do {
|
|
4957
5223
|
live();
|
|
@@ -4965,7 +5231,7 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4965
5231
|
},
|
|
4966
5232
|
async truncate(size) {
|
|
4967
5233
|
live();
|
|
4968
|
-
|
|
5234
|
+
index2(size, "truncate");
|
|
4969
5235
|
await kernel.call({ op: "fd-resize", fd, size });
|
|
4970
5236
|
},
|
|
4971
5237
|
async sync() {
|
|
@@ -5019,6 +5285,7 @@ function pathOps(kernel, resolve, statOf, open) {
|
|
|
5019
5285
|
rm: async (path) => void await kernel.call({ op: "rm", path: resolve(path) }),
|
|
5020
5286
|
unlink: async (path) => void await kernel.call({ op: "unlink", path: resolve(path) }),
|
|
5021
5287
|
rename: async (from, to) => void await kernel.call({ op: "rename", path: resolve(from), arg2: resolve(to) }),
|
|
5288
|
+
link: async (from, to) => void await kernel.call({ op: "link", path: resolve(from), arg2: resolve(to) }),
|
|
5022
5289
|
symlink: async (target, path) => void await kernel.call({ op: "symlink", path: resolve(path), arg2: target }),
|
|
5023
5290
|
readlink: async (path) => String(await kernel.json({ op: "readlink", path: resolve(path) })),
|
|
5024
5291
|
async readFile(path) {
|
|
@@ -5270,11 +5537,54 @@ function toMs(v) {
|
|
|
5270
5537
|
if (v === void 0 || v === null) return void 0;
|
|
5271
5538
|
return v instanceof Date ? v.getTime() : v;
|
|
5272
5539
|
}
|
|
5540
|
+
function linkedStates(bridgeOf) {
|
|
5541
|
+
const opens = /* @__PURE__ */ new Map();
|
|
5542
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5543
|
+
const idOf2 = (st) => st?.ino === void 0 || (st.nlink ?? 1) < 2 ? void 0 : `${st.dev}:${st.ino}`;
|
|
5544
|
+
function know(s, id) {
|
|
5545
|
+
s.id = id;
|
|
5546
|
+
if (!byId.has(id)) byId.set(id, s);
|
|
5547
|
+
}
|
|
5548
|
+
function opening(node, on) {
|
|
5549
|
+
const s = node.live;
|
|
5550
|
+
if (!on) {
|
|
5551
|
+
opens.delete(s);
|
|
5552
|
+
if (s.id !== void 0 && byId.get(s.id) === s) byId.delete(s.id);
|
|
5553
|
+
s.id = void 0;
|
|
5554
|
+
return;
|
|
5555
|
+
}
|
|
5556
|
+
opens.set(s, node);
|
|
5557
|
+
const id = idOf2(s.stat);
|
|
5558
|
+
if (id !== void 0) know(s, id);
|
|
5559
|
+
}
|
|
5560
|
+
function sharedWith(node) {
|
|
5561
|
+
const st = node.live.stat;
|
|
5562
|
+
if (st?.ino === void 0) return void 0;
|
|
5563
|
+
const id = `${st.dev}:${st.ino}`;
|
|
5564
|
+
if (!byId.has(id) && idOf2(st) !== void 0) {
|
|
5565
|
+
for (const [s2, other] of opens) {
|
|
5566
|
+
if (s2.id !== void 0 || s2.orphan) continue;
|
|
5567
|
+
let st2;
|
|
5568
|
+
try {
|
|
5569
|
+
st2 = bridgeOf(other).lstat(liveNodePath(other));
|
|
5570
|
+
} catch {
|
|
5571
|
+
}
|
|
5572
|
+
const known = idOf2(st2);
|
|
5573
|
+
if (known !== void 0) know(s2, known);
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
const s = byId.get(id);
|
|
5577
|
+
return s && s !== node.live && !stale(s) ? s : void 0;
|
|
5578
|
+
}
|
|
5579
|
+
const holder = (node) => opens.get(node.live) ?? node;
|
|
5580
|
+
return { opening, sharedWith, know, idOf: idOf2, holder };
|
|
5581
|
+
}
|
|
5273
5582
|
function createHelpers(Fs, ops) {
|
|
5274
5583
|
const bridgeOf = (node) => node.mount.opts.bridge;
|
|
5275
5584
|
const fileIo = (node) => pinnedIo2(bridgeOf(node), node.live.handle);
|
|
5276
5585
|
const dirty = /* @__PURE__ */ new Set();
|
|
5277
5586
|
const handled = /* @__PURE__ */ new Set();
|
|
5587
|
+
const linked = linkedStates(bridgeOf);
|
|
5278
5588
|
function markDirty(node) {
|
|
5279
5589
|
node.live.dirty = true;
|
|
5280
5590
|
dirty.add(node);
|
|
@@ -5282,7 +5592,7 @@ function createHelpers(Fs, ops) {
|
|
|
5282
5592
|
function flushDirty() {
|
|
5283
5593
|
for (const node of [...dirty]) {
|
|
5284
5594
|
const s = node.live;
|
|
5285
|
-
if (!s.dirty || s
|
|
5595
|
+
if (!s.dirty || stale(s)) {
|
|
5286
5596
|
dirty.delete(node);
|
|
5287
5597
|
continue;
|
|
5288
5598
|
}
|
|
@@ -5324,7 +5634,7 @@ function createHelpers(Fs, ops) {
|
|
|
5324
5634
|
return { ...node.live.stat, size };
|
|
5325
5635
|
}
|
|
5326
5636
|
if (!node.live.stat) {
|
|
5327
|
-
const st = call2(() => bridgeOf(node).lstat(liveNodePath(node)));
|
|
5637
|
+
const st = call2(() => bridgeOf(node).lstat(liveNodePath(linked.holder(node))));
|
|
5328
5638
|
node.live.stat = st;
|
|
5329
5639
|
node.mode = modeFromStat(st);
|
|
5330
5640
|
}
|
|
@@ -5337,7 +5647,7 @@ function createHelpers(Fs, ops) {
|
|
|
5337
5647
|
function ensureLoaded(node) {
|
|
5338
5648
|
const s = node.live;
|
|
5339
5649
|
if (s.loaded) return;
|
|
5340
|
-
const bytes = call2(() => fileIo(node).readFile(liveNodePath(node)));
|
|
5650
|
+
const bytes = call2(() => fileIo(node).readFile(liveNodePath(linked.holder(node))));
|
|
5341
5651
|
s.data = bytes;
|
|
5342
5652
|
s.len = bytes.length;
|
|
5343
5653
|
s.loaded = true;
|
|
@@ -5346,7 +5656,7 @@ function createHelpers(Fs, ops) {
|
|
|
5346
5656
|
const s = node.live;
|
|
5347
5657
|
if (s.ranged || !s.ranges) return s.ranged;
|
|
5348
5658
|
const bridge = bridgeOf(node);
|
|
5349
|
-
const path = () => liveNodePath(node);
|
|
5659
|
+
const path = () => liveNodePath(linked.holder(node));
|
|
5350
5660
|
const file = () => fileIo(node);
|
|
5351
5661
|
const io = {
|
|
5352
5662
|
pread: (_, at, n, version) => file().pread(path(), at, n, version),
|
|
@@ -5368,11 +5678,11 @@ function createHelpers(Fs, ops) {
|
|
|
5368
5678
|
}
|
|
5369
5679
|
function flushNode(node) {
|
|
5370
5680
|
const s = node.live;
|
|
5371
|
-
if (!s.dirty || s
|
|
5681
|
+
if (!s.dirty || stale(s) || !(s.data || s.ranged)) return;
|
|
5372
5682
|
if (s.ranged) call2(() => s.ranged?.flush());
|
|
5373
5683
|
else {
|
|
5374
5684
|
const bytes = s.data.slice(0, s.len);
|
|
5375
|
-
call2(() => fileIo(node).writeFile(liveNodePath(node), bytes, true));
|
|
5685
|
+
call2(() => fileIo(node).writeFile(liveNodePath(linked.holder(node)), bytes, true));
|
|
5376
5686
|
}
|
|
5377
5687
|
s.dirty = false;
|
|
5378
5688
|
s.stat = void 0;
|
|
@@ -5420,6 +5730,7 @@ function createHelpers(Fs, ops) {
|
|
|
5420
5730
|
Fs,
|
|
5421
5731
|
bridgeOf,
|
|
5422
5732
|
handled,
|
|
5733
|
+
linked,
|
|
5423
5734
|
call: call2,
|
|
5424
5735
|
metadataCall,
|
|
5425
5736
|
makeNode,
|
|
@@ -5434,6 +5745,33 @@ function createHelpers(Fs, ops) {
|
|
|
5434
5745
|
truncate
|
|
5435
5746
|
};
|
|
5436
5747
|
}
|
|
5748
|
+
function freshStat(h, node) {
|
|
5749
|
+
const { statOf } = h;
|
|
5750
|
+
const st = statOf(node);
|
|
5751
|
+
if (!st.linkable) return st;
|
|
5752
|
+
node.live.stat = void 0;
|
|
5753
|
+
return statOf(node);
|
|
5754
|
+
}
|
|
5755
|
+
function orphaned(h, node, st) {
|
|
5756
|
+
const { bridgeOf } = h;
|
|
5757
|
+
const s = node.live;
|
|
5758
|
+
const nlink = st.nlink ?? 1;
|
|
5759
|
+
let kept = false;
|
|
5760
|
+
try {
|
|
5761
|
+
kept = nlink > 1 && s.handle !== void 0 && bridgeOf(node).kept?.(s.handle) === true;
|
|
5762
|
+
} catch {
|
|
5763
|
+
}
|
|
5764
|
+
if (nlink > 1 && !kept && h.linked.holder(node) !== node) {
|
|
5765
|
+
s.stat = void 0;
|
|
5766
|
+
return;
|
|
5767
|
+
}
|
|
5768
|
+
s.orphan = true;
|
|
5769
|
+
if (!kept) return;
|
|
5770
|
+
s.kept = true;
|
|
5771
|
+
s.stat = { ...st, nlink: nlink - 1 };
|
|
5772
|
+
const id = h.linked.idOf(st);
|
|
5773
|
+
if (id !== void 0) h.linked.know(s, id);
|
|
5774
|
+
}
|
|
5437
5775
|
function createNodeOps(h) {
|
|
5438
5776
|
const { Fs, bridgeOf, call: call2, metadataCall, makeNode, statOf, childPath, flushNode, truncate } = h;
|
|
5439
5777
|
const { ensureLoaded } = h;
|
|
@@ -5464,7 +5802,7 @@ function createNodeOps(h) {
|
|
|
5464
5802
|
dev: st.dev ?? 1,
|
|
5465
5803
|
ino: st.ino ?? inodeOf(liveNodePath(node)),
|
|
5466
5804
|
mode: node.mode,
|
|
5467
|
-
nlink: 1,
|
|
5805
|
+
nlink: st.nlink ?? 1,
|
|
5468
5806
|
uid: owned ? st.uid ?? 0 : 0,
|
|
5469
5807
|
gid: owned ? st.gid ?? 0 : 0,
|
|
5470
5808
|
rdev: 0,
|
|
@@ -5559,14 +5897,14 @@ function createNodeOps(h) {
|
|
|
5559
5897
|
if (node && node.live?.openCount > 0 && Fs.isFile(node.mode)) open = node;
|
|
5560
5898
|
} catch {
|
|
5561
5899
|
}
|
|
5900
|
+
const st = open && freshStat(h, open);
|
|
5562
5901
|
if (open) {
|
|
5563
|
-
statOf(open);
|
|
5564
5902
|
const ranged = h.rangedOf(open);
|
|
5565
5903
|
if (ranged) ranged.pin();
|
|
5566
5904
|
else ensureLoaded(open);
|
|
5567
5905
|
}
|
|
5568
5906
|
call2(() => bridgeOf(parent).unlink(childPath(parent, name2)));
|
|
5569
|
-
if (open) open
|
|
5907
|
+
if (open && st) orphaned(h, open, st);
|
|
5570
5908
|
},
|
|
5571
5909
|
rmdir(parent, name2) {
|
|
5572
5910
|
parent.live.listed = void 0;
|
|
@@ -5614,6 +5952,7 @@ function createStreamOps(h) {
|
|
|
5614
5952
|
try {
|
|
5615
5953
|
const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle);
|
|
5616
5954
|
s.handle = on ? handle : void 0;
|
|
5955
|
+
h.linked.opening(node, on);
|
|
5617
5956
|
if (s.handle === void 0) h.handled.delete(node);
|
|
5618
5957
|
else h.handled.add(node);
|
|
5619
5958
|
} catch {
|
|
@@ -5626,7 +5965,9 @@ function createStreamOps(h) {
|
|
|
5626
5965
|
if (s.openCount === 0 && !s.orphan) {
|
|
5627
5966
|
const bridge = bridgeOf(stream.node);
|
|
5628
5967
|
s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
|
|
5629
|
-
|
|
5968
|
+
const shared = h.linked.sharedWith(stream.node);
|
|
5969
|
+
if (shared) stream.node.live = shared;
|
|
5970
|
+
else rangedOf(stream.node);
|
|
5630
5971
|
}
|
|
5631
5972
|
if ((stream.flags & 3) !== 0) {
|
|
5632
5973
|
try {
|
|
@@ -5948,7 +6289,7 @@ function useLiveChown(Fs) {
|
|
|
5948
6289
|
Fs.chown(target, uid, gid);
|
|
5949
6290
|
};
|
|
5950
6291
|
}
|
|
5951
|
-
var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE;
|
|
6292
|
+
var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, stale;
|
|
5952
6293
|
var init_live_vfs_fs = __esm({
|
|
5953
6294
|
"src/realm/live-vfs-fs.ts"() {
|
|
5954
6295
|
"use strict";
|
|
@@ -5964,6 +6305,7 @@ var init_live_vfs_fs = __esm({
|
|
|
5964
6305
|
SEEK_CUR = 1;
|
|
5965
6306
|
SEEK_END = 2;
|
|
5966
6307
|
EARLY_WHOLE_FILE = 64 * 1024;
|
|
6308
|
+
stale = (s) => !!s.orphan && !s.kept;
|
|
5967
6309
|
}
|
|
5968
6310
|
});
|
|
5969
6311
|
|
|
@@ -8965,6 +9307,13 @@ function procfsBridge(fs, tree) {
|
|
|
8965
9307
|
() => fs.rename(from, to)
|
|
8966
9308
|
),
|
|
8967
9309
|
symlink: (target, link) => readOnly([[link, false]], () => fs.symlink(target, link)),
|
|
9310
|
+
link: (from, to, follow2) => readOnly(
|
|
9311
|
+
[
|
|
9312
|
+
[from, follow2 === true],
|
|
9313
|
+
[to, false]
|
|
9314
|
+
],
|
|
9315
|
+
() => fs.link(from, to, follow2)
|
|
9316
|
+
),
|
|
8968
9317
|
hold: (p, held, open, handle) => {
|
|
8969
9318
|
if (handle !== void 0 && snapshots.delete(handle)) return void 0;
|
|
8970
9319
|
if (!held) return fs.hold?.(p, held, open, handle);
|
|
@@ -9737,8 +10086,8 @@ function readExports(r, s) {
|
|
|
9737
10086
|
for (let i = r.u32(); i > 0; i--) {
|
|
9738
10087
|
const name2 = r.name();
|
|
9739
10088
|
const kind = r.byte();
|
|
9740
|
-
const
|
|
9741
|
-
if (kind === 0) s.info.exports[name2] =
|
|
10089
|
+
const index3 = r.u32();
|
|
10090
|
+
if (kind === 0) s.info.exports[name2] = index3;
|
|
9742
10091
|
}
|
|
9743
10092
|
}
|
|
9744
10093
|
function readElems(r, s) {
|
|
@@ -10041,15 +10390,15 @@ var init_wasix_linker = __esm({
|
|
|
10041
10390
|
return out;
|
|
10042
10391
|
}
|
|
10043
10392
|
allocateClosure() {
|
|
10044
|
-
const
|
|
10045
|
-
growTable(this.table,
|
|
10046
|
-
this.live.add(
|
|
10047
|
-
return
|
|
10393
|
+
const index3 = this.indices.allocate(this.table.length);
|
|
10394
|
+
growTable(this.table, index3 + 1);
|
|
10395
|
+
this.live.add(index3);
|
|
10396
|
+
return index3;
|
|
10048
10397
|
}
|
|
10049
|
-
freeClosure(
|
|
10050
|
-
this.indices?.free(
|
|
10051
|
-
this.live.delete(
|
|
10052
|
-
this.table.set(
|
|
10398
|
+
freeClosure(index3) {
|
|
10399
|
+
this.indices?.free(index3);
|
|
10400
|
+
this.live.delete(index3);
|
|
10401
|
+
this.table.set(index3, null);
|
|
10053
10402
|
}
|
|
10054
10403
|
live = /* @__PURE__ */ new Set();
|
|
10055
10404
|
prepareClosure(record) {
|
|
@@ -10282,12 +10631,12 @@ var init_wasix_linker = __esm({
|
|
|
10282
10631
|
this.indexTable();
|
|
10283
10632
|
const known = this.slots.get(fn);
|
|
10284
10633
|
if (known !== void 0) return known;
|
|
10285
|
-
const
|
|
10286
|
-
growTable(this.table,
|
|
10287
|
-
this.table.set(
|
|
10288
|
-
this.slots.set(fn,
|
|
10289
|
-
this.publisher?.({ kind: "slot", index:
|
|
10290
|
-
return
|
|
10634
|
+
const index3 = this.reserve(1);
|
|
10635
|
+
growTable(this.table, index3 + 1);
|
|
10636
|
+
this.table.set(index3, fn);
|
|
10637
|
+
this.slots.set(fn, index3);
|
|
10638
|
+
this.publisher?.({ kind: "slot", index: index3, handle, name: name2 });
|
|
10639
|
+
return index3;
|
|
10291
10640
|
}
|
|
10292
10641
|
allocate(size, alignment) {
|
|
10293
10642
|
if (size === 0) return 0;
|
|
@@ -10572,11 +10921,11 @@ var init_wasix_sockets = __esm({
|
|
|
10572
10921
|
});
|
|
10573
10922
|
|
|
10574
10923
|
// src/process/wasi/wasix-host.ts
|
|
10575
|
-
function futexWait(view,
|
|
10924
|
+
function futexWait(view, index3, expected, ms, interrupted) {
|
|
10576
10925
|
const deadline = performance.now() + ms;
|
|
10577
10926
|
for (; ; ) {
|
|
10578
10927
|
const slice = interrupted ? Math.min(FUTEX_SLICE_MS, ms) : ms;
|
|
10579
|
-
if (Atomics.wait(view,
|
|
10928
|
+
if (Atomics.wait(view, index3, expected, slice) !== "timed-out") return true;
|
|
10580
10929
|
if (interrupted?.()) return true;
|
|
10581
10930
|
ms = deadline - performance.now();
|
|
10582
10931
|
if (ms <= 0) return false;
|
|
@@ -10705,21 +11054,21 @@ var init_wasix_host = __esm({
|
|
|
10705
11054
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10706
11055
|
this.mem.view().setUint32(out, this.linker.allocateClosure(), true);
|
|
10707
11056
|
},
|
|
10708
|
-
closure_prepare: (backing,
|
|
11057
|
+
closure_prepare: (backing, index3, argTypes, argCount, resultTypes, resultCount, userData) => {
|
|
10709
11058
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10710
11059
|
const params = valueTypes(this.mem.bytes(argTypes, argCount));
|
|
10711
11060
|
const results = valueTypes(this.mem.bytes(resultTypes, resultCount));
|
|
10712
11061
|
if (!params || !results) throw new WasiError("EINVAL");
|
|
10713
11062
|
try {
|
|
10714
|
-
this.linker.prepareClosure({ index:
|
|
11063
|
+
this.linker.prepareClosure({ index: index3, backing, userData, params, results });
|
|
10715
11064
|
} catch (e) {
|
|
10716
11065
|
if (e instanceof DlError) throw new WasiError("EINVAL");
|
|
10717
11066
|
throw e;
|
|
10718
11067
|
}
|
|
10719
11068
|
},
|
|
10720
|
-
closure_free: (
|
|
11069
|
+
closure_free: (index3) => {
|
|
10721
11070
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10722
|
-
this.linker.freeClosure(
|
|
11071
|
+
this.linker.freeClosure(index3);
|
|
10723
11072
|
},
|
|
10724
11073
|
call_dynamic: (...a) => void callDynamic(
|
|
10725
11074
|
{ mem: this.mem, table: () => this.table, types: this.types },
|
|
@@ -11024,10 +11373,10 @@ function parseFunctionNames(payload) {
|
|
|
11024
11373
|
if (end > payload.length) throw new RangeError("truncated name section");
|
|
11025
11374
|
if (id === 1) {
|
|
11026
11375
|
for (let count = leb(); count > 0; count--) {
|
|
11027
|
-
const
|
|
11376
|
+
const index3 = leb();
|
|
11028
11377
|
const length = leb();
|
|
11029
11378
|
if (at + length > end) throw new RangeError("truncated name section");
|
|
11030
|
-
names.set(
|
|
11379
|
+
names.set(index3, decoder3.decode(payload.subarray(at, at + length)));
|
|
11031
11380
|
at += length;
|
|
11032
11381
|
}
|
|
11033
11382
|
}
|
|
@@ -11051,7 +11400,7 @@ function nameFrame(line, module, name2) {
|
|
|
11051
11400
|
}
|
|
11052
11401
|
function sidecarNames(read2, path) {
|
|
11053
11402
|
let names;
|
|
11054
|
-
return (
|
|
11403
|
+
return (index3) => {
|
|
11055
11404
|
if (!names) {
|
|
11056
11405
|
try {
|
|
11057
11406
|
names = parseFunctionNames(read2(path));
|
|
@@ -11059,7 +11408,7 @@ function sidecarNames(read2, path) {
|
|
|
11059
11408
|
names = /* @__PURE__ */ new Map();
|
|
11060
11409
|
}
|
|
11061
11410
|
}
|
|
11062
|
-
return names.get(
|
|
11411
|
+
return names.get(index3);
|
|
11063
11412
|
};
|
|
11064
11413
|
}
|
|
11065
11414
|
var UNNAMED_FRAME, WASM_MODULE;
|
|
@@ -11420,7 +11769,7 @@ async function runWasiProcess(init, port3) {
|
|
|
11420
11769
|
parent: () => identify(transport, init).ppid,
|
|
11421
11770
|
kernel: { sys: traced(stats, "kernel", sys), call: call2 },
|
|
11422
11771
|
fs: procfsBridge(
|
|
11423
|
-
cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
|
|
11772
|
+
cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport)), void 0, threads?.ids),
|
|
11424
11773
|
procTree(call2, id.pid)
|
|
11425
11774
|
),
|
|
11426
11775
|
...descriptors(init, fork, threads)
|
|
@@ -11513,7 +11862,10 @@ async function runWasiThread(init, port3) {
|
|
|
11513
11862
|
ppid: id.ppid,
|
|
11514
11863
|
parent: () => identify(transport, init).ppid,
|
|
11515
11864
|
kernel: { sys, call: call2 },
|
|
11516
|
-
fs: procfsBridge(
|
|
11865
|
+
fs: procfsBridge(
|
|
11866
|
+
cachingBridge(createSyncFsSabBridge(transport), void 0, threads.ids),
|
|
11867
|
+
procTree(call2, id.pid)
|
|
11868
|
+
),
|
|
11517
11869
|
shared: threads.ids
|
|
11518
11870
|
});
|
|
11519
11871
|
const program = await programImports(init.program, host, transport, thread.tid);
|
|
@@ -11625,13 +11977,13 @@ var init_wasi_runtime = __esm({
|
|
|
11625
11977
|
},
|
|
11626
11978
|
unlock: () => this.call({ op: "dl-unlock", owner: this.owner }),
|
|
11627
11979
|
allocate: (floor) => {
|
|
11628
|
-
const
|
|
11980
|
+
const index3 = this.call({ op: "dl-closure", floor });
|
|
11629
11981
|
this.catchUp();
|
|
11630
11982
|
this.bump();
|
|
11631
|
-
return
|
|
11983
|
+
return index3;
|
|
11632
11984
|
},
|
|
11633
|
-
free: (
|
|
11634
|
-
this.call({ op: "dl-closure-free", index:
|
|
11985
|
+
free: (index3) => {
|
|
11986
|
+
this.call({ op: "dl-closure-free", index: index3 });
|
|
11635
11987
|
this.bump();
|
|
11636
11988
|
}
|
|
11637
11989
|
};
|