@ai-ecoverse/slicc-kernel 1.143.4 → 1.143.6
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 +11 -4
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +193 -26
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +1 -1
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +218 -36
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +192 -25
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +218 -36
- package/dist/process-worker.js.map +3 -3
- package/dist/types/fs/changes.d.ts +4 -0
- package/dist/types/fs/meta.d.ts +4 -0
- package/dist/types/fs/opfs.d.ts +10 -0
- package/dist/types/fs/remote.d.ts +4 -0
- package/dist/types/fs/types.d.ts +4 -0
- package/dist/types/kernel/host.d.ts +5 -0
- package/dist/types/kernel/rename-log.d.ts +14 -0
- package/dist/types/kernel/vfs-file.d.ts +1 -0
- package/dist/types/launcher.d.ts +2 -0
- package/dist/types/process/wasi/wasi-fds.d.ts +4 -1
- package/dist/types/process/wasi/wasi-files.d.ts +2 -0
- package/dist/types/process/wasi/wasi-host.d.ts +1 -0
- package/dist/types/realm/live-vfs-fs.d.ts +8 -0
- package/dist/types/realm/sync-fs-token-registry.d.ts +5 -0
- package/dist/types/realm/sync-fs-wire.d.ts +7 -2
- package/package.json +10 -10
package/dist/kernel-worker.js
CHANGED
|
@@ -262,7 +262,7 @@ var IndexedDbMeta = class {
|
|
|
262
262
|
if (left) store.put(left);
|
|
263
263
|
};
|
|
264
264
|
await settle(transaction, () => void 0);
|
|
265
|
-
this.changed({ trees: [from, to] });
|
|
265
|
+
this.changed({ trees: [from, to], moved: { from, to } });
|
|
266
266
|
}
|
|
267
267
|
absent(path) {
|
|
268
268
|
return this.cache.has(path) && this.cache.get(path) === null;
|
|
@@ -364,7 +364,8 @@ var SLOT = 2;
|
|
|
364
364
|
var SHARED_TTL_MS = 100;
|
|
365
365
|
var DIRTY = RING + RING_SIZE * SLOT;
|
|
366
366
|
var FOREIGN = DIRTY + 1;
|
|
367
|
-
var
|
|
367
|
+
var RENAMES = FOREIGN + 1;
|
|
368
|
+
var CHANGES_BYTES = (RENAMES + 1) * 4;
|
|
368
369
|
function changeHash(path) {
|
|
369
370
|
let h = 2166136261;
|
|
370
371
|
for (let i = 0; i < path.length; i++) {
|
|
@@ -398,6 +399,11 @@ var FileChanges = class {
|
|
|
398
399
|
flush() {
|
|
399
400
|
Atomics.add(this.view, GEN, RING_SIZE + 1);
|
|
400
401
|
}
|
|
402
|
+
renamed() {
|
|
403
|
+
const seq2 = Atomics.add(this.view, RENAMES, 1) + 1 | 0;
|
|
404
|
+
Atomics.notify(this.view, RENAMES);
|
|
405
|
+
return seq2;
|
|
406
|
+
}
|
|
401
407
|
publish(...paths) {
|
|
402
408
|
for (const path of paths) {
|
|
403
409
|
const g = Atomics.add(this.view, GEN, 1) + 1 | 0;
|
|
@@ -422,6 +428,13 @@ var ChangeView = class {
|
|
|
422
428
|
foreign() {
|
|
423
429
|
return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
|
|
424
430
|
}
|
|
431
|
+
renames() {
|
|
432
|
+
return this.view.length > RENAMES ? Atomics.load(this.view, RENAMES) : 0;
|
|
433
|
+
}
|
|
434
|
+
awaitRename(seen, ms) {
|
|
435
|
+
if (this.view.length > RENAMES) Atomics.wait(this.view, RENAMES, seen, ms);
|
|
436
|
+
return this.renames();
|
|
437
|
+
}
|
|
425
438
|
changedSince(seen, path) {
|
|
426
439
|
const now = Atomics.load(this.view, GEN);
|
|
427
440
|
const distance = now - seen >>> 0;
|
|
@@ -1272,7 +1285,7 @@ var STALE = /* @__PURE__ */ new Set(["NotFoundError", "TypeMismatchError"]);
|
|
|
1272
1285
|
var REPLACED_ATTEMPTS = 4;
|
|
1273
1286
|
var RECONCILE_LISTINGS = 8;
|
|
1274
1287
|
var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
|
|
1275
|
-
var
|
|
1288
|
+
var RENAMES2 = "/.slicc-renames";
|
|
1276
1289
|
var RENAME_LOCK = "slicc-rename:";
|
|
1277
1290
|
var RENAME_ADMIT = "slicc-rename-admit:";
|
|
1278
1291
|
var escapeRoot = (name2) => name2.replace(/[%:]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
@@ -1471,7 +1484,8 @@ var OpfsFs = class {
|
|
|
1471
1484
|
const remote = this.remote;
|
|
1472
1485
|
meta.listen?.((c) => {
|
|
1473
1486
|
for (const path of [...c.paths ?? [], ...c.trees ?? []]) this.forget(path);
|
|
1474
|
-
|
|
1487
|
+
const moved2 = movedOf(c.moved);
|
|
1488
|
+
remote?.emit({ paths: c.paths ?? [], trees: c.trees ?? [], ...moved2 ? { moved: moved2 } : {} });
|
|
1475
1489
|
});
|
|
1476
1490
|
remote?.listen((c) => {
|
|
1477
1491
|
for (const path of [...c.paths, ...c.trees]) this.forget(path);
|
|
@@ -2193,31 +2207,38 @@ var OpfsFs = class {
|
|
|
2193
2207
|
});
|
|
2194
2208
|
}
|
|
2195
2209
|
async pwrite(path, offset, bytes) {
|
|
2196
|
-
const
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2210
|
+
const at = normalizePath(path);
|
|
2211
|
+
const movedAway = this.renamesInFlight() ? await this.writeWaits(at) : false;
|
|
2212
|
+
this.fileWrites.set(at, (this.fileWrites.get(at) ?? 0) + 1);
|
|
2213
|
+
try {
|
|
2214
|
+
const [kept, target, existed] = await this.keptFor(path);
|
|
2215
|
+
if (kept) {
|
|
2216
|
+
try {
|
|
2217
|
+
await this.writeAt(kept, target, path, offset, bytes);
|
|
2218
|
+
return;
|
|
2219
|
+
} catch (err) {
|
|
2220
|
+
if (err.code !== "ENOENT") throw err;
|
|
2221
|
+
this.files.delete(target);
|
|
2222
|
+
}
|
|
2204
2223
|
}
|
|
2224
|
+
const [handle] = await this.fileFor(path, !existed && !movedAway);
|
|
2225
|
+
await this.writeAt(handle, target, path, offset, bytes);
|
|
2226
|
+
} finally {
|
|
2227
|
+
this.writeEnded(at);
|
|
2205
2228
|
}
|
|
2206
|
-
const [handle] = await this.fileFor(path);
|
|
2207
|
-
await this.writeAt(handle, target, path, offset, bytes);
|
|
2208
2229
|
}
|
|
2209
2230
|
async keptFor(path) {
|
|
2210
2231
|
const at = normalizePath(path);
|
|
2211
2232
|
const cached = this.files.get(at);
|
|
2212
2233
|
const fresh2 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
2213
2234
|
const [target, existed] = fresh2 ? [at, true] : await this.writeTarget(path);
|
|
2214
|
-
if (!existed) return [void 0, target];
|
|
2235
|
+
if (!existed) return [void 0, target, false];
|
|
2215
2236
|
this.refuse(target);
|
|
2216
2237
|
const [entry] = await this.meta.get([target]);
|
|
2217
2238
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
2218
2239
|
const kept = fresh2 ? cached : this.files.get(target);
|
|
2219
2240
|
const usable2 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
2220
|
-
return [usable2 ? kept : void 0, target];
|
|
2241
|
+
return [usable2 ? kept : void 0, target, true];
|
|
2221
2242
|
}
|
|
2222
2243
|
async writeAt(handle, target, path, offset, bytes) {
|
|
2223
2244
|
await this.counting(target);
|
|
@@ -2234,7 +2255,67 @@ var OpfsFs = class {
|
|
|
2234
2255
|
}
|
|
2235
2256
|
this.written(target);
|
|
2236
2257
|
}
|
|
2258
|
+
fileWrites = /* @__PURE__ */ new Map();
|
|
2259
|
+
movingFiles = /* @__PURE__ */ new Map();
|
|
2260
|
+
writesIdle;
|
|
2261
|
+
writeBlocked(at) {
|
|
2262
|
+
const file = this.movingFiles.get(at);
|
|
2263
|
+
if (file !== void 0) return { done: file, away: true };
|
|
2264
|
+
for (const m of this.renamingDirs) {
|
|
2265
|
+
if (within2(at, m.from)) return { done: m.done, away: true };
|
|
2266
|
+
if (within2(at, m.to)) return { done: m.done, away: false };
|
|
2267
|
+
}
|
|
2268
|
+
return void 0;
|
|
2269
|
+
}
|
|
2270
|
+
renamesInFlight() {
|
|
2271
|
+
return this.movingFiles.size > 0 || this.renamingDirs.size > 0;
|
|
2272
|
+
}
|
|
2273
|
+
async writeWaits(at) {
|
|
2274
|
+
let away = false;
|
|
2275
|
+
for (let busy = this.writeBlocked(at); busy !== void 0; busy = this.writeBlocked(at)) {
|
|
2276
|
+
away ||= busy.away;
|
|
2277
|
+
await busy.done;
|
|
2278
|
+
}
|
|
2279
|
+
return away;
|
|
2280
|
+
}
|
|
2281
|
+
writeEnded(at) {
|
|
2282
|
+
const left = (this.fileWrites.get(at) ?? 1) - 1;
|
|
2283
|
+
if (left > 0) this.fileWrites.set(at, left);
|
|
2284
|
+
else this.fileWrites.delete(at);
|
|
2285
|
+
const idle2 = this.writesIdle;
|
|
2286
|
+
if (idle2 === void 0) return;
|
|
2287
|
+
this.writesIdle = void 0;
|
|
2288
|
+
idle2.resolve();
|
|
2289
|
+
}
|
|
2290
|
+
async writesDrained(tree2) {
|
|
2291
|
+
while ([...this.fileWrites.keys()].some((at) => within2(at, tree2))) {
|
|
2292
|
+
this.writesIdle ??= Promise.withResolvers();
|
|
2293
|
+
await this.writesIdle.promise;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
async movingFile(path, op) {
|
|
2297
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
2298
|
+
while (this.movingFiles.has(path)) await this.movingFiles.get(path);
|
|
2299
|
+
this.movingFiles.set(path, promise);
|
|
2300
|
+
try {
|
|
2301
|
+
await this.writesDrained(path);
|
|
2302
|
+
return await op();
|
|
2303
|
+
} finally {
|
|
2304
|
+
this.movingFiles.delete(path);
|
|
2305
|
+
resolve2();
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2237
2308
|
async truncate(path, size) {
|
|
2309
|
+
const at = normalizePath(path);
|
|
2310
|
+
if (this.renamesInFlight()) await this.writeWaits(at);
|
|
2311
|
+
this.fileWrites.set(at, (this.fileWrites.get(at) ?? 0) + 1);
|
|
2312
|
+
try {
|
|
2313
|
+
await this.truncated(path, size);
|
|
2314
|
+
} finally {
|
|
2315
|
+
this.writeEnded(at);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
async truncated(path, size) {
|
|
2238
2319
|
const handle = await this.existing(path, true);
|
|
2239
2320
|
await this.refuseNode(path, (await this.io(handle.getFile())).size === 0);
|
|
2240
2321
|
const resolve2 = this.ranged || this.remote?.watched();
|
|
@@ -2292,8 +2373,9 @@ var OpfsFs = class {
|
|
|
2292
2373
|
const wanted = entry?.link === void 0 ? path : resolvePath(parentOf3(path), entry.link);
|
|
2293
2374
|
return [resolvePath((await this.locate(parentOf3(wanted), true)).path, baseOf(wanted)), false];
|
|
2294
2375
|
}
|
|
2295
|
-
async fileFor(path) {
|
|
2376
|
+
async fileFor(path, create = true) {
|
|
2296
2377
|
const [target, existed] = await this.writeTarget(path);
|
|
2378
|
+
if (!existed && !create) throw fsError("ENOENT", path);
|
|
2297
2379
|
if (existed) {
|
|
2298
2380
|
const [entry] = await this.meta.get([target]);
|
|
2299
2381
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
@@ -2302,7 +2384,7 @@ var OpfsFs = class {
|
|
|
2302
2384
|
try {
|
|
2303
2385
|
const handle = await this.inDir(
|
|
2304
2386
|
dir,
|
|
2305
|
-
(parent) => this.io(parent.getFileHandle(name2, { create
|
|
2387
|
+
(parent) => this.io(parent.getFileHandle(name2, { create }))
|
|
2306
2388
|
);
|
|
2307
2389
|
if (!existed) this.touch(Date.now(), parentOf3(target));
|
|
2308
2390
|
return [handle, existed, target];
|
|
@@ -2608,11 +2690,12 @@ var OpfsFs = class {
|
|
|
2608
2690
|
this.changed(source.path, destination);
|
|
2609
2691
|
this.touch(Date.now(), parentOf3(source.path), parent.path);
|
|
2610
2692
|
};
|
|
2611
|
-
if (!copying) return place();
|
|
2693
|
+
if (!copying) return sourceStat.isDirectory ? place() : this.movingFile(source.path, place);
|
|
2612
2694
|
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
2613
2695
|
const entry = { from: source.path, to: destination, done: promise };
|
|
2614
2696
|
this.renamingDirs.add(entry);
|
|
2615
2697
|
try {
|
|
2698
|
+
await this.writesDrained(source.path);
|
|
2616
2699
|
const locks = this.locks;
|
|
2617
2700
|
if (locks) {
|
|
2618
2701
|
lock = `${this.renameLocks()}${crypto.randomUUID()}`;
|
|
@@ -2715,7 +2798,7 @@ var OpfsFs = class {
|
|
|
2715
2798
|
return name2.startsWith(this.renameLocks()) || LEGACY_RENAME_LOCK.test(name2);
|
|
2716
2799
|
}
|
|
2717
2800
|
async learnRenames() {
|
|
2718
|
-
for (const { rename } of await this.meta.under(
|
|
2801
|
+
for (const { rename } of await this.meta.under(RENAMES2)) {
|
|
2719
2802
|
if (rename?.lock === void 0 || this.ownLocks.has(rename.lock)) continue;
|
|
2720
2803
|
this.notePeer(rename.lock, [rename.from, rename.to]);
|
|
2721
2804
|
}
|
|
@@ -2804,7 +2887,7 @@ var OpfsFs = class {
|
|
|
2804
2887
|
if (!move.done)
|
|
2805
2888
|
await locks.request(move.lock, async () => {
|
|
2806
2889
|
if (move.done) return;
|
|
2807
|
-
const left = (await this.meta.under(
|
|
2890
|
+
const left = (await this.meta.under(RENAMES2)).filter((entry) => entry.rename?.lock === move.lock).sort(byIntent);
|
|
2808
2891
|
for (const entry of left) await this.finishRename(entry);
|
|
2809
2892
|
});
|
|
2810
2893
|
this.peerMoves.delete(move.lock);
|
|
@@ -2883,7 +2966,7 @@ var OpfsFs = class {
|
|
|
2883
2966
|
}
|
|
2884
2967
|
renamingDirs = /* @__PURE__ */ new Set();
|
|
2885
2968
|
intents = 0;
|
|
2886
|
-
async intend(rename, at = `${
|
|
2969
|
+
async intend(rename, at = `${RENAMES2}/${crypto.randomUUID()}`) {
|
|
2887
2970
|
const record2 = { ...rename, at: Date.now() * 1e3 + this.intents++ % 1e3 };
|
|
2888
2971
|
await this.meta.update(at, () => ({ path: at, rename: record2 }));
|
|
2889
2972
|
return at;
|
|
@@ -2919,7 +3002,7 @@ var OpfsFs = class {
|
|
|
2919
3002
|
const { held: h = [], pending = [] } = await locks.query();
|
|
2920
3003
|
for (const lock of [...h, ...pending]) held.add(lock.name);
|
|
2921
3004
|
}
|
|
2922
|
-
const intents = (await this.meta.under(
|
|
3005
|
+
const intents = (await this.meta.under(RENAMES2)).filter(
|
|
2923
3006
|
(entry) => entry.rename !== void 0 && (!orphaned || locks !== void 0 && entry.rename.lock !== void 0 && !held.has(entry.rename.lock))
|
|
2924
3007
|
).sort(
|
|
2925
3008
|
(a, b) => a.rename.at - b.rename.at
|
|
@@ -2971,6 +3054,7 @@ var OpfsFs = class {
|
|
|
2971
3054
|
);
|
|
2972
3055
|
}
|
|
2973
3056
|
await this.meta.update(entry.path, () => void 0);
|
|
3057
|
+
this.remote?.emit({ paths: [], trees: [], moved: { from, to } });
|
|
2974
3058
|
} finally {
|
|
2975
3059
|
this.renamingDirs.delete(barrier);
|
|
2976
3060
|
resolve2();
|
|
@@ -3288,6 +3372,10 @@ var OpfsFs = class {
|
|
|
3288
3372
|
return removed;
|
|
3289
3373
|
}
|
|
3290
3374
|
};
|
|
3375
|
+
function movedOf(moved2) {
|
|
3376
|
+
const m = moved2;
|
|
3377
|
+
return typeof m?.from === "string" && typeof m.to === "string" ? { from: m.from, to: m.to } : void 0;
|
|
3378
|
+
}
|
|
3291
3379
|
function nothing() {
|
|
3292
3380
|
return void 0;
|
|
3293
3381
|
}
|
|
@@ -7598,7 +7686,7 @@ function satisfies(version, range2) {
|
|
|
7598
7686
|
}
|
|
7599
7687
|
|
|
7600
7688
|
// src/version.ts
|
|
7601
|
-
var KERNEL_VERSION = true ? "1.143.
|
|
7689
|
+
var KERNEL_VERSION = true ? "1.143.6" : "0.0.0-dev";
|
|
7602
7690
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7603
7691
|
function procVersion() {
|
|
7604
7692
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -13033,7 +13121,8 @@ var SYNC_FS_OPS = [
|
|
|
13033
13121
|
"truncate",
|
|
13034
13122
|
"chown",
|
|
13035
13123
|
"lchown",
|
|
13036
|
-
"access"
|
|
13124
|
+
"access",
|
|
13125
|
+
"renames"
|
|
13037
13126
|
];
|
|
13038
13127
|
var HOLD_READ = 4;
|
|
13039
13128
|
var HOLD_WRITE = 8;
|
|
@@ -13081,6 +13170,30 @@ async function readdirStat(fs, dir, g) {
|
|
|
13081
13170
|
const shown = async (name2, stat) => stat && statJson(await callerStat(g, joinName(dir, name2), stat));
|
|
13082
13171
|
return Promise.all(listed.map(async ([name2, stat]) => [name2, await shown(name2, stat)]));
|
|
13083
13172
|
}
|
|
13173
|
+
async function visibleRenames(entry, req) {
|
|
13174
|
+
const answer2 = entry.renames?.(req.offset ?? 0, heldPaths(req.arg2)) ?? { now: 0, renames: [] };
|
|
13175
|
+
const g = guardOf(entry);
|
|
13176
|
+
if (!g?.dac.enforcing) return answer2;
|
|
13177
|
+
const searchable2 = async (path) => {
|
|
13178
|
+
const dir = path.slice(0, Math.max(1, path.lastIndexOf("/")));
|
|
13179
|
+
const w = await walk(g.fs, g.cred, dir, true, g.links).catch(nothing2);
|
|
13180
|
+
if (w === false || w.denied || w.perm === void 0 || !permits(g.cred, w.perm, X_OK))
|
|
13181
|
+
return false;
|
|
13182
|
+
return g.fs.stat(w.path).then((st) => st.isDirectory, nothing2);
|
|
13183
|
+
};
|
|
13184
|
+
const shown = [];
|
|
13185
|
+
for (const [from, to] of answer2.renames) {
|
|
13186
|
+
if (await searchable2(from) && await searchable2(to)) shown.push([from, to]);
|
|
13187
|
+
}
|
|
13188
|
+
return { now: answer2.now, renames: shown };
|
|
13189
|
+
}
|
|
13190
|
+
function nothing2() {
|
|
13191
|
+
return false;
|
|
13192
|
+
}
|
|
13193
|
+
function heldPaths(arg) {
|
|
13194
|
+
const held = JSON.parse(arg ?? "[]");
|
|
13195
|
+
return Array.isArray(held) ? held.filter((path) => typeof path === "string") : [];
|
|
13196
|
+
}
|
|
13084
13197
|
async function usageAt(entry, path) {
|
|
13085
13198
|
if (!entry.statfs) return void 0;
|
|
13086
13199
|
const real = await realTarget(entry.fs, path).catch(() => path);
|
|
@@ -13198,7 +13311,8 @@ async function run(entry, path, req) {
|
|
|
13198
13311
|
const to = fs.resolvePath(cwd, req.arg2 ?? "");
|
|
13199
13312
|
await fs.rename(path, to);
|
|
13200
13313
|
entry.renamed?.(path, to);
|
|
13201
|
-
|
|
13314
|
+
const seq2 = entry.renameSeq?.(path, to);
|
|
13315
|
+
return seq2 === void 0 ? done2 : json2({ seq: seq2 });
|
|
13202
13316
|
}
|
|
13203
13317
|
case "link":
|
|
13204
13318
|
await fs.link(path, fs.resolvePath(cwd, req.arg2 ?? ""), req.mode === 1);
|
|
@@ -13670,6 +13784,7 @@ async function linkFree(fs, path) {
|
|
|
13670
13784
|
}
|
|
13671
13785
|
}
|
|
13672
13786
|
async function dispatchOne(entry, req) {
|
|
13787
|
+
if (req.op === "renames") return json2(await visibleRenames(entry, req));
|
|
13673
13788
|
const result = await dispatchPath(entry, req);
|
|
13674
13789
|
if (result.ok || result.errno !== "ENOENT" || !req.direct || !MISS_OPS.has(req.op) || req.handle !== void 0) {
|
|
13675
13790
|
return result;
|
|
@@ -21871,6 +21986,7 @@ var VfsNodes = class {
|
|
|
21871
21986
|
byId = /* @__PURE__ */ new Map();
|
|
21872
21987
|
keepsOnDisk = false;
|
|
21873
21988
|
changed;
|
|
21989
|
+
movedAway;
|
|
21874
21990
|
dirtied;
|
|
21875
21991
|
fs;
|
|
21876
21992
|
entries;
|
|
@@ -22300,6 +22416,7 @@ function keepingOpen(fs, nodes, changed = () => {
|
|
|
22300
22416
|
await nodes.unlinking(b);
|
|
22301
22417
|
await fs.rename(from, to);
|
|
22302
22418
|
nodes.renamed(a, b);
|
|
22419
|
+
nodes.movedAway?.(a, b);
|
|
22303
22420
|
});
|
|
22304
22421
|
},
|
|
22305
22422
|
writeFile: async (path, content, owner) => {
|
|
@@ -24523,6 +24640,8 @@ function holdingToken(opts, holds2, caller) {
|
|
|
24523
24640
|
noLinks: opts.noLinks,
|
|
24524
24641
|
cwd: opts.cwd,
|
|
24525
24642
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
24643
|
+
...opts.renames ? { renames: opts.renames } : {},
|
|
24644
|
+
...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
|
|
24526
24645
|
hold: (path, on, open2, real, handle) => holds2.hold(path, on, open2, real, handle),
|
|
24527
24646
|
keptFor: (handle) => holds2.keptFor(handle),
|
|
24528
24647
|
unlinked: (path) => holds2.keptAt(path),
|
|
@@ -25892,6 +26011,43 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
25892
26011
|
};
|
|
25893
26012
|
}
|
|
25894
26013
|
|
|
26014
|
+
// src/kernel/rename-log.ts
|
|
26015
|
+
var RENAME_LOG_SIZE = 4096;
|
|
26016
|
+
function within9(path, root) {
|
|
26017
|
+
return path === root || path.startsWith(root === "/" ? "/" : `${root}/`);
|
|
26018
|
+
}
|
|
26019
|
+
var RenameLog = class {
|
|
26020
|
+
changes;
|
|
26021
|
+
entries = [];
|
|
26022
|
+
constructor(changes) {
|
|
26023
|
+
this.changes = changes;
|
|
26024
|
+
}
|
|
26025
|
+
add(from, to) {
|
|
26026
|
+
const seq2 = this.changes.renamed();
|
|
26027
|
+
this.entries.push({ seq: seq2, from, to });
|
|
26028
|
+
if (this.entries.length > RENAME_LOG_SIZE) this.entries.shift();
|
|
26029
|
+
return seq2;
|
|
26030
|
+
}
|
|
26031
|
+
seqOf(from, to) {
|
|
26032
|
+
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
26033
|
+
const entry = this.entries[i];
|
|
26034
|
+
if (entry.from === from && entry.to === to) return entry.seq;
|
|
26035
|
+
}
|
|
26036
|
+
return void 0;
|
|
26037
|
+
}
|
|
26038
|
+
since(seen, held) {
|
|
26039
|
+
const now = this.entries.at(-1)?.seq ?? seen;
|
|
26040
|
+
const renames = [];
|
|
26041
|
+
let paths = [...held];
|
|
26042
|
+
for (const { seq: seq2, from, to } of this.entries) {
|
|
26043
|
+
if (seq2 <= seen || !paths.some((path) => within9(path, from))) continue;
|
|
26044
|
+
renames.push([from, to]);
|
|
26045
|
+
paths = paths.map((path) => within9(path, from) ? to + path.slice(from.length) : path);
|
|
26046
|
+
}
|
|
26047
|
+
return { now, renames };
|
|
26048
|
+
}
|
|
26049
|
+
};
|
|
26050
|
+
|
|
25895
26051
|
// src/kernel/net/sealed-scrubs.ts
|
|
25896
26052
|
function addTo(tree2, host, secrets) {
|
|
25897
26053
|
const entry = tree2.get(host) ?? { secrets: [], version: 0, scrubber: void 0 };
|
|
@@ -28649,6 +28805,7 @@ var Launcher = class {
|
|
|
28649
28805
|
hostname;
|
|
28650
28806
|
watchers = new FsWatchers();
|
|
28651
28807
|
changes = new FileChanges();
|
|
28808
|
+
renameLog = new RenameLog(this.changes);
|
|
28652
28809
|
cwds = new CwdTable(async (path) => {
|
|
28653
28810
|
const { dev, ino } = await this.base.stat(path);
|
|
28654
28811
|
return `${dev ?? 0}:${ino}`;
|
|
@@ -28787,6 +28944,7 @@ var Launcher = class {
|
|
|
28787
28944
|
this.openFiles.add(this.nodes);
|
|
28788
28945
|
options.fs.onPeer?.(() => this.flushOpen());
|
|
28789
28946
|
options.fs.remoteChanges?.((change) => {
|
|
28947
|
+
if (change.moved) this.moved(change.moved.from, change.moved.to);
|
|
28790
28948
|
this.changes.flush();
|
|
28791
28949
|
this.cwds.touched(change.paths, change.trees);
|
|
28792
28950
|
this.rewritten(change.paths, change.trees);
|
|
@@ -29803,6 +29961,8 @@ var Launcher = class {
|
|
|
29803
29961
|
unlinkGate: stack.unlinked.gate,
|
|
29804
29962
|
replacements: stack.unlinked,
|
|
29805
29963
|
statfs: (path) => this.mounts.statfs(path),
|
|
29964
|
+
renames: (since, held) => this.renameLog.since(since, held),
|
|
29965
|
+
renameSeq: (from, to) => this.renameLog.seqOf(from, to),
|
|
29806
29966
|
mounts: () => this.mounts.list(),
|
|
29807
29967
|
mount: (call, signal) => this.processMount(pid, call, signal),
|
|
29808
29968
|
umount: (target, flags2) => this.processUmount(pid, target, flags2),
|
|
@@ -30750,8 +30910,15 @@ var Launcher = class {
|
|
|
30750
30910
|
const target = command && (command.shows ?? command.script ?? command.wasm);
|
|
30751
30911
|
return target === void 0 ? void 0 : { path: target, ...owner ? { owner } : {} };
|
|
30752
30912
|
}
|
|
30913
|
+
moved(from, to, source) {
|
|
30914
|
+
this.renameLog.add(from, to);
|
|
30915
|
+
if (source) return;
|
|
30916
|
+
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
30917
|
+
this.watchers.moved(from, to);
|
|
30918
|
+
}
|
|
30753
30919
|
processChain(fs, nodes, unlinked) {
|
|
30754
30920
|
nodes.changed = (path) => this.changes.publish(path);
|
|
30921
|
+
nodes.movedAway = (from, to) => this.moved(from, to, nodes);
|
|
30755
30922
|
nodes.dirtied = (delta) => this.changes.dirtied(delta);
|
|
30756
30923
|
return unlinked.wrap(keepingOpen(fs, nodes, (path) => this.changes.publish(path)));
|
|
30757
30924
|
}
|