@ai-ecoverse/slicc-kernel 1.167.3 → 1.167.4
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 +1 -1
- package/dist/kernel-worker.js +26 -11
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +26 -11
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/fs/dac.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1260,7 +1260,7 @@ Reads retry briefly when a concurrent write has invalidated the OPFS file snapsh
|
|
|
1260
1260
|
|
|
1261
1261
|
At boot, a kernel drops sidecar records whose file is gone (and symlink records whose name became a real file or whose directory is gone), left behind by a tab that closed mid-change. It does this only when it is the only kernel on the origin (the watch channel's join handshake finds no other), and it drops a record only if it is still the one it found: another tab's live changes made while it looked, such as a placeholder tar replaces with a symlink, are kept. Up to 1.119.2, a tab that booted while another extracted symlinks with tar could drop some of them.
|
|
1262
1262
|
|
|
1263
|
-
A kernel caches the directory handles it has walked and the sidecar entries it has read. Its own changes keep both caches current, and the other kernels on the origin hear of them through a `BroadcastChannel` named after the database (one for the sidecar, one for directories). A cached directory is checked against its path (`resolve()`) at most once a second before a lookup goes through it, so a directory moved, removed or replaced by another writer, such as a page using the OPFS API, is found at its new place or reported missing within a second. It also keeps the file handles it has looked up (up to 4,096, the least recently used dropped first) for a second after each lookup. Before it uses one, it reads the file through it, which is the read a `stat` needs anyway, and that read serves the handle's uses in the kernel's next 64 lookups, for at most 100 ms ([#1425](https://github.com/ai-ecoverse/slicc-kernel/issues/1425)), so the count doesn't depend on how fast the machine is. So a file another writer removed is missing, and a rewritten one shows its new contents, within 100 ms. The kernel's own writes, truncates, rewrites and renames drop the read at once, and a read that started before an own change isn't kept, so the kernel's own changes always show at once. One replaced by a directory is seen as a directory within a second. Its own changes, and the other kernels' notices, drop the handles they touch at once. A lookup of a directory it has cached and checked within the second is answered from the cache, so a directory replaced by another writer is seen as replaced within a second, as above. A name it has just found missing stays missing for the kernel's next 256 lookups, for at most 100 ms, which serves the several checks a single create makes of a name that isn't there yet (about ten per file in a pnpm install, up to a few hundred lookups apart); its own creates, renames and links in that directory end that at once, so only a file another kernel or a page using the OPFS API makes in that window is seen up to 100 ms late. While another kernel shares the root, both short-lived windows follow the contract below. From [#945](https://github.com/ai-ecoverse/slicc-kernel/issues/945) until [#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984) they were off then, which made every stat and every miss an OPFS call.
|
|
1263
|
+
A kernel caches the directory handles it has walked and the sidecar entries it has read. Its own changes keep both caches current, and the other kernels on the origin hear of them through a `BroadcastChannel` named after the database (one for the sidecar, one for directories). A cached directory is checked against its path (`resolve()`) at most once a second before a lookup goes through it, so a directory moved, removed or replaced by another writer, such as a page using the OPFS API, is found at its new place or reported missing within a second. It also keeps the file handles it has looked up (up to 4,096, the least recently used dropped first) for a second after each lookup. Before it uses one, it reads the file through it, which is the read a `stat` needs anyway, and that read serves the handle's uses in the kernel's next 64 lookups, for at most 100 ms ([#1425](https://github.com/ai-ecoverse/slicc-kernel/issues/1425)), so the count doesn't depend on how fast the machine is. So a file another writer removed is missing, and a rewritten one shows its new contents, within 100 ms. The kernel's own writes, truncates, rewrites and renames drop the read at once, and a read that started before an own change isn't kept, so the kernel's own changes always show at once. One replaced by a directory is seen as a directory within a second. Its own changes, and the other kernels' notices, drop the handles they touch at once. A lookup of a directory it has cached and checked within the second is answered from the cache, so a directory replaced by another writer is seen as replaced within a second, as above. A name it has just found missing stays missing for the kernel's next 256 lookups, for at most 100 ms, which serves the several checks a single create makes of a name that isn't there yet (about ten per file in a pnpm install, up to a few hundred lookups apart); its own creates, renames and links in that directory end that at once, so only a file another kernel or a page using the OPFS API makes in that window is seen up to 100 ms late. A listing of the directory (`ls`, a glob, `readdir`) ends it too for every name it shows, so `ls` and then `cat` agree ([#1693](https://github.com/ai-ecoverse/slicc-kernel/issues/1693)). A writer outside the kernel whose file must open in the very next run, such as a page that writes a file and then calls `kernel.run`, posts a notice for it (`postFsNotice`, below) or waits 100 ms. While another kernel shares the root, both short-lived windows follow the contract below. From [#945](https://github.com/ai-ecoverse/slicc-kernel/issues/945) until [#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984) they were off then, which made every stat and every miss an OPFS call.
|
|
1264
1264
|
|
|
1265
1265
|
**What another tab sees, and when** ([#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984)): one rule covers everything a kernel caches about a shared root.
|
|
1266
1266
|
- **Notices:** while another kernel shares the root, a kernel posts a notice before each changing call returns. A notice names the sidecar records it changed (owners, modes, links, times, write counts), the directories it created, removed or renamed into, and the files it wrote back ([#962](https://github.com/ai-ecoverse/slicc-kernel/issues/962)).
|
package/dist/kernel-worker.js
CHANGED
|
@@ -2838,6 +2838,10 @@ var OpfsFs = class {
|
|
|
2838
2838
|
const children3 = /* @__PURE__ */ new Map();
|
|
2839
2839
|
this.others++;
|
|
2840
2840
|
for await (const child of handle.values()) children3.set(child.name, child);
|
|
2841
|
+
if (this.absent.size > 0) {
|
|
2842
|
+
const base = found.path === "/" ? "" : found.path;
|
|
2843
|
+
for (const name2 of children3.keys()) this.absent.delete(`${base}/${name2}`);
|
|
2844
|
+
}
|
|
2841
2845
|
for (const link2 of await this.meta.links(found.path)) {
|
|
2842
2846
|
const name2 = baseOf(link2.path);
|
|
2843
2847
|
if (!children3.has(name2)) children3.set(name2, link2);
|
|
@@ -5271,28 +5275,39 @@ async function stickyEntry(g, op, path, dir) {
|
|
|
5271
5275
|
if (sticky(g.cred, perm, (await ancestryOf(g.fs, entry)).at(-1))) return;
|
|
5272
5276
|
if (await present(g.fs, entry, false)) deny(g, op, path, "EPERM");
|
|
5273
5277
|
}
|
|
5278
|
+
async function unwritable(g, op, path, dir) {
|
|
5279
|
+
if (dir.denied === void 0) return false;
|
|
5280
|
+
if (dir.link) {
|
|
5281
|
+
deny(g, op, dir.denied);
|
|
5282
|
+
return false;
|
|
5283
|
+
}
|
|
5284
|
+
const perm = dir.denied === dir.path ? dir.perm : void 0;
|
|
5285
|
+
if (perm && !await present(g.fs, dir.path, true)) return false;
|
|
5286
|
+
if (perm && permits(g.cred, perm, X_OK)) return true;
|
|
5287
|
+
deny(g, op, path);
|
|
5288
|
+
return false;
|
|
5289
|
+
}
|
|
5274
5290
|
async function inParent(g, op, path, old = false) {
|
|
5275
5291
|
await fence(g, op, path);
|
|
5276
|
-
if (old === "replaced") {
|
|
5277
|
-
const dir2 = await need(g, op, parentOf4(path), W_OK | X_OK, DIR, path);
|
|
5278
|
-
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
5279
|
-
}
|
|
5280
|
-
if (!old) return void await need(g, op, parentOf4(path), W_OK | X_OK, DIR, path);
|
|
5281
5292
|
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, linked(g, DIR));
|
|
5293
|
+
if (old !== true) {
|
|
5294
|
+
if (await unwritable(g, op, path, dir)) deny(g, op, path);
|
|
5295
|
+
else if (old === "replaced" && dir.denied === void 0) await stickyEntry(g, op, path, dir);
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5282
5298
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
5283
5299
|
if (dir.link) return deny(g, op, dir.denied);
|
|
5284
5300
|
const lookup2 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
5285
5301
|
if (!lookup2 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
5286
5302
|
}
|
|
5287
|
-
async function makeIn(g, op, path) {
|
|
5303
|
+
async function makeIn(g, op, path, parents = true) {
|
|
5288
5304
|
for (let dir = parentOf4(path); ; dir = parentOf4(dir)) {
|
|
5289
5305
|
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
5290
|
-
if (
|
|
5291
|
-
if (walked.denied !== void 0) {
|
|
5306
|
+
if (await unwritable(g, op, path, walked)) {
|
|
5292
5307
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
5293
5308
|
return;
|
|
5294
5309
|
}
|
|
5295
|
-
if (!walked.missing || dir === "/") return;
|
|
5310
|
+
if (!parents || !walked.missing || dir === "/") return;
|
|
5296
5311
|
}
|
|
5297
5312
|
}
|
|
5298
5313
|
async function tree(g, op, dir, perm) {
|
|
@@ -8477,7 +8492,7 @@ function satisfies(version, range2) {
|
|
|
8477
8492
|
}
|
|
8478
8493
|
|
|
8479
8494
|
// src/version.ts
|
|
8480
|
-
var KERNEL_VERSION = true ? "1.167.
|
|
8495
|
+
var KERNEL_VERSION = true ? "1.167.4" : "0.0.0-dev";
|
|
8481
8496
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8482
8497
|
function procVersion() {
|
|
8483
8498
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -15134,7 +15149,7 @@ async function guard(g, path, req, cwd) {
|
|
|
15134
15149
|
return { path: w };
|
|
15135
15150
|
}
|
|
15136
15151
|
case "mkdir": {
|
|
15137
|
-
await makeIn(g, op, path);
|
|
15152
|
+
await makeIn(g, op, path, !req.exclusive);
|
|
15138
15153
|
return { path: await walkSafe(g, path, false) };
|
|
15139
15154
|
}
|
|
15140
15155
|
case "create":
|