@ai-ecoverse/slicc-kernel 1.142.0 → 1.142.2
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 +15 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +504 -108
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +3 -0
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +13 -2
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +501 -108
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +13 -2
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/meta.d.ts +2 -0
- package/dist/types/fs/opfs.d.ts +33 -0
- package/dist/types/fs/remote.d.ts +15 -0
- package/dist/types/fs/types.d.ts +7 -0
- package/dist/types/kernel/proc-info.d.ts +7 -0
- package/package.json +5 -5
package/dist/kernel-worker.js
CHANGED
|
@@ -165,6 +165,9 @@ var IndexedDbMeta = class {
|
|
|
165
165
|
};
|
|
166
166
|
this.channel.unref?.();
|
|
167
167
|
}
|
|
168
|
+
forgetTrees(trees) {
|
|
169
|
+
this.drop({ trees: [...trees] });
|
|
170
|
+
}
|
|
168
171
|
drop({ paths = [], trees = [] }) {
|
|
169
172
|
this.generation++;
|
|
170
173
|
for (const path of paths) this.cache.delete(path);
|
|
@@ -353,6 +356,90 @@ async function openMeta(name2, factory) {
|
|
|
353
356
|
return new IndexedDbMeta(await openMetaDb(name2, factory));
|
|
354
357
|
}
|
|
355
358
|
|
|
359
|
+
// src/fs/changes.ts
|
|
360
|
+
var GEN = 0;
|
|
361
|
+
var RING = 1;
|
|
362
|
+
var RING_SIZE = 4096;
|
|
363
|
+
var SLOT = 2;
|
|
364
|
+
var SHARED_TTL_MS = 100;
|
|
365
|
+
var DIRTY = RING + RING_SIZE * SLOT;
|
|
366
|
+
var FOREIGN = DIRTY + 1;
|
|
367
|
+
var CHANGES_BYTES = (FOREIGN + 1) * 4;
|
|
368
|
+
function changeHash(path) {
|
|
369
|
+
let h = 2166136261;
|
|
370
|
+
for (let i = 0; i < path.length; i++) {
|
|
371
|
+
h ^= path.charCodeAt(i);
|
|
372
|
+
h = Math.imul(h, 16777619);
|
|
373
|
+
}
|
|
374
|
+
return h === 0 ? 1 : h;
|
|
375
|
+
}
|
|
376
|
+
function normal(path) {
|
|
377
|
+
const parts2 = [];
|
|
378
|
+
for (const part of path.split("/")) {
|
|
379
|
+
if (part === "" || part === ".") continue;
|
|
380
|
+
if (part === "..") parts2.pop();
|
|
381
|
+
else parts2.push(part);
|
|
382
|
+
}
|
|
383
|
+
return `/${parts2.join("/")}`;
|
|
384
|
+
}
|
|
385
|
+
var FileChanges = class {
|
|
386
|
+
sab;
|
|
387
|
+
view;
|
|
388
|
+
constructor(sab = new SharedArrayBuffer(CHANGES_BYTES)) {
|
|
389
|
+
this.sab = sab;
|
|
390
|
+
this.view = new Int32Array(sab);
|
|
391
|
+
}
|
|
392
|
+
dirtied(delta) {
|
|
393
|
+
Atomics.add(this.view, DIRTY, delta);
|
|
394
|
+
}
|
|
395
|
+
foreign(on) {
|
|
396
|
+
Atomics.store(this.view, FOREIGN, on ? 1 : 0);
|
|
397
|
+
}
|
|
398
|
+
flush() {
|
|
399
|
+
Atomics.add(this.view, GEN, RING_SIZE + 1);
|
|
400
|
+
}
|
|
401
|
+
publish(...paths) {
|
|
402
|
+
for (const path of paths) {
|
|
403
|
+
const g = Atomics.add(this.view, GEN, 1) + 1 | 0;
|
|
404
|
+
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
405
|
+
Atomics.store(this.view, at, 0);
|
|
406
|
+
Atomics.store(this.view, at + 1, changeHash(normal(path)));
|
|
407
|
+
Atomics.store(this.view, at, g);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
var ChangeView = class {
|
|
412
|
+
view;
|
|
413
|
+
constructor(sab) {
|
|
414
|
+
this.view = new Int32Array(sab);
|
|
415
|
+
}
|
|
416
|
+
now() {
|
|
417
|
+
return Atomics.load(this.view, GEN);
|
|
418
|
+
}
|
|
419
|
+
clean() {
|
|
420
|
+
return this.view.length > DIRTY && Atomics.load(this.view, DIRTY) === 0;
|
|
421
|
+
}
|
|
422
|
+
foreign() {
|
|
423
|
+
return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
|
|
424
|
+
}
|
|
425
|
+
changedSince(seen, path) {
|
|
426
|
+
const now = Atomics.load(this.view, GEN);
|
|
427
|
+
const distance = now - seen >>> 0;
|
|
428
|
+
if (distance === 0) return { now, changed: false };
|
|
429
|
+
if (distance > RING_SIZE) return { now, changed: true };
|
|
430
|
+
const hash = changeHash(normal(path));
|
|
431
|
+
for (let i = 1; i <= distance; i++) {
|
|
432
|
+
const g = seen + i | 0;
|
|
433
|
+
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
434
|
+
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
435
|
+
const hit = Atomics.load(this.view, at + 1) === hash;
|
|
436
|
+
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
437
|
+
if (hit) return { now, changed: true };
|
|
438
|
+
}
|
|
439
|
+
return { now, changed: false };
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
356
443
|
// src/fs/notice.ts
|
|
357
444
|
function dirsChannel(metadata) {
|
|
358
445
|
return `slicc-kernel-dirs:${metadata}`;
|
|
@@ -881,6 +968,8 @@ var ANNOUNCE_WAIT_MS = 500;
|
|
|
881
968
|
var PRUNE_EVERY_MS = 3e4;
|
|
882
969
|
var MOURN_TRIES = 5;
|
|
883
970
|
var MOURN_RETRY_MS = 100;
|
|
971
|
+
var RENAME_ACK_MAX_MS = 1e4;
|
|
972
|
+
var ANNOUNCE_POLL_MS = 20;
|
|
884
973
|
function lockManager() {
|
|
885
974
|
return globalThis.navigator?.locks;
|
|
886
975
|
}
|
|
@@ -904,6 +993,9 @@ var RemoteWatch = class {
|
|
|
904
993
|
quiet;
|
|
905
994
|
crowd;
|
|
906
995
|
gone;
|
|
996
|
+
renaming;
|
|
997
|
+
renamed;
|
|
998
|
+
ackers = /* @__PURE__ */ new Set();
|
|
907
999
|
told;
|
|
908
1000
|
counted = 0;
|
|
909
1001
|
recount() {
|
|
@@ -931,7 +1023,7 @@ var RemoteWatch = class {
|
|
|
931
1023
|
this.settled = true;
|
|
932
1024
|
this.recount();
|
|
933
1025
|
});
|
|
934
|
-
this.channel.postMessage({ hello: this.tab });
|
|
1026
|
+
this.channel.postMessage({ hello: this.tab, renames: true });
|
|
935
1027
|
}
|
|
936
1028
|
async join() {
|
|
937
1029
|
if (!this.locks) return;
|
|
@@ -952,6 +1044,20 @@ var RemoteWatch = class {
|
|
|
952
1044
|
await this.joined;
|
|
953
1045
|
return this.peers.size > 0;
|
|
954
1046
|
}
|
|
1047
|
+
async joinedAll(cap) {
|
|
1048
|
+
if (!this.locks) return true;
|
|
1049
|
+
const prefix = `${this.name}:`;
|
|
1050
|
+
const began = performance.now();
|
|
1051
|
+
for (; ; ) {
|
|
1052
|
+
const held = ((await this.locks.query()).held ?? []).map((lock) => lock.name ?? "");
|
|
1053
|
+
const silent = held.some(
|
|
1054
|
+
(name2) => name2.startsWith(prefix) && name2 !== this.lockOf(this.tab) && !this.peers.has(name2.slice(prefix.length))
|
|
1055
|
+
);
|
|
1056
|
+
if (!silent) return true;
|
|
1057
|
+
if (performance.now() - began >= cap) return false;
|
|
1058
|
+
await new Promise((resolve2) => setTimeout(resolve2, ANNOUNCE_POLL_MS));
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
955
1061
|
crowded() {
|
|
956
1062
|
return !this.settled || this.peers.size > 0;
|
|
957
1063
|
}
|
|
@@ -959,7 +1065,11 @@ var RemoteWatch = class {
|
|
|
959
1065
|
return `${this.name}:${tab}`;
|
|
960
1066
|
}
|
|
961
1067
|
receive(data) {
|
|
1068
|
+
const sender = data.hello ?? data.here;
|
|
1069
|
+
if (sender !== void 0 && data.renames) this.ackers.add(sender);
|
|
962
1070
|
if (data.hello !== void 0) this.greeted(data.hello);
|
|
1071
|
+
if (data.renaming !== void 0 && data.tab !== void 0) this.heard(data);
|
|
1072
|
+
if (data.renamed !== void 0) this.renamed?.(data.renamed);
|
|
963
1073
|
if (data.here !== void 0 && data.to === this.tab) {
|
|
964
1074
|
this.arrived(data.here);
|
|
965
1075
|
this.met?.();
|
|
@@ -991,6 +1101,7 @@ var RemoteWatch = class {
|
|
|
991
1101
|
this.mourned.delete(peer);
|
|
992
1102
|
this.others.delete(peer);
|
|
993
1103
|
this.peers.delete(peer);
|
|
1104
|
+
this.ackers.delete(peer);
|
|
994
1105
|
this.rebuild();
|
|
995
1106
|
this.recount();
|
|
996
1107
|
this.gone?.();
|
|
@@ -1002,12 +1113,18 @@ var RemoteWatch = class {
|
|
|
1002
1113
|
greeted(peer) {
|
|
1003
1114
|
this.arrived(peer);
|
|
1004
1115
|
const answer2 = () => {
|
|
1005
|
-
this.channel.postMessage({ here: this.tab, to: peer });
|
|
1116
|
+
this.channel.postMessage({ here: this.tab, to: peer, renames: true });
|
|
1006
1117
|
if (this.mine.length > 0) void this.announce(this.mine);
|
|
1007
1118
|
};
|
|
1008
1119
|
if (this.quiet) void this.quiet().then(answer2, answer2);
|
|
1009
1120
|
else answer2();
|
|
1010
1121
|
}
|
|
1122
|
+
heard({ tab, renaming, seq: seq2 }) {
|
|
1123
|
+
const ack = () => this.channel.postMessage({ ack: seq2, from: this.tab, to: tab });
|
|
1124
|
+
const heard = this.renaming?.(renaming);
|
|
1125
|
+
if (heard !== void 0) void heard.then(ack, ack);
|
|
1126
|
+
else ack();
|
|
1127
|
+
}
|
|
1011
1128
|
announced({ tab, paths, seq: seq2 }) {
|
|
1012
1129
|
const from = tab;
|
|
1013
1130
|
this.arrived(from);
|
|
@@ -1034,6 +1151,7 @@ var RemoteWatch = class {
|
|
|
1034
1151
|
if (!held.has(this.lockOf(tab))) {
|
|
1035
1152
|
if (this.peers.delete(tab)) left = true;
|
|
1036
1153
|
this.others.delete(tab);
|
|
1154
|
+
this.ackers.delete(tab);
|
|
1037
1155
|
}
|
|
1038
1156
|
}
|
|
1039
1157
|
this.rebuild();
|
|
@@ -1055,7 +1173,34 @@ var RemoteWatch = class {
|
|
|
1055
1173
|
this.mine = [...paths];
|
|
1056
1174
|
const seq2 = ++this.seq;
|
|
1057
1175
|
this.channel.postMessage({ tab: this.tab, paths: this.mine, seq: seq2 });
|
|
1058
|
-
|
|
1176
|
+
return this.acks(seq2, this.peers);
|
|
1177
|
+
}
|
|
1178
|
+
renamingTree(rename, cap = RENAME_ACK_MAX_MS) {
|
|
1179
|
+
const seq2 = ++this.seq;
|
|
1180
|
+
this.channel.postMessage({ tab: this.tab, renaming: rename, seq: seq2 });
|
|
1181
|
+
const left = new Set(this.ackers);
|
|
1182
|
+
if (left.size === 0) return Promise.resolve([]);
|
|
1183
|
+
const began = performance.now();
|
|
1184
|
+
return new Promise((resolve2) => {
|
|
1185
|
+
const done5 = () => {
|
|
1186
|
+
clearInterval(timer);
|
|
1187
|
+
this.waiting.delete(seq2);
|
|
1188
|
+
resolve2([...left]);
|
|
1189
|
+
};
|
|
1190
|
+
const timer = setInterval(() => {
|
|
1191
|
+
void this.prune().then(() => {
|
|
1192
|
+
for (const peer of left) if (!this.ackers.has(peer)) left.delete(peer);
|
|
1193
|
+
if (left.size === 0 || performance.now() - began >= cap) done5();
|
|
1194
|
+
});
|
|
1195
|
+
}, ANNOUNCE_WAIT_MS);
|
|
1196
|
+
this.waiting.set(seq2, { left, done: done5 });
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
renamedTree(lock) {
|
|
1200
|
+
this.channel.postMessage({ renamed: lock });
|
|
1201
|
+
}
|
|
1202
|
+
acks(seq2, from) {
|
|
1203
|
+
if (from.size === 0) return Promise.resolve();
|
|
1059
1204
|
return new Promise((resolve2) => {
|
|
1060
1205
|
const done5 = () => {
|
|
1061
1206
|
clearTimeout(timer);
|
|
@@ -1066,7 +1211,7 @@ var RemoteWatch = class {
|
|
|
1066
1211
|
done5();
|
|
1067
1212
|
void this.prune();
|
|
1068
1213
|
}, ANNOUNCE_WAIT_MS);
|
|
1069
|
-
this.waiting.set(seq2, { left: new Set(
|
|
1214
|
+
this.waiting.set(seq2, { left: new Set(from), done: done5 });
|
|
1070
1215
|
});
|
|
1071
1216
|
}
|
|
1072
1217
|
emit(change) {
|
|
@@ -1129,6 +1274,14 @@ var RECONCILE_LISTINGS = 8;
|
|
|
1129
1274
|
var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
|
|
1130
1275
|
var RENAMES = "/.slicc-renames";
|
|
1131
1276
|
var RENAME_LOCK = "slicc-rename:";
|
|
1277
|
+
var RENAME_ADMIT = "slicc-rename-admit:";
|
|
1278
|
+
var escapeRoot = (name2) => name2.replace(/[%:]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
1279
|
+
var LEGACY_RENAME_LOCK = /^slicc-rename:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
1280
|
+
var PAIRED = /* @__PURE__ */ new Set(["rename", "link", "copyFile"]);
|
|
1281
|
+
var LISTINGS = /* @__PURE__ */ new Set(["readdir", "readdirStat"]);
|
|
1282
|
+
var RETRY = /* @__PURE__ */ Symbol("retry");
|
|
1283
|
+
var ACK_SAMPLES = 4096;
|
|
1284
|
+
var INTENT_POLL_MS = 5;
|
|
1132
1285
|
function movable(handle) {
|
|
1133
1286
|
return typeof handle.move === "function";
|
|
1134
1287
|
}
|
|
@@ -1173,6 +1326,7 @@ function sidecar(meta) {
|
|
|
1173
1326
|
for (const { path, change } of changes) await ops.update(path, change);
|
|
1174
1327
|
};
|
|
1175
1328
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
1329
|
+
if (meta.forgetTrees) ops.forgetTrees = meta.forgetTrees.bind(meta);
|
|
1176
1330
|
const { removeFile } = meta;
|
|
1177
1331
|
if (removeFile)
|
|
1178
1332
|
ops.removeFile = (path) => removeFile.call(meta, path).catch((err) => {
|
|
@@ -1287,6 +1441,7 @@ var OpfsFs = class {
|
|
|
1287
1441
|
locks;
|
|
1288
1442
|
lockPrefix;
|
|
1289
1443
|
rootName;
|
|
1444
|
+
renamePrefix;
|
|
1290
1445
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
1291
1446
|
this.root = root;
|
|
1292
1447
|
this.meta = sidecar(meta);
|
|
@@ -1294,11 +1449,22 @@ var OpfsFs = class {
|
|
|
1294
1449
|
this.locks = options.locks === void 0 ? lockManager() : options.locks ?? void 0;
|
|
1295
1450
|
this.lockPrefix = `slicc-excl:${channel ?? ""}:`;
|
|
1296
1451
|
this.rootName = channel;
|
|
1452
|
+
this.renamePrefix = `${RENAME_LOCK}${escapeRoot(channel ?? "")}:`;
|
|
1297
1453
|
this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
|
|
1298
1454
|
this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`, { locks: this.locks ?? null });
|
|
1299
1455
|
if (this.remote) {
|
|
1300
1456
|
this.remote.quiet = () => this.quiet().then(() => this.settle?.());
|
|
1301
|
-
this.remote.gone = () =>
|
|
1457
|
+
this.remote.gone = () => {
|
|
1458
|
+
void this.orphans();
|
|
1459
|
+
for (const move of [...this.peerMoves.values()]) void this.peerMoved(move);
|
|
1460
|
+
};
|
|
1461
|
+
this.remote.renaming = (rename) => this.heardRename(rename);
|
|
1462
|
+
this.remote.renamed = (lock) => {
|
|
1463
|
+
const move = this.peerMoves.get(lock);
|
|
1464
|
+
if (!move) return;
|
|
1465
|
+
move.done = true;
|
|
1466
|
+
void this.peerMoved(move);
|
|
1467
|
+
};
|
|
1302
1468
|
}
|
|
1303
1469
|
if (this.channel) {
|
|
1304
1470
|
const remote = this.remote;
|
|
@@ -2342,16 +2508,27 @@ var OpfsFs = class {
|
|
|
2342
2508
|
throw fsError("EPERM", `${from}: this file system has no hard links`);
|
|
2343
2509
|
}
|
|
2344
2510
|
async rename(from, to) {
|
|
2511
|
+
const call = this.renameCall;
|
|
2512
|
+
this.renameCall = void 0;
|
|
2345
2513
|
if (from === to) return;
|
|
2514
|
+
for (; ; ) {
|
|
2515
|
+
try {
|
|
2516
|
+
return await this.renameOnce(from, to, call);
|
|
2517
|
+
} catch (err) {
|
|
2518
|
+
if (err !== RETRY) throw err;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
async renameOnce(from, to, call) {
|
|
2346
2523
|
const source = await this.locate(from, false);
|
|
2347
2524
|
this.refuse(source.path, true);
|
|
2348
2525
|
this.forget(source.path);
|
|
2349
2526
|
const parent = await this.locate(parentOf3(to), true);
|
|
2350
2527
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
2351
2528
|
this.refuse(destination, true);
|
|
2352
|
-
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
2529
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to, call));
|
|
2353
2530
|
}
|
|
2354
|
-
async moveTo(source, parent, destination, to) {
|
|
2531
|
+
async moveTo(source, parent, destination, to, call) {
|
|
2355
2532
|
const sourceStat = await this.describe(source);
|
|
2356
2533
|
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
2357
2534
|
const target = await this.exactly(() => this.locate(destination, false)).catch((err) => {
|
|
@@ -2386,6 +2563,7 @@ var OpfsFs = class {
|
|
|
2386
2563
|
const name2 = baseOf(destination);
|
|
2387
2564
|
const swap = targetStat?.isDirectory === true;
|
|
2388
2565
|
let lock;
|
|
2566
|
+
const hooks = {};
|
|
2389
2567
|
const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
|
|
2390
2568
|
const copying = sourceStat.isDirectory && !movable(source.handle);
|
|
2391
2569
|
const staged = resolvePath(parent.path, staging);
|
|
@@ -2394,8 +2572,15 @@ var OpfsFs = class {
|
|
|
2394
2572
|
const copies = /* @__PURE__ */ new Map();
|
|
2395
2573
|
const root = { ino: inodeOf(source.path), ...moving };
|
|
2396
2574
|
const owned4 = lock ? { lock } : {};
|
|
2575
|
+
hooks.notify?.();
|
|
2397
2576
|
const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
|
|
2398
2577
|
const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
|
|
2578
|
+
await hooks.started?.().catch(async (err) => {
|
|
2579
|
+
for (const intent of [first, second]) {
|
|
2580
|
+
if (intent) await this.meta.update(intent, () => void 0);
|
|
2581
|
+
}
|
|
2582
|
+
throw err;
|
|
2583
|
+
});
|
|
2399
2584
|
const moved2 = await this.replacingTarget(
|
|
2400
2585
|
targetStat !== null,
|
|
2401
2586
|
() => this.place(source.handle, dir, staging, copies)
|
|
@@ -2429,14 +2614,270 @@ var OpfsFs = class {
|
|
|
2429
2614
|
try {
|
|
2430
2615
|
const locks = this.locks;
|
|
2431
2616
|
if (locks) {
|
|
2432
|
-
lock = `${
|
|
2433
|
-
|
|
2617
|
+
lock = `${this.renameLocks()}${crypto.randomUUID()}`;
|
|
2618
|
+
this.ownLocks.add(lock);
|
|
2619
|
+
call?.release();
|
|
2620
|
+
await this.admitted(locks, lock, source.path, destination, place, hooks);
|
|
2434
2621
|
} else await place();
|
|
2435
2622
|
} finally {
|
|
2623
|
+
if (lock) this.ownLocks.delete(lock);
|
|
2436
2624
|
this.renamingDirs.delete(entry);
|
|
2437
2625
|
resolve2();
|
|
2438
2626
|
}
|
|
2439
2627
|
}
|
|
2628
|
+
async admitted(locks, lock, from, to, place, hooks) {
|
|
2629
|
+
const remote = this.remote;
|
|
2630
|
+
if (remote && !this.shared() && !await remote.joinedAll(RENAME_ACK_MAX_MS)) {
|
|
2631
|
+
this.ackBusy++;
|
|
2632
|
+
console.warn(
|
|
2633
|
+
`slicc-kernel: renaming ${from} to ${to} gave up (EBUSY): a tab sharing the root did not finish joining in ${RENAME_ACK_MAX_MS} ms (#1140)`
|
|
2634
|
+
);
|
|
2635
|
+
throw fsError("EBUSY", from);
|
|
2636
|
+
}
|
|
2637
|
+
if (!remote || !this.shared()) {
|
|
2638
|
+
await locks.request(lock, place);
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2641
|
+
let clash;
|
|
2642
|
+
let run2;
|
|
2643
|
+
await locks.request(`${RENAME_ADMIT}${this.rootName ?? ""}`, async () => {
|
|
2644
|
+
if (await this.renamingElsewhere()) await this.learnRenames();
|
|
2645
|
+
clash = this.clashing(from, to);
|
|
2646
|
+
if (clash) return;
|
|
2647
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
2648
|
+
let told;
|
|
2649
|
+
hooks.notify = () => {
|
|
2650
|
+
told = remote.renamingTree({ from, to, lock });
|
|
2651
|
+
};
|
|
2652
|
+
hooks.started = async () => {
|
|
2653
|
+
resolve2();
|
|
2654
|
+
this.renameAcks++;
|
|
2655
|
+
const at = performance.now();
|
|
2656
|
+
const stuck = await told;
|
|
2657
|
+
this.ackMs.push(performance.now() - at);
|
|
2658
|
+
if (this.ackMs.length > ACK_SAMPLES) this.ackMs.shift();
|
|
2659
|
+
if (stuck.length === 0) return;
|
|
2660
|
+
this.ackBusy++;
|
|
2661
|
+
console.warn(
|
|
2662
|
+
`slicc-kernel: renaming ${from} to ${to} gave up (EBUSY): peer tab ${stuck.join(", ")} is alive but did not answer in ${RENAME_ACK_MAX_MS} ms (#1140)`
|
|
2663
|
+
);
|
|
2664
|
+
throw fsError("EBUSY", from);
|
|
2665
|
+
};
|
|
2666
|
+
run2 = locks.request(lock, async () => {
|
|
2667
|
+
await place();
|
|
2668
|
+
remote.renamedTree(lock);
|
|
2669
|
+
});
|
|
2670
|
+
await Promise.race([promise, run2.then(nothing, nothing)]);
|
|
2671
|
+
});
|
|
2672
|
+
if (clash) {
|
|
2673
|
+
this.peerWaited++;
|
|
2674
|
+
await this.peerMoved(clash);
|
|
2675
|
+
throw RETRY;
|
|
2676
|
+
}
|
|
2677
|
+
await run2;
|
|
2678
|
+
}
|
|
2679
|
+
renameAcks = 0;
|
|
2680
|
+
ackBusy = 0;
|
|
2681
|
+
ackMs = [];
|
|
2682
|
+
ownLocks = /* @__PURE__ */ new Set();
|
|
2683
|
+
peerMoves = /* @__PURE__ */ new Map();
|
|
2684
|
+
peerWaits = /* @__PURE__ */ new Map();
|
|
2685
|
+
inflight = /* @__PURE__ */ new Set();
|
|
2686
|
+
renameCall;
|
|
2687
|
+
looking;
|
|
2688
|
+
lookedAt = Number.NEGATIVE_INFINITY;
|
|
2689
|
+
peerWaited = 0;
|
|
2690
|
+
queries = 0;
|
|
2691
|
+
renameWaits() {
|
|
2692
|
+
return {
|
|
2693
|
+
acks: this.renameAcks,
|
|
2694
|
+
busy: this.ackBusy,
|
|
2695
|
+
waits: this.peerWaited,
|
|
2696
|
+
queries: this.queries,
|
|
2697
|
+
ackMs: this.ackMs
|
|
2698
|
+
};
|
|
2699
|
+
}
|
|
2700
|
+
notePeer(lock, tree2) {
|
|
2701
|
+
let known = this.peerMoves.get(lock);
|
|
2702
|
+
if (!known) {
|
|
2703
|
+
known = { lock, trees: [] };
|
|
2704
|
+
this.peerMoves.set(lock, known);
|
|
2705
|
+
}
|
|
2706
|
+
if (!known.trees.some(([a, b]) => a === tree2[0] && b === tree2[1])) known.trees.push(tree2);
|
|
2707
|
+
return known;
|
|
2708
|
+
}
|
|
2709
|
+
renameLocks() {
|
|
2710
|
+
return this.renamePrefix;
|
|
2711
|
+
}
|
|
2712
|
+
renameHere(name2) {
|
|
2713
|
+
if (name2 === void 0) return false;
|
|
2714
|
+
return name2.startsWith(this.renameLocks()) || LEGACY_RENAME_LOCK.test(name2);
|
|
2715
|
+
}
|
|
2716
|
+
async learnRenames() {
|
|
2717
|
+
for (const { rename } of await this.meta.under(RENAMES)) {
|
|
2718
|
+
if (rename?.lock === void 0 || this.ownLocks.has(rename.lock)) continue;
|
|
2719
|
+
this.notePeer(rename.lock, [rename.from, rename.to]);
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
async renamingElsewhere() {
|
|
2723
|
+
const { held = [] } = await this.locks.query();
|
|
2724
|
+
return held.some(({ name: name2 }) => this.renameHere(name2) && !this.ownLocks.has(name2));
|
|
2725
|
+
}
|
|
2726
|
+
lookForRenames() {
|
|
2727
|
+
const locks = this.locks;
|
|
2728
|
+
const age = performance.now() - this.lookedAt;
|
|
2729
|
+
if (!locks || age < SHARED_TTL_MS / 2) return Promise.resolve();
|
|
2730
|
+
this.looking ??= (async () => {
|
|
2731
|
+
for (; ; ) {
|
|
2732
|
+
const asked = performance.now();
|
|
2733
|
+
this.queries++;
|
|
2734
|
+
const { held = [] } = await locks.query();
|
|
2735
|
+
const unknown = () => held.some(
|
|
2736
|
+
({ name: name2 }) => this.renameHere(name2) && !this.ownLocks.has(name2) && !this.peerMoves.has(name2)
|
|
2737
|
+
);
|
|
2738
|
+
if (unknown()) await this.learnRenames();
|
|
2739
|
+
if (!unknown()) {
|
|
2740
|
+
this.lookedAt = asked;
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2743
|
+
await new Promise((resolve2) => setTimeout(resolve2, INTENT_POLL_MS));
|
|
2744
|
+
}
|
|
2745
|
+
})().finally(() => {
|
|
2746
|
+
this.looking = void 0;
|
|
2747
|
+
});
|
|
2748
|
+
if (age >= SHARED_TTL_MS) return this.looking;
|
|
2749
|
+
this.looking.catch(nothing);
|
|
2750
|
+
return Promise.resolve();
|
|
2751
|
+
}
|
|
2752
|
+
async heardRename({ from, to, lock }) {
|
|
2753
|
+
if (this.ownLocks.has(lock)) return;
|
|
2754
|
+
this.notePeer(lock, [from, to]);
|
|
2755
|
+
this.lookedAt = performance.now();
|
|
2756
|
+
const trees = [[from, to]];
|
|
2757
|
+
const running = [...this.inflight];
|
|
2758
|
+
const reached = await Promise.all(
|
|
2759
|
+
running.map(async (op) => {
|
|
2760
|
+
if (op.paths.some((at) => touches(at, trees))) return true;
|
|
2761
|
+
for (const at of op.paths) {
|
|
2762
|
+
const forms = await this.resolvedForms(at);
|
|
2763
|
+
if (forms.some((form) => touches(form, trees))) return true;
|
|
2764
|
+
}
|
|
2765
|
+
return false;
|
|
2766
|
+
})
|
|
2767
|
+
);
|
|
2768
|
+
const busy = running.filter((op, i) => reached[i] && this.inflight.has(op));
|
|
2769
|
+
if (this.aloneCalls > 0) {
|
|
2770
|
+
this.aloneDrain ??= Promise.withResolvers();
|
|
2771
|
+
busy.push({ paths: [], waiting: this.aloneDrain, release: nothing });
|
|
2772
|
+
}
|
|
2773
|
+
await Promise.all(
|
|
2774
|
+
busy.map((op) => {
|
|
2775
|
+
op.waiting ??= Promise.withResolvers();
|
|
2776
|
+
return op.waiting.promise;
|
|
2777
|
+
})
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
peerAt(at, listing) {
|
|
2781
|
+
for (const move of this.peerMoves.values()) {
|
|
2782
|
+
if (this.ownLocks.has(move.lock)) continue;
|
|
2783
|
+
if (touches(at, move.trees, listing)) return move;
|
|
2784
|
+
}
|
|
2785
|
+
return void 0;
|
|
2786
|
+
}
|
|
2787
|
+
clashing(from, to) {
|
|
2788
|
+
for (const move of this.peerMoves.values()) {
|
|
2789
|
+
for (const tree2 of move.trees) {
|
|
2790
|
+
for (const mine of [from, to]) {
|
|
2791
|
+
if (tree2.some((theirs) => within2(mine, theirs) || within2(theirs, mine))) return move;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
return void 0;
|
|
2796
|
+
}
|
|
2797
|
+
peerMoved(move) {
|
|
2798
|
+
const locks = this.locks;
|
|
2799
|
+
let wait2 = this.peerWaits.get(move.lock);
|
|
2800
|
+
if (wait2 !== void 0) return wait2;
|
|
2801
|
+
wait2 = (async () => {
|
|
2802
|
+
if (!move.done)
|
|
2803
|
+
await locks.request(move.lock, async () => {
|
|
2804
|
+
if (move.done) return;
|
|
2805
|
+
const left = (await this.meta.under(RENAMES)).filter((entry) => entry.rename?.lock === move.lock).sort(byIntent);
|
|
2806
|
+
for (const entry of left) await this.finishRename(entry);
|
|
2807
|
+
});
|
|
2808
|
+
this.peerMoves.delete(move.lock);
|
|
2809
|
+
for (const [from, to] of move.trees) {
|
|
2810
|
+
this.forget(from);
|
|
2811
|
+
this.forget(to);
|
|
2812
|
+
this.meta.forgetTrees?.([from, to]);
|
|
2813
|
+
}
|
|
2814
|
+
})().finally(() => this.peerWaits.delete(move.lock));
|
|
2815
|
+
this.peerWaits.set(move.lock, wait2);
|
|
2816
|
+
return wait2;
|
|
2817
|
+
}
|
|
2818
|
+
async peerSettled(at, listing) {
|
|
2819
|
+
await this.lookForRenames();
|
|
2820
|
+
for (let reals; ; ) {
|
|
2821
|
+
const forms = [at, ...reals ?? []];
|
|
2822
|
+
const move = forms.map((form) => this.peerAt(form, listing)).find(Boolean);
|
|
2823
|
+
if (move) {
|
|
2824
|
+
this.peerWaited++;
|
|
2825
|
+
await this.peerMoved(move);
|
|
2826
|
+
continue;
|
|
2827
|
+
}
|
|
2828
|
+
if (reals !== void 0 || at === "/" || this.peerMoves.size === 0) return forms;
|
|
2829
|
+
reals = await this.resolvedForms(at);
|
|
2830
|
+
if (reals.length === 0) return forms;
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
aloneCalls = 0;
|
|
2834
|
+
aloneDrain;
|
|
2835
|
+
async alonePlain(inner, args) {
|
|
2836
|
+
this.aloneCalls++;
|
|
2837
|
+
try {
|
|
2838
|
+
return await inner.apply(this, args);
|
|
2839
|
+
} finally {
|
|
2840
|
+
this.aloneCalls--;
|
|
2841
|
+
if (this.aloneCalls === 0 && this.aloneDrain) {
|
|
2842
|
+
this.aloneDrain.resolve();
|
|
2843
|
+
this.aloneDrain = void 0;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
async resolvedForms(at) {
|
|
2848
|
+
if (at === "/") return [];
|
|
2849
|
+
const parent = await PLAIN.realpath.call(this, parentOf3(at), true).catch(() => parentOf3(at));
|
|
2850
|
+
const named = resolvePath(parent, baseOf(at));
|
|
2851
|
+
const target = await PLAIN.realpath.call(this, at, true).catch(() => named);
|
|
2852
|
+
return [.../* @__PURE__ */ new Set([named, target])].filter((form) => form !== at);
|
|
2853
|
+
}
|
|
2854
|
+
amongPeers() {
|
|
2855
|
+
return this.remote !== void 0 && this.locks !== void 0 && this.shared();
|
|
2856
|
+
}
|
|
2857
|
+
async peerOp(name2, args, inner) {
|
|
2858
|
+
const paths = (name2 === "symlink" ? args.slice(1, 2) : PAIRED.has(name2) ? args.slice(0, 2) : args.slice(0, 1)).filter((path) => typeof path === "string").map(normalizePath);
|
|
2859
|
+
const listing = LISTINGS.has(name2);
|
|
2860
|
+
const checked = [...paths];
|
|
2861
|
+
while (this.amongPeers()) {
|
|
2862
|
+
checked.length = 0;
|
|
2863
|
+
for (const at of paths) checked.push(...await this.peerSettled(at, listing));
|
|
2864
|
+
if (!checked.some((at) => this.peerAt(at, listing))) break;
|
|
2865
|
+
}
|
|
2866
|
+
const busy = { paths: checked, release: () => void 0 };
|
|
2867
|
+
const done5 = () => {
|
|
2868
|
+
this.inflight.delete(busy);
|
|
2869
|
+
busy.waiting?.resolve();
|
|
2870
|
+
};
|
|
2871
|
+
busy.release = done5;
|
|
2872
|
+
this.inflight.add(busy);
|
|
2873
|
+
if (name2 === "rename") this.renameCall = busy;
|
|
2874
|
+
if (name2 !== "writeSession") return await inner.apply(this, args).finally(done5);
|
|
2875
|
+
const session = await inner.apply(this, args).catch((err) => {
|
|
2876
|
+
done5();
|
|
2877
|
+
throw err;
|
|
2878
|
+
});
|
|
2879
|
+
return { ...session, close: () => session.close().finally(done5) };
|
|
2880
|
+
}
|
|
2440
2881
|
renamingDirs = /* @__PURE__ */ new Set();
|
|
2441
2882
|
intents = 0;
|
|
2442
2883
|
async intend(rename, at = `${RENAMES}/${crypto.randomUUID()}`) {
|
|
@@ -2482,7 +2923,7 @@ var OpfsFs = class {
|
|
|
2482
2923
|
);
|
|
2483
2924
|
for (const entry of intents) {
|
|
2484
2925
|
const lock = entry.rename.lock;
|
|
2485
|
-
if (!
|
|
2926
|
+
if (!locks || !lock) await this.finishRename(entry);
|
|
2486
2927
|
else await locks.request(lock, () => this.finishRename(entry));
|
|
2487
2928
|
}
|
|
2488
2929
|
return intents.length;
|
|
@@ -2498,7 +2939,8 @@ var OpfsFs = class {
|
|
|
2498
2939
|
this.forget(to);
|
|
2499
2940
|
try {
|
|
2500
2941
|
const left = await this.real(from);
|
|
2501
|
-
if (left && replace && await this.real(to))
|
|
2942
|
+
if (left && replace && await this.real(to))
|
|
2943
|
+
await PLAIN.rm.call(this, to, { recursive: true });
|
|
2502
2944
|
if (left) {
|
|
2503
2945
|
const source = await this.locate(from, false);
|
|
2504
2946
|
const target = await this.locate(parentOf3(to), true);
|
|
@@ -2512,7 +2954,7 @@ var OpfsFs = class {
|
|
|
2512
2954
|
this.forget(from);
|
|
2513
2955
|
this.forget(to);
|
|
2514
2956
|
}
|
|
2515
|
-
if ((await this.meta.under(from)).
|
|
2957
|
+
if ((await this.meta.under(from)).some((entry2) => !entry2.vacated)) {
|
|
2516
2958
|
await this.meta.move(
|
|
2517
2959
|
from,
|
|
2518
2960
|
to,
|
|
@@ -2843,6 +3285,21 @@ var OpfsFs = class {
|
|
|
2843
3285
|
return removed;
|
|
2844
3286
|
}
|
|
2845
3287
|
};
|
|
3288
|
+
function nothing() {
|
|
3289
|
+
return void 0;
|
|
3290
|
+
}
|
|
3291
|
+
function touches(at, trees, listing = true) {
|
|
3292
|
+
return trees.some(
|
|
3293
|
+
([from, to]) => within2(at, from) || within2(at, to) || listing && (at === parentOf3(from) || at === parentOf3(to))
|
|
3294
|
+
);
|
|
3295
|
+
}
|
|
3296
|
+
function byIntent(a, b) {
|
|
3297
|
+
return a.rename.at - b.rename.at;
|
|
3298
|
+
}
|
|
3299
|
+
var PLAIN = {
|
|
3300
|
+
rm: OpfsFs.prototype.rm,
|
|
3301
|
+
realpath: OpfsFs.prototype.realpath
|
|
3302
|
+
};
|
|
2846
3303
|
var READS = [
|
|
2847
3304
|
"stat",
|
|
2848
3305
|
"lstat",
|
|
@@ -2873,6 +3330,14 @@ var WRITES = [
|
|
|
2873
3330
|
"lutimes",
|
|
2874
3331
|
"chown"
|
|
2875
3332
|
];
|
|
3333
|
+
{
|
|
3334
|
+
const proto = OpfsFs.prototype;
|
|
3335
|
+
const inner = proto.createExclusive;
|
|
3336
|
+
proto.createExclusive = function(...args) {
|
|
3337
|
+
if (this.amongPeers()) return this.peerOp("createExclusive", args, inner);
|
|
3338
|
+
return this.alonePlain(inner, args);
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
2876
3341
|
for (const [names2, op] of [
|
|
2877
3342
|
[READS, "read"],
|
|
2878
3343
|
[WRITES, "write"]
|
|
@@ -2883,7 +3348,9 @@ for (const [names2, op] of [
|
|
|
2883
3348
|
proto[name2] = async function(...args) {
|
|
2884
3349
|
try {
|
|
2885
3350
|
if (op === "read") await this.settledRename(args[0]);
|
|
2886
|
-
|
|
3351
|
+
if (this.amongPeers() || name2 === "writeSession")
|
|
3352
|
+
return await this.peerOp(name2, args, inner);
|
|
3353
|
+
return await this.alonePlain(inner, args);
|
|
2887
3354
|
} catch (err) {
|
|
2888
3355
|
throw translate(err, String(args[0]), op, false);
|
|
2889
3356
|
}
|
|
@@ -7128,7 +7595,7 @@ function satisfies(version, range2) {
|
|
|
7128
7595
|
}
|
|
7129
7596
|
|
|
7130
7597
|
// src/version.ts
|
|
7131
|
-
var KERNEL_VERSION = true ? "1.142.
|
|
7598
|
+
var KERNEL_VERSION = true ? "1.142.2" : "0.0.0-dev";
|
|
7132
7599
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7133
7600
|
function procVersion() {
|
|
7134
7601
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9505,89 +9972,6 @@ var FileWatches = class {
|
|
|
9505
9972
|
}
|
|
9506
9973
|
};
|
|
9507
9974
|
|
|
9508
|
-
// src/fs/changes.ts
|
|
9509
|
-
var GEN = 0;
|
|
9510
|
-
var RING = 1;
|
|
9511
|
-
var RING_SIZE = 4096;
|
|
9512
|
-
var SLOT = 2;
|
|
9513
|
-
var DIRTY = RING + RING_SIZE * SLOT;
|
|
9514
|
-
var FOREIGN = DIRTY + 1;
|
|
9515
|
-
var CHANGES_BYTES = (FOREIGN + 1) * 4;
|
|
9516
|
-
function changeHash(path) {
|
|
9517
|
-
let h = 2166136261;
|
|
9518
|
-
for (let i = 0; i < path.length; i++) {
|
|
9519
|
-
h ^= path.charCodeAt(i);
|
|
9520
|
-
h = Math.imul(h, 16777619);
|
|
9521
|
-
}
|
|
9522
|
-
return h === 0 ? 1 : h;
|
|
9523
|
-
}
|
|
9524
|
-
function normal(path) {
|
|
9525
|
-
const parts2 = [];
|
|
9526
|
-
for (const part of path.split("/")) {
|
|
9527
|
-
if (part === "" || part === ".") continue;
|
|
9528
|
-
if (part === "..") parts2.pop();
|
|
9529
|
-
else parts2.push(part);
|
|
9530
|
-
}
|
|
9531
|
-
return `/${parts2.join("/")}`;
|
|
9532
|
-
}
|
|
9533
|
-
var FileChanges = class {
|
|
9534
|
-
sab;
|
|
9535
|
-
view;
|
|
9536
|
-
constructor(sab = new SharedArrayBuffer(CHANGES_BYTES)) {
|
|
9537
|
-
this.sab = sab;
|
|
9538
|
-
this.view = new Int32Array(sab);
|
|
9539
|
-
}
|
|
9540
|
-
dirtied(delta) {
|
|
9541
|
-
Atomics.add(this.view, DIRTY, delta);
|
|
9542
|
-
}
|
|
9543
|
-
foreign(on) {
|
|
9544
|
-
Atomics.store(this.view, FOREIGN, on ? 1 : 0);
|
|
9545
|
-
}
|
|
9546
|
-
flush() {
|
|
9547
|
-
Atomics.add(this.view, GEN, RING_SIZE + 1);
|
|
9548
|
-
}
|
|
9549
|
-
publish(...paths) {
|
|
9550
|
-
for (const path of paths) {
|
|
9551
|
-
const g = Atomics.add(this.view, GEN, 1) + 1 | 0;
|
|
9552
|
-
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
9553
|
-
Atomics.store(this.view, at, 0);
|
|
9554
|
-
Atomics.store(this.view, at + 1, changeHash(normal(path)));
|
|
9555
|
-
Atomics.store(this.view, at, g);
|
|
9556
|
-
}
|
|
9557
|
-
}
|
|
9558
|
-
};
|
|
9559
|
-
var ChangeView = class {
|
|
9560
|
-
view;
|
|
9561
|
-
constructor(sab) {
|
|
9562
|
-
this.view = new Int32Array(sab);
|
|
9563
|
-
}
|
|
9564
|
-
now() {
|
|
9565
|
-
return Atomics.load(this.view, GEN);
|
|
9566
|
-
}
|
|
9567
|
-
clean() {
|
|
9568
|
-
return this.view.length > DIRTY && Atomics.load(this.view, DIRTY) === 0;
|
|
9569
|
-
}
|
|
9570
|
-
foreign() {
|
|
9571
|
-
return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
|
|
9572
|
-
}
|
|
9573
|
-
changedSince(seen, path) {
|
|
9574
|
-
const now = Atomics.load(this.view, GEN);
|
|
9575
|
-
const distance = now - seen >>> 0;
|
|
9576
|
-
if (distance === 0) return { now, changed: false };
|
|
9577
|
-
if (distance > RING_SIZE) return { now, changed: true };
|
|
9578
|
-
const hash = changeHash(normal(path));
|
|
9579
|
-
for (let i = 1; i <= distance; i++) {
|
|
9580
|
-
const g = seen + i | 0;
|
|
9581
|
-
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
9582
|
-
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
9583
|
-
const hit = Atomics.load(this.view, at + 1) === hash;
|
|
9584
|
-
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
9585
|
-
if (hit) return { now, changed: true };
|
|
9586
|
-
}
|
|
9587
|
-
return { now, changed: false };
|
|
9588
|
-
}
|
|
9589
|
-
};
|
|
9590
|
-
|
|
9591
9975
|
// src/fs/commands.ts
|
|
9592
9976
|
var S_IFDIR2 = 16384;
|
|
9593
9977
|
var S_IFREG2 = 32768;
|
|
@@ -10016,10 +10400,10 @@ var FreshModules = class {
|
|
|
10016
10400
|
const ranged2 = rangedOps(fs);
|
|
10017
10401
|
if (ranged2) {
|
|
10018
10402
|
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
10019
|
-
const
|
|
10403
|
+
const touches3 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
10020
10404
|
const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
|
|
10021
10405
|
await ranged2.pwrite(path, at, bytes, transfer);
|
|
10022
|
-
if (
|
|
10406
|
+
if (touches3) await decide(path, first);
|
|
10023
10407
|
};
|
|
10024
10408
|
overrides.truncate = async (path, size) => {
|
|
10025
10409
|
await ranged2.truncate(path, size);
|
|
@@ -10096,7 +10480,7 @@ var baseOf3 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
|
10096
10480
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
10097
10481
|
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
10098
10482
|
var parentOf7 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
10099
|
-
function
|
|
10483
|
+
function touches2(watcher, changed) {
|
|
10100
10484
|
return watcher.paths.some(
|
|
10101
10485
|
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) : parentOf7(changed) === watched)
|
|
10102
10486
|
);
|
|
@@ -10224,7 +10608,7 @@ var FsWatchers = class {
|
|
|
10224
10608
|
for (const watcher of this.watchers) {
|
|
10225
10609
|
for (const path of paths) {
|
|
10226
10610
|
const changed = normalizePath(path);
|
|
10227
|
-
if (
|
|
10611
|
+
if (touches2(watcher, changed)) watcher.pending.add(changed);
|
|
10228
10612
|
}
|
|
10229
10613
|
if (watcher.pending.size === 0 || watcher.scheduled) continue;
|
|
10230
10614
|
watcher.scheduled = true;
|
|
@@ -13889,7 +14273,18 @@ var SYS_TREE = {
|
|
|
13889
14273
|
slicc_opfs_ops: (listing) => `${listing.opfsOps ?? 0}
|
|
13890
14274
|
`,
|
|
13891
14275
|
slicc_cwd_checks: (listing) => `${listing.cwdChecks ?? 0}
|
|
13892
|
-
|
|
14276
|
+
`,
|
|
14277
|
+
slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
|
|
14278
|
+
`,
|
|
14279
|
+
slicc_rename_acks: (listing) => {
|
|
14280
|
+
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
14281
|
+
const median = samples[Math.floor(samples.length / 2)] ?? 0;
|
|
14282
|
+
const most = samples.at(-1) ?? 0;
|
|
14283
|
+
const waits = listing.renameAcks?.waits ?? 0;
|
|
14284
|
+
const queries = listing.renameAcks?.queries ?? 0;
|
|
14285
|
+
return `${listing.renameAcks?.acks ?? 0} ${median.toFixed(1)} ${most.toFixed(1)} ${waits} ${queries}
|
|
14286
|
+
`;
|
|
14287
|
+
}
|
|
13893
14288
|
}
|
|
13894
14289
|
};
|
|
13895
14290
|
function isSysFile(at) {
|
|
@@ -19721,7 +20116,7 @@ function sniffPg(start2) {
|
|
|
19721
20116
|
const length2 = int32(bytes, 0);
|
|
19722
20117
|
return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
|
|
19723
20118
|
}
|
|
19724
|
-
var
|
|
20119
|
+
var PLAIN2 = "SCRAM-SHA-256";
|
|
19725
20120
|
var PLUS = "SCRAM-SHA-256-PLUS";
|
|
19726
20121
|
var END_POINT = "p=tls-server-end-point,,";
|
|
19727
20122
|
var SASL = 10;
|
|
@@ -19843,7 +20238,7 @@ function pgLength(bytes, started) {
|
|
|
19843
20238
|
const length2 = int32(bytes, started ? 1 : 0);
|
|
19844
20239
|
return started ? 1 + length2 : length2;
|
|
19845
20240
|
}
|
|
19846
|
-
var MECHANISMS = /* @__PURE__ */ new Set([
|
|
20241
|
+
var MECHANISMS = /* @__PURE__ */ new Set([PLAIN2, PLUS]);
|
|
19847
20242
|
async function cleartext(message3, asks) {
|
|
19848
20243
|
const body = latin2(message3.subarray(5));
|
|
19849
20244
|
if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
|
|
@@ -19876,7 +20271,7 @@ function serverHeader(header4, server) {
|
|
|
19876
20271
|
function rewritten(first, header4) {
|
|
19877
20272
|
const parsed2 = clientFirstOf(first.data);
|
|
19878
20273
|
if (!parsed2 || parsed2.header === header4) return first;
|
|
19879
|
-
return { mechanism: header4 === END_POINT ? PLUS :
|
|
20274
|
+
return { mechanism: header4 === END_POINT ? PLUS : PLAIN2, data: `${header4}${parsed2.bare}` };
|
|
19880
20275
|
}
|
|
19881
20276
|
var PgClient = class {
|
|
19882
20277
|
clientFirst;
|
|
@@ -27494,7 +27889,7 @@ var RULE = new RegExp(
|
|
|
27494
27889
|
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
27495
27890
|
);
|
|
27496
27891
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
27497
|
-
var
|
|
27892
|
+
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
27498
27893
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
27499
27894
|
function failed2(errno3, error) {
|
|
27500
27895
|
return { error, errno: errno3 };
|
|
@@ -27521,7 +27916,7 @@ function splitWords(text) {
|
|
|
27521
27916
|
return words2;
|
|
27522
27917
|
}
|
|
27523
27918
|
function quoteWord(word) {
|
|
27524
|
-
return
|
|
27919
|
+
return PLAIN3.test(word) ? word : `'${word.replaceAll("'", `'\\''`)}'`;
|
|
27525
27920
|
}
|
|
27526
27921
|
function validWho(who) {
|
|
27527
27922
|
if (who === "ALL") return true;
|
|
@@ -29334,7 +29729,8 @@ var Launcher = class {
|
|
|
29334
29729
|
fsCalls: servedFsCalls(),
|
|
29335
29730
|
opfsCalls: this.rootFs.opfsCalls?.() ?? 0,
|
|
29336
29731
|
opfsOps: this.rootFs.opfsOps?.() ?? 0,
|
|
29337
|
-
cwdChecks: this.cwds.checks
|
|
29732
|
+
cwdChecks: this.cwds.checks,
|
|
29733
|
+
renameAcks: this.rootFs.renameWaits?.()
|
|
29338
29734
|
}),
|
|
29339
29735
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
29340
29736
|
crontab: (call) => this.crontab(pid, call),
|