@ai-ecoverse/slicc-kernel 1.166.5 → 1.167.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 +1 -1
- package/dist/kernel-worker.js +192 -36
- 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 +192 -36
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/fs/unlinked.d.ts +18 -0
- package/dist/types/launcher.d.ts +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1256,7 +1256,7 @@ The database is `slicc-kernel` (or the `metadata` option), schema version 1, wit
|
|
|
1256
1256
|
|
|
1257
1257
|
Not covered: hard links (OPFS cannot share contents between names; they work only within a mount whose driver offers `links`, such as `tmpfs`). File owners are stored only with `users: 'report'` or `'enforce'` (see [File owners](#file-owners)). With `users: 'off'`, an Emscripten process built against the kernel's credential calls (its glue imports `slicc_cred_js`, as homescoop's H1 builds do) sees every file as owned by its own effective uid and gid: root's 0 by default, a user's own ids when it runs as one, and the new ids after a `setuid`. Owner checks such as git's `safe.directory`, ssh's key checks and gnupg's home directory check then pass, as WASIX programs already see through their libc. An older program, whose libc says it is uid 1000 whoever runs it, sees every file as owned by 1000:1000 as before, so its own checks pass too. The kernel decides this once, when it loads the program. Emscripten also doesn't enforce permission bits, so a file runs whether or not its exec bit is set; the bits are what `ls`, `stat` and `test` report. With `users: 'off'` a file or directory with no permission bits at all shows as `0666` or `0777` to Emscripten programs; with owners on they see the real mode (`0`), and the kernel, not Emscripten's own checks, decides who may read, write or enter it (`cd` asks the kernel for `x` on the directory), so root still enters a `000` directory.
|
|
1258
1258
|
|
|
1259
|
-
Reads retry briefly when a concurrent write has invalidated the OPFS file snapshot (`NotReadableError`).
|
|
1259
|
+
Reads retry briefly when a concurrent write has invalidated the OPFS file snapshot (`NotReadableError`). A positioned read uses the snapshot the kernel's last look at the file took (below) when it is still current and covers the whole range, so a run of reads through a descriptor makes no `getFile` of its own beyond the one each window's look takes ([#1626](https://github.com/ai-ecoverse/slicc-kernel/issues/1626)). A read past the snapshot's end, an empty read, or a snapshot that can't be read any more takes a fresh one. In Chrome the snapshot holds no bytes of its own: it reads the file as it is now, so a write in place (a sync access handle) shows at once, and a file another writer replaced, truncated or removed fails the snapshot (`NotReadableError`, `NotFoundError`), which sends the read to a fresh one. Holding a snapshot blocks no other writer: a sync access handle, `createWritable`, `move` and `removeEntry` all go ahead.
|
|
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
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -1312,6 +1312,7 @@ var RemoteWatch = class {
|
|
|
1312
1312
|
};
|
|
1313
1313
|
const left = /* @__PURE__ */ new Set([to]);
|
|
1314
1314
|
const timer = setTimeout(done5, cap);
|
|
1315
|
+
timer.unref?.();
|
|
1315
1316
|
this.waiting.set(seq2, { left, done: done5 });
|
|
1316
1317
|
});
|
|
1317
1318
|
}
|
|
@@ -1353,6 +1354,9 @@ var RemoteWatch = class {
|
|
|
1353
1354
|
this.keeps?.left(tab);
|
|
1354
1355
|
this.ackers.delete(tab);
|
|
1355
1356
|
this.holders.delete(tab);
|
|
1357
|
+
for (const wait2 of [...this.waiting.values()]) {
|
|
1358
|
+
if (wait2.left.delete(tab) && wait2.left.size === 0) wait2.done();
|
|
1359
|
+
}
|
|
1356
1360
|
}
|
|
1357
1361
|
}
|
|
1358
1362
|
this.rebuild();
|
|
@@ -1598,9 +1602,9 @@ async function unlocked(name2, op) {
|
|
|
1598
1602
|
return await op();
|
|
1599
1603
|
} catch (err) {
|
|
1600
1604
|
if (!LOCKED.has(err?.name)) throw err;
|
|
1601
|
-
const
|
|
1602
|
-
if (
|
|
1603
|
-
await new Promise((resolve2) => setTimeout(resolve2,
|
|
1605
|
+
const delay2 = SYNC_BACKOFF_MS[attempt];
|
|
1606
|
+
if (delay2 === void 0) throw fsError("EBUSY", name2);
|
|
1607
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay2));
|
|
1604
1608
|
}
|
|
1605
1609
|
}
|
|
1606
1610
|
}
|
|
@@ -1611,10 +1615,10 @@ async function openSync(handle) {
|
|
|
1611
1615
|
try {
|
|
1612
1616
|
return await sync.call(handle, { mode: "readwrite-unsafe" });
|
|
1613
1617
|
} catch (err) {
|
|
1614
|
-
const
|
|
1618
|
+
const delay2 = SYNC_BACKOFF_MS[attempt];
|
|
1615
1619
|
if (!LOCKED.has(err?.name)) throw err;
|
|
1616
|
-
if (
|
|
1617
|
-
await new Promise((resolve2) => setTimeout(resolve2,
|
|
1620
|
+
if (delay2 === void 0) return void 0;
|
|
1621
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay2));
|
|
1618
1622
|
}
|
|
1619
1623
|
}
|
|
1620
1624
|
}
|
|
@@ -2552,6 +2556,15 @@ var OpfsFs = class {
|
|
|
2552
2556
|
}
|
|
2553
2557
|
async pread(path, offset, length2) {
|
|
2554
2558
|
return this.reading(path, async (handle) => {
|
|
2559
|
+
const seen = this.glanced(handle);
|
|
2560
|
+
if (seen && length2 > 0 && offset + length2 <= seen.size) {
|
|
2561
|
+
const bytes = await this.io(seen.slice(offset, offset + length2).arrayBuffer()).then(
|
|
2562
|
+
(buffer) => new Uint8Array(buffer),
|
|
2563
|
+
() => void 0
|
|
2564
|
+
);
|
|
2565
|
+
if (bytes?.length === length2) return bytes;
|
|
2566
|
+
this.glances.delete(handle);
|
|
2567
|
+
}
|
|
2555
2568
|
const file = await this.io(handle.getFile());
|
|
2556
2569
|
await this.refuseNode(path, file.size === 0);
|
|
2557
2570
|
return new Uint8Array(await file.slice(offset, offset + length2).arrayBuffer());
|
|
@@ -3623,9 +3636,9 @@ var OpfsFs = class {
|
|
|
3623
3636
|
if (!failed3) return true;
|
|
3624
3637
|
const error = failed3.err?.name;
|
|
3625
3638
|
if (handle.kind !== "file" || !LOCKED.has(error)) return false;
|
|
3626
|
-
const
|
|
3627
|
-
if (
|
|
3628
|
-
await new Promise((resolve2) => setTimeout(resolve2,
|
|
3639
|
+
const delay2 = SYNC_BACKOFF_MS[attempt];
|
|
3640
|
+
if (delay2 === void 0) throw fsError("EBUSY", name2);
|
|
3641
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay2));
|
|
3629
3642
|
}
|
|
3630
3643
|
}
|
|
3631
3644
|
async copy(handle, dir, name2, copies, rest2 = "") {
|
|
@@ -8464,7 +8477,7 @@ function satisfies(version, range2) {
|
|
|
8464
8477
|
}
|
|
8465
8478
|
|
|
8466
8479
|
// src/version.ts
|
|
8467
|
-
var KERNEL_VERSION = true ? "1.
|
|
8480
|
+
var KERNEL_VERSION = true ? "1.167.1" : "0.0.0-dev";
|
|
8468
8481
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8469
8482
|
function procVersion() {
|
|
8470
8483
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9415,8 +9428,41 @@ var within4 = (path, target) => path === target || target === "/" || path.starts
|
|
|
9415
9428
|
var TOUCHED_MAX = 4096;
|
|
9416
9429
|
var parentOf5 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
9417
9430
|
var PEER_RM_MS = 1e3;
|
|
9431
|
+
var SHARED_ACK_MS = 24 * 60 * 60 * 1e3;
|
|
9432
|
+
var delay = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
9418
9433
|
var PEER_RENAME_MS = 1e4;
|
|
9419
9434
|
var PEER_GATE_MS = PEER_RENAME_MS + 5e3;
|
|
9435
|
+
var SHARED_PREFIX = "shared.";
|
|
9436
|
+
var keptLock = (hidden) => `slicc-kept:${hidden}`;
|
|
9437
|
+
function sharedKept(hidden) {
|
|
9438
|
+
const at = `/${UNLINKED_DIR}/${SHARED_PREFIX}`;
|
|
9439
|
+
return hidden.startsWith(at) && /^[0-9a-f]+$/.test(hidden.slice(at.length));
|
|
9440
|
+
}
|
|
9441
|
+
function holdShared(locks, name2) {
|
|
9442
|
+
if (!locks) return Promise.resolve(async () => void 0);
|
|
9443
|
+
return new Promise((resolve2) => {
|
|
9444
|
+
const settled = locks.request(name2, { mode: "shared" }, () => {
|
|
9445
|
+
const { promise, resolve: done5 } = Promise.withResolvers();
|
|
9446
|
+
resolve2(async () => {
|
|
9447
|
+
done5();
|
|
9448
|
+
await settled.catch(() => void 0);
|
|
9449
|
+
});
|
|
9450
|
+
return promise;
|
|
9451
|
+
});
|
|
9452
|
+
});
|
|
9453
|
+
}
|
|
9454
|
+
async function whenLast(locks, name2, op) {
|
|
9455
|
+
if (!locks) {
|
|
9456
|
+
await op();
|
|
9457
|
+
return true;
|
|
9458
|
+
}
|
|
9459
|
+
let free = false;
|
|
9460
|
+
await locks.request(name2, { mode: "exclusive", ifAvailable: true }, async (lock) => {
|
|
9461
|
+
free = lock !== null;
|
|
9462
|
+
if (free) await op();
|
|
9463
|
+
});
|
|
9464
|
+
return free;
|
|
9465
|
+
}
|
|
9420
9466
|
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
9421
9467
|
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
9422
9468
|
var PathGate = class {
|
|
@@ -9732,52 +9778,124 @@ var UnlinkedKeeper = class {
|
|
|
9732
9778
|
void peers.ask(tab, { kept: { items: [], paths } }, PEER_RM_MS);
|
|
9733
9779
|
throw fsError("EBUSY", `${target}: open in another tab that did not answer`);
|
|
9734
9780
|
}
|
|
9735
|
-
const { whole, sends } = await this.setAside(target, asked);
|
|
9736
|
-
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard) };
|
|
9781
|
+
const { whole, sends, shared } = await this.setAside(target, asked);
|
|
9782
|
+
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard, shared) };
|
|
9737
9783
|
}
|
|
9738
9784
|
async setAside(target, asked) {
|
|
9739
9785
|
const mine = this.heldWithin(target);
|
|
9740
|
-
const
|
|
9741
|
-
|
|
9786
|
+
const tabsOf = /* @__PURE__ */ new Map();
|
|
9787
|
+
for (const { holders } of asked)
|
|
9788
|
+
for (const { path } of holders) tabsOf.set(path, (tabsOf.get(path) ?? 0) + 1);
|
|
9789
|
+
const done5 = /* @__PURE__ */ new Map();
|
|
9790
|
+
const shared = [];
|
|
9742
9791
|
const sends = [];
|
|
9743
9792
|
for (const { tab, holders, paths } of asked) {
|
|
9744
9793
|
const items = [];
|
|
9745
9794
|
for (const holder of holders) {
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
taken.add(holder.path);
|
|
9750
|
-
if (holder.path === target) whole = true;
|
|
9795
|
+
if (!done5.has(holder.path)) {
|
|
9796
|
+
const many = mine.has(holder.path) || (tabsOf.get(holder.path) ?? 0) > 1;
|
|
9797
|
+
done5.set(holder.path, await this.asideOne(holder, many, mine, shared));
|
|
9751
9798
|
}
|
|
9752
|
-
items.push({ path: holder.path, hidden, fid: holder.fid });
|
|
9799
|
+
items.push({ path: holder.path, hidden: done5.get(holder.path), fid: holder.fid });
|
|
9753
9800
|
}
|
|
9754
9801
|
sends.push({ tab, items, paths });
|
|
9755
9802
|
}
|
|
9756
|
-
return { whole, sends };
|
|
9803
|
+
return { whole: done5.get(target) !== void 0, sends, shared };
|
|
9757
9804
|
}
|
|
9758
|
-
async
|
|
9805
|
+
async asideOne(holder, many, mine, shared) {
|
|
9806
|
+
if (!many) return this.asideFor(holder.path, holder.instance);
|
|
9807
|
+
const one = await this.sharedAside(holder.path, mine);
|
|
9808
|
+
if (one) shared.push(one);
|
|
9809
|
+
return one?.hidden;
|
|
9810
|
+
}
|
|
9811
|
+
async sharedAside(path, mine) {
|
|
9812
|
+
const hidden = `${dirOf("/")}/${SHARED_PREFIX}${crypto.randomUUID().replaceAll("-", "")}`;
|
|
9813
|
+
const release = await holdShared(this.sharedLocks(), keptLock(hidden));
|
|
9814
|
+
const moved2 = await this.serial(async () => {
|
|
9815
|
+
try {
|
|
9816
|
+
const owner = this.dirOwner;
|
|
9817
|
+
await this.fs.mkdir(dirOf("/"), { recursive: true, ...owner ? { owner } : {} });
|
|
9818
|
+
await this.fs.rename(path, hidden);
|
|
9819
|
+
return true;
|
|
9820
|
+
} catch {
|
|
9821
|
+
return false;
|
|
9822
|
+
}
|
|
9823
|
+
});
|
|
9824
|
+
if (!moved2) {
|
|
9825
|
+
await release();
|
|
9826
|
+
return void 0;
|
|
9827
|
+
}
|
|
9828
|
+
const local2 = mine.get(path) ?? [];
|
|
9829
|
+
const file = local2.length > 0 ? await this.sharedFile(hidden, local2.length) : void 0;
|
|
9830
|
+
if (file) for (const holder of local2) holder.keep(path, file);
|
|
9831
|
+
return { path, hidden, release, local: local2, file };
|
|
9832
|
+
}
|
|
9833
|
+
async sharedFile(hidden, refs) {
|
|
9834
|
+
const locks = this.sharedLocks();
|
|
9835
|
+
const mine = await holdShared(locks, keptLock(hidden));
|
|
9836
|
+
let left = refs;
|
|
9837
|
+
return {
|
|
9838
|
+
hidden,
|
|
9839
|
+
release: () => {
|
|
9840
|
+
if (--left > 0) return;
|
|
9841
|
+
void mine().then(() => this.dropIfLast(hidden));
|
|
9842
|
+
}
|
|
9843
|
+
};
|
|
9844
|
+
}
|
|
9845
|
+
dropIfLast(hidden) {
|
|
9846
|
+
return this.serial(
|
|
9847
|
+
() => whenLast(this.sharedLocks(), keptLock(hidden), () => this.drop(hidden))
|
|
9848
|
+
);
|
|
9849
|
+
}
|
|
9850
|
+
sharedLocks() {
|
|
9851
|
+
return this.locks;
|
|
9852
|
+
}
|
|
9853
|
+
async undoing(op, peers, sends, heard, shared = []) {
|
|
9759
9854
|
let failed3;
|
|
9760
9855
|
let out;
|
|
9761
9856
|
try {
|
|
9762
9857
|
out = await op();
|
|
9763
9858
|
} catch (err) {
|
|
9764
9859
|
failed3 = err ?? new Error("failed");
|
|
9765
|
-
|
|
9766
|
-
for (const item of send2.items) {
|
|
9767
|
-
const { hidden, path } = item;
|
|
9768
|
-
if (hidden !== void 0 && await this.moveBack(hidden, path)) item.hidden = void 0;
|
|
9769
|
-
}
|
|
9770
|
-
}
|
|
9860
|
+
await this.rollBackAsides(sends, shared);
|
|
9771
9861
|
}
|
|
9862
|
+
const hiddenShared = new Set(shared.map((one) => one.hidden));
|
|
9863
|
+
const answers2 = sends.map(({ tab, items, paths }) => {
|
|
9864
|
+
const keeps = items.some((item) => item.hidden && hiddenShared.has(item.hidden));
|
|
9865
|
+
return {
|
|
9866
|
+
keeps,
|
|
9867
|
+
told: peers.ask(tab, { kept: { items, paths } }, keeps ? SHARED_ACK_MS : PEER_RM_MS)
|
|
9868
|
+
};
|
|
9869
|
+
});
|
|
9772
9870
|
await Promise.all(
|
|
9773
|
-
|
|
9774
|
-
const told = peers.ask(tab, { kept: { items, paths } }, PEER_RM_MS);
|
|
9775
|
-
return heard[i] ? told : void 0;
|
|
9776
|
-
})
|
|
9871
|
+
answers2.map(({ told }, i) => heard[i] ? Promise.race([told, delay(PEER_RM_MS)]) : void 0)
|
|
9777
9872
|
);
|
|
9873
|
+
for (const one of shared) {
|
|
9874
|
+
const waits = answers2.filter(
|
|
9875
|
+
({ keeps }, i) => keeps && sends[i]?.items.some((item) => item.hidden === one.hidden)
|
|
9876
|
+
);
|
|
9877
|
+
const done5 = () => one.release().then(() => this.dropIfLast(one.hidden));
|
|
9878
|
+
void Promise.all(waits.map(({ told }) => told)).then(done5, done5);
|
|
9879
|
+
}
|
|
9778
9880
|
if (failed3 !== void 0) throw failed3;
|
|
9779
9881
|
return out;
|
|
9780
9882
|
}
|
|
9883
|
+
async rollBackAsides(sends, shared) {
|
|
9884
|
+
const back = /* @__PURE__ */ new Map();
|
|
9885
|
+
for (const item of sends.flatMap((send2) => send2.items)) {
|
|
9886
|
+
const { hidden, path } = item;
|
|
9887
|
+
if (hidden === void 0) continue;
|
|
9888
|
+
if (!back.has(hidden)) back.set(hidden, await this.moveBack(hidden, path));
|
|
9889
|
+
if (back.get(hidden)) item.hidden = void 0;
|
|
9890
|
+
}
|
|
9891
|
+
for (const { hidden, path, local: local2, file } of shared) {
|
|
9892
|
+
if (!back.get(hidden) || !file) continue;
|
|
9893
|
+
for (const holder of local2) {
|
|
9894
|
+
holder.unkeep(path, file);
|
|
9895
|
+
file.release();
|
|
9896
|
+
}
|
|
9897
|
+
}
|
|
9898
|
+
}
|
|
9781
9899
|
moveBack(hidden, path) {
|
|
9782
9900
|
return this.serial(async () => {
|
|
9783
9901
|
if (await this.present(path)) return false;
|
|
@@ -9886,6 +10004,15 @@ var UnlinkedKeeper = class {
|
|
|
9886
10004
|
for (const name2 of names2) {
|
|
9887
10005
|
const id2 = name2.slice(0, name2.lastIndexOf("."));
|
|
9888
10006
|
const at = id2.indexOf("~");
|
|
10007
|
+
if (name2.startsWith(SHARED_PREFIX)) {
|
|
10008
|
+
const at2 = `${dir}/${name2}`;
|
|
10009
|
+
await whenLast(
|
|
10010
|
+
this.sharedLocks(),
|
|
10011
|
+
keptLock(at2),
|
|
10012
|
+
() => this.fs.rm(at2, { recursive: true }).catch(() => void 0)
|
|
10013
|
+
);
|
|
10014
|
+
continue;
|
|
10015
|
+
}
|
|
9889
10016
|
const dead = id2 !== this.instance && (at < 0 ? held !== void 0 && !held.has(lockName(id2)) : owner?.alive(id2.slice(0, at)) === false);
|
|
9890
10017
|
if (dead) await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
|
|
9891
10018
|
}
|
|
@@ -24598,13 +24725,13 @@ var VfsNode = class {
|
|
|
24598
24725
|
this.recount();
|
|
24599
24726
|
if (!this.orphaned) this.onDirty?.();
|
|
24600
24727
|
if (this.writeBack !== void 0 || this.orphaned) return;
|
|
24601
|
-
const
|
|
24728
|
+
const delay2 = Math.max(WRITEBACK_MS, this.writeBackCost * WRITEBACK_COST_FACTOR);
|
|
24602
24729
|
this.writeBack = setTimeout(() => {
|
|
24603
24730
|
this.writeBack = void 0;
|
|
24604
24731
|
this.serial(() => this.flush()).catch(() => {
|
|
24605
24732
|
this.failed = true;
|
|
24606
24733
|
});
|
|
24607
|
-
},
|
|
24734
|
+
}, delay2);
|
|
24608
24735
|
}
|
|
24609
24736
|
ensure(need2) {
|
|
24610
24737
|
const cur = this.data ?? new Uint8Array(0);
|
|
@@ -33572,7 +33699,10 @@ var Launcher = class {
|
|
|
33572
33699
|
await Promise.all(mine);
|
|
33573
33700
|
},
|
|
33574
33701
|
kept: async (tab, items, paths) => {
|
|
33575
|
-
for (const { path, hidden, fid } of items)
|
|
33702
|
+
for (const { path, hidden, fid } of items) {
|
|
33703
|
+
if (hidden !== void 0 && sharedKept(hidden)) await this.adoptShared(path, hidden, fid);
|
|
33704
|
+
else this.adoptKept(path, hidden, fid, ours);
|
|
33705
|
+
}
|
|
33576
33706
|
await open2(tab, paths);
|
|
33577
33707
|
},
|
|
33578
33708
|
left: (tab) => {
|
|
@@ -33581,6 +33711,33 @@ var Launcher = class {
|
|
|
33581
33711
|
}
|
|
33582
33712
|
};
|
|
33583
33713
|
}
|
|
33714
|
+
async adoptShared(path, hidden, fid) {
|
|
33715
|
+
const bound3 = [...this.held].map(
|
|
33716
|
+
(holds2) => [holds2, [...holds2.boundAt(path, fid), ...holds2.boundAt(hidden, fid)]]
|
|
33717
|
+
);
|
|
33718
|
+
const keeping = bound3.filter(([, ids]) => ids.length > 0);
|
|
33719
|
+
const nodes = [...this.openFiles].filter(
|
|
33720
|
+
(open2) => [path, hidden].some((at) => open2.holdsAt(at))
|
|
33721
|
+
);
|
|
33722
|
+
const refs = keeping.length + nodes.length;
|
|
33723
|
+
if (refs === 0) {
|
|
33724
|
+
this.held.doubt([path]);
|
|
33725
|
+
return;
|
|
33726
|
+
}
|
|
33727
|
+
const file = await this.unlinked.sharedFile(hidden, refs);
|
|
33728
|
+
if (!await this.rootFs.lstat(hidden).then(
|
|
33729
|
+
() => true,
|
|
33730
|
+
() => false
|
|
33731
|
+
)) {
|
|
33732
|
+
for (let i = 0; i < refs; i++) file.release();
|
|
33733
|
+
this.held.doubt([path]);
|
|
33734
|
+
return;
|
|
33735
|
+
}
|
|
33736
|
+
const kept = nodes.filter((open2) => open2.keepBound([hidden, path], fid, file)).length;
|
|
33737
|
+
for (let i = kept; i < nodes.length; i++) file.release();
|
|
33738
|
+
for (const [holds2, ids] of keeping) holds2.keepBound(ids, path, file);
|
|
33739
|
+
void this.rootFs.announceHolds?.([], [path, hidden], false);
|
|
33740
|
+
}
|
|
33584
33741
|
adoptKept(path, hidden, fid, ours) {
|
|
33585
33742
|
if (hidden === void 0 || !ours(hidden)) {
|
|
33586
33743
|
this.held.doubt([path]);
|
|
@@ -33723,7 +33880,6 @@ var Launcher = class {
|
|
|
33723
33880
|
moved(from, to, source) {
|
|
33724
33881
|
this.renameLog.add(from, to);
|
|
33725
33882
|
for (const holds2 of this.held) holds2.renamed(from, to);
|
|
33726
|
-
if (this.mounts.locate(to) === void 0) this.rootFs.rehold?.(from, to);
|
|
33727
33883
|
if (source) return;
|
|
33728
33884
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
33729
33885
|
this.watchers.moved(from, to);
|