@ai-ecoverse/slicc-kernel 1.124.13 → 1.125.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/dist/kernel-worker.js +246 -43
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +165 -88
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +246 -43
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +165 -88
- package/dist/process-worker.js.map +4 -4
- package/dist/types/fs/watch.d.ts +19 -0
- package/dist/types/kernel/fd-table.d.ts +1 -0
- package/dist/types/kernel/host.d.ts +1 -0
- package/dist/types/kernel/process.d.ts +4 -1
- package/dist/types/kernel/select.d.ts +1 -0
- package/dist/types/kernel/watch-ops.d.ts +30 -0
- package/dist/types/launcher.d.ts +1 -0
- package/dist/types/process/js/js-context.d.ts +2 -0
- package/dist/types/process/js/js-sync.d.ts +7 -2
- package/dist/types/process/js/js-watch.d.ts +17 -0
- package/dist/types/realm/sync-fs-wire.d.ts +1 -0
- package/package.json +3 -3
package/dist/node.js
CHANGED
|
@@ -930,7 +930,12 @@ function openPipe(capacity) {
|
|
|
930
930
|
}
|
|
931
931
|
},
|
|
932
932
|
close: () => pipe.closeRead(),
|
|
933
|
-
poll: () => ({
|
|
933
|
+
poll: () => ({
|
|
934
|
+
readable: pipe.readReady,
|
|
935
|
+
writable: false,
|
|
936
|
+
hangup: pipe.writersGone,
|
|
937
|
+
nread: pipe.buffered
|
|
938
|
+
}),
|
|
934
939
|
changed: (signal) => pipe.changed(signal),
|
|
935
940
|
identity: pipe
|
|
936
941
|
}),
|
|
@@ -1718,7 +1723,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
1718
1723
|
readable: this.readShut || rx.readReady,
|
|
1719
1724
|
writable: this.writeShut || tx.writeReady,
|
|
1720
1725
|
hangup: rx.writersGone && tx.readersGone,
|
|
1721
|
-
rdhup: rx.writersGone
|
|
1726
|
+
rdhup: rx.writersGone,
|
|
1727
|
+
nread: this.readShut ? 0 : rx.buffered
|
|
1722
1728
|
};
|
|
1723
1729
|
}
|
|
1724
1730
|
changed(signal) {
|
|
@@ -1778,8 +1784,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
1778
1784
|
if (this.state !== "open") throw new KernelError("EINVAL");
|
|
1779
1785
|
if (addr.family !== this.domain) throw new KernelError("EAFNOSUPPORT");
|
|
1780
1786
|
this.failed = void 0;
|
|
1781
|
-
const
|
|
1782
|
-
if (
|
|
1787
|
+
const route2 = viaUplink && addr.family === "inet" ? this.net.uplinkFor(addr.host) : void 0;
|
|
1788
|
+
if (route2) return this.dial(addr, route2);
|
|
1783
1789
|
const target = this.net.target(addr, name2);
|
|
1784
1790
|
if (!this.local) {
|
|
1785
1791
|
if (addr.family === "inet") {
|
|
@@ -1835,9 +1841,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
1835
1841
|
}
|
|
1836
1842
|
}
|
|
1837
1843
|
switch;
|
|
1838
|
-
connectSecure(addr,
|
|
1844
|
+
connectSecure(addr, route2, secure2) {
|
|
1839
1845
|
if (this.state !== "open") throw new KernelError("EISCONN");
|
|
1840
|
-
return this.dial(addr,
|
|
1846
|
+
return this.dial(addr, route2, secure2);
|
|
1841
1847
|
}
|
|
1842
1848
|
upgradeSecure(make) {
|
|
1843
1849
|
if (this.state !== "connected") throw new KernelError("ENOTCONN");
|
|
@@ -1845,7 +1851,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
1845
1851
|
if (this.switch.upgraded || this.writeShut || this.readShut) throw new KernelError("EINVAL");
|
|
1846
1852
|
return this.switch.upgrade(make);
|
|
1847
1853
|
}
|
|
1848
|
-
dial(addr,
|
|
1854
|
+
dial(addr, route2, secure2) {
|
|
1849
1855
|
this.state = "connecting";
|
|
1850
1856
|
const abort = new AbortController();
|
|
1851
1857
|
this.dialing = abort;
|
|
@@ -1853,13 +1859,13 @@ var KernelSocket = class _KernelSocket {
|
|
|
1853
1859
|
const timer = setTimeout(() => {
|
|
1854
1860
|
timedOut = true;
|
|
1855
1861
|
abort.abort(new KernelError("ETIMEDOUT"));
|
|
1856
|
-
},
|
|
1862
|
+
}, route2.timeoutMs ?? DIAL_TIMEOUT_MS);
|
|
1857
1863
|
const abandoned = new Promise((_, reject) => {
|
|
1858
1864
|
abort.signal.addEventListener("abort", () => reject(abort.signal.reason), { once: true });
|
|
1859
1865
|
});
|
|
1860
1866
|
const { host, port } = addr;
|
|
1861
1867
|
const dialled = new Promise(
|
|
1862
|
-
(resolve2) => resolve2(
|
|
1868
|
+
(resolve2) => resolve2(route2.uplink.dial({ network: "tcp", host, port, signal: abort.signal }))
|
|
1863
1869
|
);
|
|
1864
1870
|
dialled.then(
|
|
1865
1871
|
(conn) => abort.signal.aborted && conn.close(),
|
|
@@ -2008,14 +2014,14 @@ var LoopbackNet = class {
|
|
|
2008
2014
|
if (!this.origins) throw new KernelError("ENETUNREACH");
|
|
2009
2015
|
void this.origins(conn, origin).catch(() => conn.close());
|
|
2010
2016
|
}
|
|
2011
|
-
useUplink(
|
|
2012
|
-
this.route =
|
|
2017
|
+
useUplink(route2) {
|
|
2018
|
+
this.route = route2;
|
|
2013
2019
|
}
|
|
2014
2020
|
tlsClient;
|
|
2015
2021
|
uplinkFor(host) {
|
|
2016
|
-
const
|
|
2017
|
-
if (!
|
|
2018
|
-
return this.destination(host) === "uplink" ?
|
|
2022
|
+
const route2 = this.route;
|
|
2023
|
+
if (!route2) return void 0;
|
|
2024
|
+
return this.destination(host) === "uplink" ? route2 : void 0;
|
|
2019
2025
|
}
|
|
2020
2026
|
destination(host) {
|
|
2021
2027
|
return (this.route?.routes ?? LOCAL_ONLY).classify(host);
|
|
@@ -7080,7 +7086,7 @@ function satisfies(version, range2) {
|
|
|
7080
7086
|
}
|
|
7081
7087
|
|
|
7082
7088
|
// src/version.ts
|
|
7083
|
-
var KERNEL_VERSION = true ? "1.
|
|
7089
|
+
var KERNEL_VERSION = true ? "1.125.1" : "0.0.0-dev";
|
|
7084
7090
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7085
7091
|
function procVersion() {
|
|
7086
7092
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9514,6 +9520,8 @@ async function physicalPathAsync(fs, path) {
|
|
|
9514
9520
|
}
|
|
9515
9521
|
|
|
9516
9522
|
// src/fs/watch.ts
|
|
9523
|
+
var WATCH_NOTES_LIMIT = 1e3;
|
|
9524
|
+
var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
9517
9525
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
9518
9526
|
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
9519
9527
|
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
@@ -9523,8 +9531,39 @@ function touches(watcher, changed) {
|
|
|
9523
9531
|
);
|
|
9524
9532
|
}
|
|
9525
9533
|
var REALS_KEPT = 4096;
|
|
9534
|
+
function noted(watch, note) {
|
|
9535
|
+
if (watch.ended) return;
|
|
9536
|
+
if ("ended" in note) {
|
|
9537
|
+
watch.notes.push(note);
|
|
9538
|
+
watch.ended = true;
|
|
9539
|
+
watch.wake?.();
|
|
9540
|
+
return;
|
|
9541
|
+
}
|
|
9542
|
+
if (watch.overflowed) return;
|
|
9543
|
+
if (watch.notes.length >= WATCH_NOTES_LIMIT) {
|
|
9544
|
+
watch.overflowed = true;
|
|
9545
|
+
watch.notes.push({ overflow: true });
|
|
9546
|
+
} else watch.notes.push(note);
|
|
9547
|
+
watch.wake?.();
|
|
9548
|
+
}
|
|
9549
|
+
function route(watch, type, path) {
|
|
9550
|
+
for (const root of watch.roots) if (routed(watch, root, type, path)) return;
|
|
9551
|
+
}
|
|
9552
|
+
function routed(watch, root, type, path) {
|
|
9553
|
+
if (path === root || type === "rename" && root !== "/" && under3(root, path)) {
|
|
9554
|
+
noted(watch, { type, filename: baseOf2(root) });
|
|
9555
|
+
if (type === "rename") noted(watch, { ended: true });
|
|
9556
|
+
return true;
|
|
9557
|
+
}
|
|
9558
|
+
if (parentOf6(path) === root) noted(watch, { type, filename: baseOf2(path) });
|
|
9559
|
+
else if (watch.recursive && under3(path, root)) {
|
|
9560
|
+
noted(watch, { type, filename: path.slice(root === "/" ? 1 : root.length + 1) });
|
|
9561
|
+
} else return false;
|
|
9562
|
+
return true;
|
|
9563
|
+
}
|
|
9526
9564
|
var FsWatchers = class {
|
|
9527
9565
|
watchers = /* @__PURE__ */ new Set();
|
|
9566
|
+
typed = /* @__PURE__ */ new Set();
|
|
9528
9567
|
taps = [];
|
|
9529
9568
|
reals = /* @__PURE__ */ new Map();
|
|
9530
9569
|
reshapes = [];
|
|
@@ -9551,7 +9590,65 @@ var FsWatchers = class {
|
|
|
9551
9590
|
this.watchers.delete(watcher);
|
|
9552
9591
|
};
|
|
9553
9592
|
}
|
|
9593
|
+
typedWatch(root, recursive, alias) {
|
|
9594
|
+
const main = normalizePath(root);
|
|
9595
|
+
const other = alias === void 0 ? main : normalizePath(alias);
|
|
9596
|
+
const watch = {
|
|
9597
|
+
roots: other === main ? [main] : [main, other],
|
|
9598
|
+
recursive,
|
|
9599
|
+
notes: [],
|
|
9600
|
+
overflowed: false,
|
|
9601
|
+
ended: false,
|
|
9602
|
+
wake: void 0
|
|
9603
|
+
};
|
|
9604
|
+
this.typed.add(watch);
|
|
9605
|
+
const close = () => {
|
|
9606
|
+
this.typed.delete(watch);
|
|
9607
|
+
watch.ended = true;
|
|
9608
|
+
watch.wake?.();
|
|
9609
|
+
};
|
|
9610
|
+
return {
|
|
9611
|
+
close,
|
|
9612
|
+
next: async (signal) => {
|
|
9613
|
+
while (watch.notes.length === 0 && !watch.ended && !signal.aborted) {
|
|
9614
|
+
await new Promise((resolve2) => {
|
|
9615
|
+
const done4 = () => {
|
|
9616
|
+
watch.wake = void 0;
|
|
9617
|
+
signal.removeEventListener("abort", done4);
|
|
9618
|
+
resolve2();
|
|
9619
|
+
};
|
|
9620
|
+
watch.wake = done4;
|
|
9621
|
+
signal.addEventListener("abort", done4, { once: true });
|
|
9622
|
+
});
|
|
9623
|
+
}
|
|
9624
|
+
const notes = watch.notes.splice(0);
|
|
9625
|
+
watch.overflowed = false;
|
|
9626
|
+
if (watch.ended) this.typed.delete(watch);
|
|
9627
|
+
return notes.length === 0 && watch.ended ? [{ ended: true }] : notes;
|
|
9628
|
+
}
|
|
9629
|
+
};
|
|
9630
|
+
}
|
|
9631
|
+
covers(path) {
|
|
9632
|
+
for (const watch of this.typed) {
|
|
9633
|
+
for (const root of watch.roots) {
|
|
9634
|
+
if (path === root || parentOf6(path) === root || watch.recursive && under3(path, root))
|
|
9635
|
+
return true;
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
return false;
|
|
9639
|
+
}
|
|
9640
|
+
emit(type, paths) {
|
|
9641
|
+
if (this.typed.size === 0) return;
|
|
9642
|
+
for (const path of paths) {
|
|
9643
|
+
const at = normalizePath(path);
|
|
9644
|
+
for (const watch of [...this.typed]) route(watch, type, at);
|
|
9645
|
+
}
|
|
9646
|
+
}
|
|
9554
9647
|
changed(...paths) {
|
|
9648
|
+
this.report(paths);
|
|
9649
|
+
this.emit("change", paths);
|
|
9650
|
+
}
|
|
9651
|
+
report(paths) {
|
|
9555
9652
|
for (const tap of this.taps) tap(paths);
|
|
9556
9653
|
for (const watcher of this.watchers) {
|
|
9557
9654
|
for (const path of paths) {
|
|
@@ -9571,11 +9668,15 @@ var FsWatchers = class {
|
|
|
9571
9668
|
watcher.notify(paths.length > WATCH_BATCH_LIMIT ? { overflow: true } : { paths });
|
|
9572
9669
|
}
|
|
9573
9670
|
wrap(fs) {
|
|
9574
|
-
const after = (run2, changed) => async (...args) => {
|
|
9671
|
+
const after = (run2, changed, type) => async (...args) => {
|
|
9672
|
+
let done4 = false;
|
|
9575
9673
|
try {
|
|
9576
9674
|
await run2(...args);
|
|
9675
|
+
done4 = true;
|
|
9577
9676
|
} finally {
|
|
9578
|
-
|
|
9677
|
+
const paths = changed(...args);
|
|
9678
|
+
this.report(paths);
|
|
9679
|
+
if (done4) this.emit(type, paths);
|
|
9579
9680
|
}
|
|
9580
9681
|
};
|
|
9581
9682
|
const reals = this.reals;
|
|
@@ -9594,15 +9695,21 @@ var FsWatchers = class {
|
|
|
9594
9695
|
reals.set(at, real);
|
|
9595
9696
|
return real;
|
|
9596
9697
|
};
|
|
9597
|
-
const content = (run2) => async (...args) => {
|
|
9698
|
+
const content = (run2, types) => async (...args) => {
|
|
9699
|
+
const at = normalizePath(args[0]);
|
|
9700
|
+
const fresh2 = this.covers(at) && !await fs.exists(at).catch(() => true);
|
|
9701
|
+
let done4 = false;
|
|
9598
9702
|
try {
|
|
9599
9703
|
await run2(...args);
|
|
9704
|
+
done4 = true;
|
|
9600
9705
|
} finally {
|
|
9601
|
-
const at = normalizePath(args[0]);
|
|
9602
9706
|
const real = await realOf(at);
|
|
9603
|
-
|
|
9707
|
+
const paths = real === at ? [at] : [at, real];
|
|
9708
|
+
this.report(paths);
|
|
9709
|
+
if (done4) for (const type of types(fresh2)) this.emit(type, paths);
|
|
9604
9710
|
}
|
|
9605
9711
|
};
|
|
9712
|
+
const written2 = (fresh2) => fresh2 ? ["rename", "change"] : ["change"];
|
|
9606
9713
|
const reshaping = (run2) => async (...args) => {
|
|
9607
9714
|
this.reshaped();
|
|
9608
9715
|
try {
|
|
@@ -9612,8 +9719,8 @@ var FsWatchers = class {
|
|
|
9612
9719
|
}
|
|
9613
9720
|
};
|
|
9614
9721
|
const overrides = {
|
|
9615
|
-
writeFile: content(fs.writeFile.bind(fs)),
|
|
9616
|
-
...fs.createExclusive ? { createExclusive: content(fs.createExclusive.bind(fs)) } : {},
|
|
9722
|
+
writeFile: content(fs.writeFile.bind(fs), written2),
|
|
9723
|
+
...fs.createExclusive ? { createExclusive: content(fs.createExclusive.bind(fs), () => ["rename"]) } : {},
|
|
9617
9724
|
mkdir: async (path, options) => {
|
|
9618
9725
|
const created3 = [];
|
|
9619
9726
|
if (options?.recursive) {
|
|
@@ -9623,33 +9730,39 @@ var FsWatchers = class {
|
|
|
9623
9730
|
if (created3.length > 0 || !await fs.exists(ancestor)) created3.push(ancestor);
|
|
9624
9731
|
}
|
|
9625
9732
|
}
|
|
9733
|
+
const fresh2 = !options?.recursive || !(this.covers(path) && await fs.exists(path));
|
|
9734
|
+
let done4 = false;
|
|
9626
9735
|
try {
|
|
9627
9736
|
await fs.mkdir(path, options);
|
|
9737
|
+
done4 = true;
|
|
9628
9738
|
} finally {
|
|
9629
|
-
this.
|
|
9739
|
+
this.report([...created3, path]);
|
|
9740
|
+
if (done4) this.emit("rename", fresh2 ? [...created3, path] : created3);
|
|
9630
9741
|
}
|
|
9631
9742
|
},
|
|
9632
|
-
rm: reshaping(after(fs.rm.bind(fs), (path) => [path])),
|
|
9633
|
-
rename: reshaping(after(fs.rename.bind(fs), (from, to) => [from, to])),
|
|
9743
|
+
rm: reshaping(after(fs.rm.bind(fs), (path) => [path], "rename")),
|
|
9744
|
+
rename: reshaping(after(fs.rename.bind(fs), (from, to) => [from, to], "rename")),
|
|
9634
9745
|
link: reshaping(
|
|
9635
9746
|
after(
|
|
9636
9747
|
(from, to, follow2) => fs.link(from, to, follow2),
|
|
9637
|
-
(_from, to) => [to]
|
|
9748
|
+
(_from, to) => [to],
|
|
9749
|
+
"rename"
|
|
9638
9750
|
)
|
|
9639
9751
|
),
|
|
9640
|
-
symlink: reshaping(after(fs.symlink.bind(fs), (_target, path) => [path])),
|
|
9641
|
-
chmod: after(fs.chmod.bind(fs), (path) => [path]),
|
|
9642
|
-
...fs.chown ? { chown: after(fs.chown.bind(fs), (path) => [path]) } : {},
|
|
9643
|
-
utimes: after(fs.utimes.bind(fs), (path) => [path]),
|
|
9752
|
+
symlink: reshaping(after(fs.symlink.bind(fs), (_target, path) => [path], "rename")),
|
|
9753
|
+
chmod: after(fs.chmod.bind(fs), (path) => [path], "change"),
|
|
9754
|
+
...fs.chown ? { chown: after(fs.chown.bind(fs), (path) => [path], "change") } : {},
|
|
9755
|
+
utimes: after(fs.utimes.bind(fs), (path) => [path], "change"),
|
|
9644
9756
|
lutimes: after(
|
|
9645
9757
|
(path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
9646
|
-
(path) => [path]
|
|
9758
|
+
(path) => [path],
|
|
9759
|
+
"change"
|
|
9647
9760
|
)
|
|
9648
9761
|
};
|
|
9649
9762
|
const ranged2 = rangedOps(fs);
|
|
9650
9763
|
if (ranged2) {
|
|
9651
|
-
overrides.pwrite = content(ranged2.pwrite);
|
|
9652
|
-
overrides.truncate = content(ranged2.truncate);
|
|
9764
|
+
overrides.pwrite = content(ranged2.pwrite, () => ["change"]);
|
|
9765
|
+
overrides.truncate = content(ranged2.truncate, () => ["change"]);
|
|
9653
9766
|
}
|
|
9654
9767
|
return new Proxy(fs, {
|
|
9655
9768
|
get(target, key, receiver) {
|
|
@@ -10257,7 +10370,8 @@ var FifoTable = class {
|
|
|
10257
10370
|
poll: () => ({
|
|
10258
10371
|
readable: reads && pipe.readReady,
|
|
10259
10372
|
writable: writes && pipe.writeReady,
|
|
10260
|
-
hangup: reads ? pipe.writersGone : pipe.readersGone
|
|
10373
|
+
hangup: reads ? pipe.writersGone : pipe.readersGone,
|
|
10374
|
+
...reads ? { nread: pipe.buffered } : {}
|
|
10261
10375
|
}),
|
|
10262
10376
|
changed: (signal) => pipe.changed(signal)
|
|
10263
10377
|
});
|
|
@@ -10656,8 +10770,8 @@ var MountTable = class {
|
|
|
10656
10770
|
...error ? { error } : {}
|
|
10657
10771
|
})
|
|
10658
10772
|
);
|
|
10659
|
-
const
|
|
10660
|
-
return [...mounted, ...
|
|
10773
|
+
const noted2 = [...this.notes.values()].filter((note) => !this.mounts.has(note.target));
|
|
10774
|
+
return [...mounted, ...noted2.map((note) => ({ ...note, options: { ...note.options } }))];
|
|
10661
10775
|
}
|
|
10662
10776
|
listed() {
|
|
10663
10777
|
return this.list().filter((entry) => !this.system.has(entry.target));
|
|
@@ -15968,7 +16082,8 @@ var KernelTty = class {
|
|
|
15968
16082
|
poll: () => ({
|
|
15969
16083
|
readable: this.readable.length > 0 || this.hungUp,
|
|
15970
16084
|
writable: true,
|
|
15971
|
-
hangup: this.hungUp
|
|
16085
|
+
hangup: this.hungUp,
|
|
16086
|
+
nread: this.readable.reduce((n, chunk2) => n + (chunk2?.length ?? 0), 0)
|
|
15972
16087
|
}),
|
|
15973
16088
|
changed: (signal) => this.changed(signal),
|
|
15974
16089
|
close: () => {
|
|
@@ -16164,7 +16279,8 @@ var PtyPair = class {
|
|
|
16164
16279
|
poll: () => ({
|
|
16165
16280
|
readable: this.queue.length > 0 || this.slaveGone,
|
|
16166
16281
|
writable: true,
|
|
16167
|
-
hangup: this.slaveGone
|
|
16282
|
+
hangup: this.slaveGone,
|
|
16283
|
+
nread: this.queue.reduce((n, chunk2) => n + chunk2.length, 0)
|
|
16168
16284
|
}),
|
|
16169
16285
|
changed: (signal) => this.changed(signal),
|
|
16170
16286
|
close: () => this.closeMaster(),
|
|
@@ -16446,13 +16562,17 @@ async function runChild(req, deps) {
|
|
|
16446
16562
|
// src/kernel/select.ts
|
|
16447
16563
|
function ready(fds, read, write) {
|
|
16448
16564
|
const hangup = /* @__PURE__ */ new Set();
|
|
16565
|
+
const nread = {};
|
|
16449
16566
|
const pick = (list, dir) => list.filter((fd) => {
|
|
16450
16567
|
const state = pollFile(fds.get(fd).file);
|
|
16451
16568
|
if (state.hangup) hangup.add(fd);
|
|
16452
|
-
|
|
16569
|
+
const picked = state[dir] || state.hangup;
|
|
16570
|
+
if (picked && dir === "readable" && state.nread !== void 0) nread[fd] = state.nread;
|
|
16571
|
+
return picked;
|
|
16453
16572
|
});
|
|
16454
16573
|
const out = { read: pick(read, "readable"), write: pick(write, "writable") };
|
|
16455
16574
|
if (hangup.size > 0) out.hangup = [...hangup];
|
|
16575
|
+
if (Object.keys(nread).length > 0) out.nread = nread;
|
|
16456
16576
|
return out;
|
|
16457
16577
|
}
|
|
16458
16578
|
function interruption(signal) {
|
|
@@ -17447,14 +17567,14 @@ async function connectSecure(proc, socket, host, port, req) {
|
|
|
17447
17567
|
const servername = serverName(req.servername || host);
|
|
17448
17568
|
if (isLoopbackHost(servername) || isLoopbackHost(host)) throw new KernelError("ENOTSUP");
|
|
17449
17569
|
const address = await uplinkAddress(proc, host);
|
|
17450
|
-
const
|
|
17451
|
-
if (!
|
|
17570
|
+
const route2 = proc.net.uplinkFor(address);
|
|
17571
|
+
if (!route2)
|
|
17452
17572
|
throw new KernelError("ENOTSUP", "TLS in the kernel needs a destination the uplink routes");
|
|
17453
17573
|
const support = supportOf(proc.net);
|
|
17454
17574
|
let info;
|
|
17455
17575
|
const { make, abandon } = secure(await prepare(support, req, servername));
|
|
17456
17576
|
try {
|
|
17457
|
-
await socket.connectSecure({ family: "inet", host: address, port },
|
|
17577
|
+
await socket.connectSecure({ family: "inet", host: address, port }, route2, async (conn) => {
|
|
17458
17578
|
info = await conn.upgrade(make);
|
|
17459
17579
|
});
|
|
17460
17580
|
} finally {
|
|
@@ -18665,6 +18785,65 @@ function vfsFile(fs, opts, nodes) {
|
|
|
18665
18785
|
});
|
|
18666
18786
|
}
|
|
18667
18787
|
|
|
18788
|
+
// src/kernel/watch-ops.ts
|
|
18789
|
+
var WATCH_OPS = ["watch-open", "watch-next", "watch-close"];
|
|
18790
|
+
var WATCHING = new Set(WATCH_OPS);
|
|
18791
|
+
function isWatchSyscall(req) {
|
|
18792
|
+
return WATCHING.has(req.op);
|
|
18793
|
+
}
|
|
18794
|
+
var WATCHES_MAX = 8192;
|
|
18795
|
+
var parentOf8 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
18796
|
+
function visibleTo2(watch, root, visible) {
|
|
18797
|
+
return {
|
|
18798
|
+
close: () => watch.close(),
|
|
18799
|
+
next: async (signal) => {
|
|
18800
|
+
const notes = await watch.next(signal);
|
|
18801
|
+
const seen = /* @__PURE__ */ new Map();
|
|
18802
|
+
const shown = await Promise.all(
|
|
18803
|
+
notes.map(async (note) => {
|
|
18804
|
+
if (!("filename" in note) || !note.filename.includes("/")) return true;
|
|
18805
|
+
const dir = parentOf8(`${root === "/" ? "" : root}/${note.filename}`);
|
|
18806
|
+
if (!seen.has(dir)) seen.set(dir, visible(dir));
|
|
18807
|
+
return seen.get(dir);
|
|
18808
|
+
})
|
|
18809
|
+
);
|
|
18810
|
+
return notes.filter((_note, i) => shown[i]);
|
|
18811
|
+
}
|
|
18812
|
+
};
|
|
18813
|
+
}
|
|
18814
|
+
var ProcessWatches = class {
|
|
18815
|
+
open = /* @__PURE__ */ new Map();
|
|
18816
|
+
nextId = 1;
|
|
18817
|
+
source;
|
|
18818
|
+
constructor(source) {
|
|
18819
|
+
this.source = source;
|
|
18820
|
+
}
|
|
18821
|
+
async syscall(req, cancelled) {
|
|
18822
|
+
if (req.op === "watch-open") {
|
|
18823
|
+
if (!this.source) throw new KernelError("ENOSYS");
|
|
18824
|
+
if (this.open.size >= WATCHES_MAX) throw new KernelError("ENOSPC");
|
|
18825
|
+
const watch2 = await this.source.open(req.path, req.recursive === true);
|
|
18826
|
+
const id2 = this.nextId++;
|
|
18827
|
+
this.open.set(id2, watch2);
|
|
18828
|
+
return { ok: true, kind: "json", json: id2 };
|
|
18829
|
+
}
|
|
18830
|
+
const watch = this.open.get(req.id);
|
|
18831
|
+
if (req.op === "watch-close") {
|
|
18832
|
+
watch?.close();
|
|
18833
|
+
this.open.delete(req.id);
|
|
18834
|
+
return { ok: true, kind: "void" };
|
|
18835
|
+
}
|
|
18836
|
+
if (!watch) return { ok: true, kind: "json", json: [{ ended: true }] };
|
|
18837
|
+
const notes = await watch.next(cancelled);
|
|
18838
|
+
if (notes.some((note) => "ended" in note)) this.open.delete(req.id);
|
|
18839
|
+
return { ok: true, kind: "json", json: notes };
|
|
18840
|
+
}
|
|
18841
|
+
closeAll() {
|
|
18842
|
+
for (const watch of this.open.values()) watch.close();
|
|
18843
|
+
this.open.clear();
|
|
18844
|
+
}
|
|
18845
|
+
};
|
|
18846
|
+
|
|
18668
18847
|
// src/kernel/process.ts
|
|
18669
18848
|
function aborted(signal) {
|
|
18670
18849
|
return new Promise((_, reject) => {
|
|
@@ -18791,7 +18970,8 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
18791
18970
|
...SEM_OPS,
|
|
18792
18971
|
...HTTP_OPS,
|
|
18793
18972
|
...PTY_OPS,
|
|
18794
|
-
...HOST_OPS
|
|
18973
|
+
...HOST_OPS,
|
|
18974
|
+
...WATCH_OPS
|
|
18795
18975
|
]);
|
|
18796
18976
|
function isWasmSyscall(req) {
|
|
18797
18977
|
const op = req.op;
|
|
@@ -18843,6 +19023,7 @@ function timeLeft(req, started) {
|
|
|
18843
19023
|
}
|
|
18844
19024
|
var WasmProcess = class {
|
|
18845
19025
|
exited = false;
|
|
19026
|
+
watches;
|
|
18846
19027
|
children;
|
|
18847
19028
|
deathSignals = /* @__PURE__ */ new Map();
|
|
18848
19029
|
caught = 0;
|
|
@@ -18873,6 +19054,7 @@ var WasmProcess = class {
|
|
|
18873
19054
|
this.pid = pid;
|
|
18874
19055
|
this.fds = fds;
|
|
18875
19056
|
this.options = options;
|
|
19057
|
+
this.watches = new ProcessWatches(options.watches);
|
|
18876
19058
|
this.inherited = options.ignored ?? 0;
|
|
18877
19059
|
this.umask = options.umask ?? DEFAULT_UMASK2;
|
|
18878
19060
|
this.cred = copyCred(options.cred ?? ROOT);
|
|
@@ -19130,6 +19312,7 @@ var WasmProcess = class {
|
|
|
19130
19312
|
});
|
|
19131
19313
|
}
|
|
19132
19314
|
if (isHttpSyscall(req)) return await this.httpSyscall(req);
|
|
19315
|
+
if (isWatchSyscall(req)) return await this.watches.syscall(req, cancelled);
|
|
19133
19316
|
if (isHostSyscall(req)) {
|
|
19134
19317
|
return await hostSyscall(req, {
|
|
19135
19318
|
pid: this.pid,
|
|
@@ -20270,6 +20453,7 @@ var WasmProcess = class {
|
|
|
20270
20453
|
this.options.locks?.release(this.pid);
|
|
20271
20454
|
for (const owner of this.lockOwners) this.options.locks?.release(owner);
|
|
20272
20455
|
this.asyncOps.close();
|
|
20456
|
+
this.watches.closeAll();
|
|
20273
20457
|
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
20274
20458
|
this.deathSignals.clear();
|
|
20275
20459
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
@@ -20531,6 +20715,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
20531
20715
|
locks: opts.locks,
|
|
20532
20716
|
fifos: opts.fifos,
|
|
20533
20717
|
...opts.sems ? { sems: opts.sems } : {},
|
|
20718
|
+
watches: opts.watches,
|
|
20534
20719
|
onReap: opts.onReap,
|
|
20535
20720
|
resolver: opts.resolver,
|
|
20536
20721
|
...notifiers(header4),
|
|
@@ -25816,6 +26001,7 @@ var Launcher = class {
|
|
|
25816
26001
|
locks: this.locks,
|
|
25817
26002
|
fifos: this.fifos,
|
|
25818
26003
|
sems: this.sems,
|
|
26004
|
+
watches: this.watchSource(pid),
|
|
25819
26005
|
resolver: this.resolver,
|
|
25820
26006
|
onReap: (child) => this.reaped(child, pid),
|
|
25821
26007
|
...req.fork ? { fork: req.fork } : {},
|
|
@@ -26359,6 +26545,23 @@ var Launcher = class {
|
|
|
26359
26545
|
mounts: this.mounts.list().map((entry) => entry.target).filter((target) => this.mounts.mounted(target) !== void 0)
|
|
26360
26546
|
});
|
|
26361
26547
|
}
|
|
26548
|
+
watchSource(pid) {
|
|
26549
|
+
return {
|
|
26550
|
+
open: async (path, recursive) => {
|
|
26551
|
+
const at = normalizePath(path);
|
|
26552
|
+
const g = this.execGuard(this.credOf(pid), pid);
|
|
26553
|
+
if (g) await readable(g, "watch", at);
|
|
26554
|
+
const st = await this.fs.stat(at);
|
|
26555
|
+
const real = await this.fs.realpath?.(at, true).catch(() => at) ?? at;
|
|
26556
|
+
const watch = this.watchers.typedWatch(real, recursive && st.isDirectory, at);
|
|
26557
|
+
if (!g || g.cred.euid === 0) return watch;
|
|
26558
|
+
return visibleTo2(watch, real, async (dir) => {
|
|
26559
|
+
const walked = await access(g.fs, g.cred, dir, R_OK | X_OK, { directory: true });
|
|
26560
|
+
return walked.denied === void 0 && walked.missing !== true;
|
|
26561
|
+
});
|
|
26562
|
+
}
|
|
26563
|
+
};
|
|
26564
|
+
}
|
|
26362
26565
|
watchFiles(paths, notify) {
|
|
26363
26566
|
this.fileWatches ??= new FileWatches(this.watchers, this.rootFs);
|
|
26364
26567
|
return this.fileWatches.watch(paths, notify);
|