@ai-ecoverse/slicc-kernel 1.141.3 → 1.142.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 +17 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +492 -107
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +3 -0
- package/dist/meta.js.map +2 -2
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +113 -85
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +505 -110
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +14 -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 +30 -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/dist/types/node.d.ts +1 -0
- package/package.json +2 -2
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,12 @@ 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 PAIRED = /* @__PURE__ */ new Set(["rename", "link", "copyFile"]);
|
|
1279
|
+
var LISTINGS = /* @__PURE__ */ new Set(["readdir", "readdirStat"]);
|
|
1280
|
+
var RETRY = /* @__PURE__ */ Symbol("retry");
|
|
1281
|
+
var ACK_SAMPLES = 4096;
|
|
1282
|
+
var INTENT_POLL_MS = 5;
|
|
1132
1283
|
function movable(handle) {
|
|
1133
1284
|
return typeof handle.move === "function";
|
|
1134
1285
|
}
|
|
@@ -1173,6 +1324,7 @@ function sidecar(meta) {
|
|
|
1173
1324
|
for (const { path, change } of changes) await ops.update(path, change);
|
|
1174
1325
|
};
|
|
1175
1326
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
1327
|
+
if (meta.forgetTrees) ops.forgetTrees = meta.forgetTrees.bind(meta);
|
|
1176
1328
|
const { removeFile } = meta;
|
|
1177
1329
|
if (removeFile)
|
|
1178
1330
|
ops.removeFile = (path) => removeFile.call(meta, path).catch((err) => {
|
|
@@ -1298,7 +1450,17 @@ var OpfsFs = class {
|
|
|
1298
1450
|
this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`, { locks: this.locks ?? null });
|
|
1299
1451
|
if (this.remote) {
|
|
1300
1452
|
this.remote.quiet = () => this.quiet().then(() => this.settle?.());
|
|
1301
|
-
this.remote.gone = () =>
|
|
1453
|
+
this.remote.gone = () => {
|
|
1454
|
+
void this.orphans();
|
|
1455
|
+
for (const move of [...this.peerMoves.values()]) void this.peerMoved(move);
|
|
1456
|
+
};
|
|
1457
|
+
this.remote.renaming = (rename) => this.heardRename(rename);
|
|
1458
|
+
this.remote.renamed = (lock) => {
|
|
1459
|
+
const move = this.peerMoves.get(lock);
|
|
1460
|
+
if (!move) return;
|
|
1461
|
+
move.done = true;
|
|
1462
|
+
void this.peerMoved(move);
|
|
1463
|
+
};
|
|
1302
1464
|
}
|
|
1303
1465
|
if (this.channel) {
|
|
1304
1466
|
const remote = this.remote;
|
|
@@ -2342,16 +2504,27 @@ var OpfsFs = class {
|
|
|
2342
2504
|
throw fsError("EPERM", `${from}: this file system has no hard links`);
|
|
2343
2505
|
}
|
|
2344
2506
|
async rename(from, to) {
|
|
2507
|
+
const call = this.renameCall;
|
|
2508
|
+
this.renameCall = void 0;
|
|
2345
2509
|
if (from === to) return;
|
|
2510
|
+
for (; ; ) {
|
|
2511
|
+
try {
|
|
2512
|
+
return await this.renameOnce(from, to, call);
|
|
2513
|
+
} catch (err) {
|
|
2514
|
+
if (err !== RETRY) throw err;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
async renameOnce(from, to, call) {
|
|
2346
2519
|
const source = await this.locate(from, false);
|
|
2347
2520
|
this.refuse(source.path, true);
|
|
2348
2521
|
this.forget(source.path);
|
|
2349
2522
|
const parent = await this.locate(parentOf3(to), true);
|
|
2350
2523
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
2351
2524
|
this.refuse(destination, true);
|
|
2352
|
-
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
2525
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to, call));
|
|
2353
2526
|
}
|
|
2354
|
-
async moveTo(source, parent, destination, to) {
|
|
2527
|
+
async moveTo(source, parent, destination, to, call) {
|
|
2355
2528
|
const sourceStat = await this.describe(source);
|
|
2356
2529
|
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
2357
2530
|
const target = await this.exactly(() => this.locate(destination, false)).catch((err) => {
|
|
@@ -2386,6 +2559,7 @@ var OpfsFs = class {
|
|
|
2386
2559
|
const name2 = baseOf(destination);
|
|
2387
2560
|
const swap = targetStat?.isDirectory === true;
|
|
2388
2561
|
let lock;
|
|
2562
|
+
const hooks = {};
|
|
2389
2563
|
const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
|
|
2390
2564
|
const copying = sourceStat.isDirectory && !movable(source.handle);
|
|
2391
2565
|
const staged = resolvePath(parent.path, staging);
|
|
@@ -2394,8 +2568,15 @@ var OpfsFs = class {
|
|
|
2394
2568
|
const copies = /* @__PURE__ */ new Map();
|
|
2395
2569
|
const root = { ino: inodeOf(source.path), ...moving };
|
|
2396
2570
|
const owned4 = lock ? { lock } : {};
|
|
2571
|
+
hooks.notify?.();
|
|
2397
2572
|
const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
|
|
2398
2573
|
const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
|
|
2574
|
+
await hooks.started?.().catch(async (err) => {
|
|
2575
|
+
for (const intent of [first, second]) {
|
|
2576
|
+
if (intent) await this.meta.update(intent, () => void 0);
|
|
2577
|
+
}
|
|
2578
|
+
throw err;
|
|
2579
|
+
});
|
|
2399
2580
|
const moved2 = await this.replacingTarget(
|
|
2400
2581
|
targetStat !== null,
|
|
2401
2582
|
() => this.place(source.handle, dir, staging, copies)
|
|
@@ -2430,13 +2611,262 @@ var OpfsFs = class {
|
|
|
2430
2611
|
const locks = this.locks;
|
|
2431
2612
|
if (locks) {
|
|
2432
2613
|
lock = `${RENAME_LOCK}${crypto.randomUUID()}`;
|
|
2433
|
-
|
|
2614
|
+
this.ownLocks.add(lock);
|
|
2615
|
+
call?.release();
|
|
2616
|
+
await this.admitted(locks, lock, source.path, destination, place, hooks);
|
|
2434
2617
|
} else await place();
|
|
2435
2618
|
} finally {
|
|
2619
|
+
if (lock) this.ownLocks.delete(lock);
|
|
2436
2620
|
this.renamingDirs.delete(entry);
|
|
2437
2621
|
resolve2();
|
|
2438
2622
|
}
|
|
2439
2623
|
}
|
|
2624
|
+
async admitted(locks, lock, from, to, place, hooks) {
|
|
2625
|
+
const remote = this.remote;
|
|
2626
|
+
if (remote && !this.shared() && !await remote.joinedAll(RENAME_ACK_MAX_MS)) {
|
|
2627
|
+
this.ackBusy++;
|
|
2628
|
+
console.warn(
|
|
2629
|
+
`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)`
|
|
2630
|
+
);
|
|
2631
|
+
throw fsError("EBUSY", from);
|
|
2632
|
+
}
|
|
2633
|
+
if (!remote || !this.shared()) {
|
|
2634
|
+
await locks.request(lock, place);
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
let clash;
|
|
2638
|
+
let run2;
|
|
2639
|
+
await locks.request(`${RENAME_ADMIT}${this.rootName ?? ""}`, async () => {
|
|
2640
|
+
if (await this.renamingElsewhere()) await this.learnRenames();
|
|
2641
|
+
clash = this.clashing(from, to);
|
|
2642
|
+
if (clash) return;
|
|
2643
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
2644
|
+
let told;
|
|
2645
|
+
hooks.notify = () => {
|
|
2646
|
+
told = remote.renamingTree({ from, to, lock });
|
|
2647
|
+
};
|
|
2648
|
+
hooks.started = async () => {
|
|
2649
|
+
resolve2();
|
|
2650
|
+
this.renameAcks++;
|
|
2651
|
+
const at = performance.now();
|
|
2652
|
+
const stuck = await told;
|
|
2653
|
+
this.ackMs.push(performance.now() - at);
|
|
2654
|
+
if (this.ackMs.length > ACK_SAMPLES) this.ackMs.shift();
|
|
2655
|
+
if (stuck.length === 0) return;
|
|
2656
|
+
this.ackBusy++;
|
|
2657
|
+
console.warn(
|
|
2658
|
+
`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)`
|
|
2659
|
+
);
|
|
2660
|
+
throw fsError("EBUSY", from);
|
|
2661
|
+
};
|
|
2662
|
+
run2 = locks.request(lock, async () => {
|
|
2663
|
+
await place();
|
|
2664
|
+
remote.renamedTree(lock);
|
|
2665
|
+
});
|
|
2666
|
+
await Promise.race([promise, run2.then(nothing, nothing)]);
|
|
2667
|
+
});
|
|
2668
|
+
if (clash) {
|
|
2669
|
+
this.peerWaited++;
|
|
2670
|
+
await this.peerMoved(clash);
|
|
2671
|
+
throw RETRY;
|
|
2672
|
+
}
|
|
2673
|
+
await run2;
|
|
2674
|
+
}
|
|
2675
|
+
renameAcks = 0;
|
|
2676
|
+
ackBusy = 0;
|
|
2677
|
+
ackMs = [];
|
|
2678
|
+
ownLocks = /* @__PURE__ */ new Set();
|
|
2679
|
+
peerMoves = /* @__PURE__ */ new Map();
|
|
2680
|
+
peerWaits = /* @__PURE__ */ new Map();
|
|
2681
|
+
inflight = /* @__PURE__ */ new Set();
|
|
2682
|
+
renameCall;
|
|
2683
|
+
looking;
|
|
2684
|
+
lookedAt = Number.NEGATIVE_INFINITY;
|
|
2685
|
+
peerWaited = 0;
|
|
2686
|
+
queries = 0;
|
|
2687
|
+
renameWaits() {
|
|
2688
|
+
return {
|
|
2689
|
+
acks: this.renameAcks,
|
|
2690
|
+
busy: this.ackBusy,
|
|
2691
|
+
waits: this.peerWaited,
|
|
2692
|
+
queries: this.queries,
|
|
2693
|
+
ackMs: this.ackMs
|
|
2694
|
+
};
|
|
2695
|
+
}
|
|
2696
|
+
notePeer(lock, tree2) {
|
|
2697
|
+
let known = this.peerMoves.get(lock);
|
|
2698
|
+
if (!known) {
|
|
2699
|
+
known = { lock, trees: [] };
|
|
2700
|
+
this.peerMoves.set(lock, known);
|
|
2701
|
+
}
|
|
2702
|
+
if (!known.trees.some(([a, b]) => a === tree2[0] && b === tree2[1])) known.trees.push(tree2);
|
|
2703
|
+
return known;
|
|
2704
|
+
}
|
|
2705
|
+
async learnRenames() {
|
|
2706
|
+
for (const { rename } of await this.meta.under(RENAMES)) {
|
|
2707
|
+
if (rename?.lock === void 0 || this.ownLocks.has(rename.lock)) continue;
|
|
2708
|
+
this.notePeer(rename.lock, [rename.from, rename.to]);
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
async renamingElsewhere() {
|
|
2712
|
+
const { held = [] } = await this.locks.query();
|
|
2713
|
+
return held.some(({ name: name2 }) => name2?.startsWith(RENAME_LOCK) && !this.ownLocks.has(name2));
|
|
2714
|
+
}
|
|
2715
|
+
lookForRenames() {
|
|
2716
|
+
const locks = this.locks;
|
|
2717
|
+
const age = performance.now() - this.lookedAt;
|
|
2718
|
+
if (!locks || age < SHARED_TTL_MS / 2) return Promise.resolve();
|
|
2719
|
+
this.looking ??= (async () => {
|
|
2720
|
+
for (; ; ) {
|
|
2721
|
+
const asked = performance.now();
|
|
2722
|
+
this.queries++;
|
|
2723
|
+
const { held = [] } = await locks.query();
|
|
2724
|
+
const unknown = () => held.some(
|
|
2725
|
+
({ name: name2 }) => name2?.startsWith(RENAME_LOCK) && !this.ownLocks.has(name2) && !this.peerMoves.has(name2)
|
|
2726
|
+
);
|
|
2727
|
+
if (unknown()) await this.learnRenames();
|
|
2728
|
+
if (!unknown()) {
|
|
2729
|
+
this.lookedAt = asked;
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
await new Promise((resolve2) => setTimeout(resolve2, INTENT_POLL_MS));
|
|
2733
|
+
}
|
|
2734
|
+
})().finally(() => {
|
|
2735
|
+
this.looking = void 0;
|
|
2736
|
+
});
|
|
2737
|
+
if (age >= SHARED_TTL_MS) return this.looking;
|
|
2738
|
+
this.looking.catch(nothing);
|
|
2739
|
+
return Promise.resolve();
|
|
2740
|
+
}
|
|
2741
|
+
async heardRename({ from, to, lock }) {
|
|
2742
|
+
if (this.ownLocks.has(lock)) return;
|
|
2743
|
+
this.notePeer(lock, [from, to]);
|
|
2744
|
+
this.lookedAt = performance.now();
|
|
2745
|
+
const trees = [[from, to]];
|
|
2746
|
+
const running = [...this.inflight];
|
|
2747
|
+
const reached = await Promise.all(
|
|
2748
|
+
running.map(async (op) => {
|
|
2749
|
+
if (op.paths.some((at) => touches(at, trees))) return true;
|
|
2750
|
+
for (const at of op.paths) {
|
|
2751
|
+
const forms = await this.resolvedForms(at);
|
|
2752
|
+
if (forms.some((form) => touches(form, trees))) return true;
|
|
2753
|
+
}
|
|
2754
|
+
return false;
|
|
2755
|
+
})
|
|
2756
|
+
);
|
|
2757
|
+
const busy = running.filter((op, i) => reached[i] && this.inflight.has(op));
|
|
2758
|
+
if (this.aloneCalls > 0) {
|
|
2759
|
+
this.aloneDrain ??= Promise.withResolvers();
|
|
2760
|
+
busy.push({ paths: [], waiting: this.aloneDrain, release: nothing });
|
|
2761
|
+
}
|
|
2762
|
+
await Promise.all(
|
|
2763
|
+
busy.map((op) => {
|
|
2764
|
+
op.waiting ??= Promise.withResolvers();
|
|
2765
|
+
return op.waiting.promise;
|
|
2766
|
+
})
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2769
|
+
peerAt(at, listing) {
|
|
2770
|
+
for (const move of this.peerMoves.values()) {
|
|
2771
|
+
if (this.ownLocks.has(move.lock)) continue;
|
|
2772
|
+
if (touches(at, move.trees, listing)) return move;
|
|
2773
|
+
}
|
|
2774
|
+
return void 0;
|
|
2775
|
+
}
|
|
2776
|
+
clashing(from, to) {
|
|
2777
|
+
for (const move of this.peerMoves.values()) {
|
|
2778
|
+
for (const tree2 of move.trees) {
|
|
2779
|
+
for (const mine of [from, to]) {
|
|
2780
|
+
if (tree2.some((theirs) => within2(mine, theirs) || within2(theirs, mine))) return move;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
return void 0;
|
|
2785
|
+
}
|
|
2786
|
+
peerMoved(move) {
|
|
2787
|
+
const locks = this.locks;
|
|
2788
|
+
let wait2 = this.peerWaits.get(move.lock);
|
|
2789
|
+
if (wait2 !== void 0) return wait2;
|
|
2790
|
+
wait2 = (async () => {
|
|
2791
|
+
if (!move.done)
|
|
2792
|
+
await locks.request(move.lock, async () => {
|
|
2793
|
+
if (move.done) return;
|
|
2794
|
+
const left = (await this.meta.under(RENAMES)).filter((entry) => entry.rename?.lock === move.lock).sort(byIntent);
|
|
2795
|
+
for (const entry of left) await this.finishRename(entry);
|
|
2796
|
+
});
|
|
2797
|
+
this.peerMoves.delete(move.lock);
|
|
2798
|
+
for (const [from, to] of move.trees) {
|
|
2799
|
+
this.forget(from);
|
|
2800
|
+
this.forget(to);
|
|
2801
|
+
this.meta.forgetTrees?.([from, to]);
|
|
2802
|
+
}
|
|
2803
|
+
})().finally(() => this.peerWaits.delete(move.lock));
|
|
2804
|
+
this.peerWaits.set(move.lock, wait2);
|
|
2805
|
+
return wait2;
|
|
2806
|
+
}
|
|
2807
|
+
async peerSettled(at, listing) {
|
|
2808
|
+
await this.lookForRenames();
|
|
2809
|
+
for (let reals; ; ) {
|
|
2810
|
+
const forms = [at, ...reals ?? []];
|
|
2811
|
+
const move = forms.map((form) => this.peerAt(form, listing)).find(Boolean);
|
|
2812
|
+
if (move) {
|
|
2813
|
+
this.peerWaited++;
|
|
2814
|
+
await this.peerMoved(move);
|
|
2815
|
+
continue;
|
|
2816
|
+
}
|
|
2817
|
+
if (reals !== void 0 || at === "/" || this.peerMoves.size === 0) return forms;
|
|
2818
|
+
reals = await this.resolvedForms(at);
|
|
2819
|
+
if (reals.length === 0) return forms;
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
aloneCalls = 0;
|
|
2823
|
+
aloneDrain;
|
|
2824
|
+
async alonePlain(inner, args) {
|
|
2825
|
+
this.aloneCalls++;
|
|
2826
|
+
try {
|
|
2827
|
+
return await inner.apply(this, args);
|
|
2828
|
+
} finally {
|
|
2829
|
+
this.aloneCalls--;
|
|
2830
|
+
if (this.aloneCalls === 0 && this.aloneDrain) {
|
|
2831
|
+
this.aloneDrain.resolve();
|
|
2832
|
+
this.aloneDrain = void 0;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
async resolvedForms(at) {
|
|
2837
|
+
if (at === "/") return [];
|
|
2838
|
+
const parent = await PLAIN.realpath.call(this, parentOf3(at), true).catch(() => parentOf3(at));
|
|
2839
|
+
const named = resolvePath(parent, baseOf(at));
|
|
2840
|
+
const target = await PLAIN.realpath.call(this, at, true).catch(() => named);
|
|
2841
|
+
return [.../* @__PURE__ */ new Set([named, target])].filter((form) => form !== at);
|
|
2842
|
+
}
|
|
2843
|
+
amongPeers() {
|
|
2844
|
+
return this.remote !== void 0 && this.locks !== void 0 && this.shared();
|
|
2845
|
+
}
|
|
2846
|
+
async peerOp(name2, args, inner) {
|
|
2847
|
+
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);
|
|
2848
|
+
const listing = LISTINGS.has(name2);
|
|
2849
|
+
const checked = [...paths];
|
|
2850
|
+
while (this.amongPeers()) {
|
|
2851
|
+
checked.length = 0;
|
|
2852
|
+
for (const at of paths) checked.push(...await this.peerSettled(at, listing));
|
|
2853
|
+
if (!checked.some((at) => this.peerAt(at, listing))) break;
|
|
2854
|
+
}
|
|
2855
|
+
const busy = { paths: checked, release: () => void 0 };
|
|
2856
|
+
const done5 = () => {
|
|
2857
|
+
this.inflight.delete(busy);
|
|
2858
|
+
busy.waiting?.resolve();
|
|
2859
|
+
};
|
|
2860
|
+
busy.release = done5;
|
|
2861
|
+
this.inflight.add(busy);
|
|
2862
|
+
if (name2 === "rename") this.renameCall = busy;
|
|
2863
|
+
if (name2 !== "writeSession") return await inner.apply(this, args).finally(done5);
|
|
2864
|
+
const session = await inner.apply(this, args).catch((err) => {
|
|
2865
|
+
done5();
|
|
2866
|
+
throw err;
|
|
2867
|
+
});
|
|
2868
|
+
return { ...session, close: () => session.close().finally(done5) };
|
|
2869
|
+
}
|
|
2440
2870
|
renamingDirs = /* @__PURE__ */ new Set();
|
|
2441
2871
|
intents = 0;
|
|
2442
2872
|
async intend(rename, at = `${RENAMES}/${crypto.randomUUID()}`) {
|
|
@@ -2482,7 +2912,7 @@ var OpfsFs = class {
|
|
|
2482
2912
|
);
|
|
2483
2913
|
for (const entry of intents) {
|
|
2484
2914
|
const lock = entry.rename.lock;
|
|
2485
|
-
if (!
|
|
2915
|
+
if (!locks || !lock) await this.finishRename(entry);
|
|
2486
2916
|
else await locks.request(lock, () => this.finishRename(entry));
|
|
2487
2917
|
}
|
|
2488
2918
|
return intents.length;
|
|
@@ -2498,7 +2928,8 @@ var OpfsFs = class {
|
|
|
2498
2928
|
this.forget(to);
|
|
2499
2929
|
try {
|
|
2500
2930
|
const left = await this.real(from);
|
|
2501
|
-
if (left && replace && await this.real(to))
|
|
2931
|
+
if (left && replace && await this.real(to))
|
|
2932
|
+
await PLAIN.rm.call(this, to, { recursive: true });
|
|
2502
2933
|
if (left) {
|
|
2503
2934
|
const source = await this.locate(from, false);
|
|
2504
2935
|
const target = await this.locate(parentOf3(to), true);
|
|
@@ -2512,7 +2943,7 @@ var OpfsFs = class {
|
|
|
2512
2943
|
this.forget(from);
|
|
2513
2944
|
this.forget(to);
|
|
2514
2945
|
}
|
|
2515
|
-
if ((await this.meta.under(from)).
|
|
2946
|
+
if ((await this.meta.under(from)).some((entry2) => !entry2.vacated)) {
|
|
2516
2947
|
await this.meta.move(
|
|
2517
2948
|
from,
|
|
2518
2949
|
to,
|
|
@@ -2843,6 +3274,21 @@ var OpfsFs = class {
|
|
|
2843
3274
|
return removed;
|
|
2844
3275
|
}
|
|
2845
3276
|
};
|
|
3277
|
+
function nothing() {
|
|
3278
|
+
return void 0;
|
|
3279
|
+
}
|
|
3280
|
+
function touches(at, trees, listing = true) {
|
|
3281
|
+
return trees.some(
|
|
3282
|
+
([from, to]) => within2(at, from) || within2(at, to) || listing && (at === parentOf3(from) || at === parentOf3(to))
|
|
3283
|
+
);
|
|
3284
|
+
}
|
|
3285
|
+
function byIntent(a, b) {
|
|
3286
|
+
return a.rename.at - b.rename.at;
|
|
3287
|
+
}
|
|
3288
|
+
var PLAIN = {
|
|
3289
|
+
rm: OpfsFs.prototype.rm,
|
|
3290
|
+
realpath: OpfsFs.prototype.realpath
|
|
3291
|
+
};
|
|
2846
3292
|
var READS = [
|
|
2847
3293
|
"stat",
|
|
2848
3294
|
"lstat",
|
|
@@ -2873,6 +3319,14 @@ var WRITES = [
|
|
|
2873
3319
|
"lutimes",
|
|
2874
3320
|
"chown"
|
|
2875
3321
|
];
|
|
3322
|
+
{
|
|
3323
|
+
const proto = OpfsFs.prototype;
|
|
3324
|
+
const inner = proto.createExclusive;
|
|
3325
|
+
proto.createExclusive = function(...args) {
|
|
3326
|
+
if (this.amongPeers()) return this.peerOp("createExclusive", args, inner);
|
|
3327
|
+
return this.alonePlain(inner, args);
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
2876
3330
|
for (const [names2, op] of [
|
|
2877
3331
|
[READS, "read"],
|
|
2878
3332
|
[WRITES, "write"]
|
|
@@ -2883,7 +3337,9 @@ for (const [names2, op] of [
|
|
|
2883
3337
|
proto[name2] = async function(...args) {
|
|
2884
3338
|
try {
|
|
2885
3339
|
if (op === "read") await this.settledRename(args[0]);
|
|
2886
|
-
|
|
3340
|
+
if (this.amongPeers() || name2 === "writeSession")
|
|
3341
|
+
return await this.peerOp(name2, args, inner);
|
|
3342
|
+
return await this.alonePlain(inner, args);
|
|
2887
3343
|
} catch (err) {
|
|
2888
3344
|
throw translate(err, String(args[0]), op, false);
|
|
2889
3345
|
}
|
|
@@ -7128,7 +7584,7 @@ function satisfies(version, range2) {
|
|
|
7128
7584
|
}
|
|
7129
7585
|
|
|
7130
7586
|
// src/version.ts
|
|
7131
|
-
var KERNEL_VERSION = true ? "1.
|
|
7587
|
+
var KERNEL_VERSION = true ? "1.142.1" : "0.0.0-dev";
|
|
7132
7588
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7133
7589
|
function procVersion() {
|
|
7134
7590
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9505,89 +9961,6 @@ var FileWatches = class {
|
|
|
9505
9961
|
}
|
|
9506
9962
|
};
|
|
9507
9963
|
|
|
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
9964
|
// src/fs/commands.ts
|
|
9592
9965
|
var S_IFDIR2 = 16384;
|
|
9593
9966
|
var S_IFREG2 = 32768;
|
|
@@ -10016,10 +10389,10 @@ var FreshModules = class {
|
|
|
10016
10389
|
const ranged2 = rangedOps(fs);
|
|
10017
10390
|
if (ranged2) {
|
|
10018
10391
|
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
10019
|
-
const
|
|
10392
|
+
const touches3 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
10020
10393
|
const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
|
|
10021
10394
|
await ranged2.pwrite(path, at, bytes, transfer);
|
|
10022
|
-
if (
|
|
10395
|
+
if (touches3) await decide(path, first);
|
|
10023
10396
|
};
|
|
10024
10397
|
overrides.truncate = async (path, size) => {
|
|
10025
10398
|
await ranged2.truncate(path, size);
|
|
@@ -10096,7 +10469,7 @@ var baseOf3 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
|
10096
10469
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
10097
10470
|
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
10098
10471
|
var parentOf7 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
10099
|
-
function
|
|
10472
|
+
function touches2(watcher, changed) {
|
|
10100
10473
|
return watcher.paths.some(
|
|
10101
10474
|
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) : parentOf7(changed) === watched)
|
|
10102
10475
|
);
|
|
@@ -10224,7 +10597,7 @@ var FsWatchers = class {
|
|
|
10224
10597
|
for (const watcher of this.watchers) {
|
|
10225
10598
|
for (const path of paths) {
|
|
10226
10599
|
const changed = normalizePath(path);
|
|
10227
|
-
if (
|
|
10600
|
+
if (touches2(watcher, changed)) watcher.pending.add(changed);
|
|
10228
10601
|
}
|
|
10229
10602
|
if (watcher.pending.size === 0 || watcher.scheduled) continue;
|
|
10230
10603
|
watcher.scheduled = true;
|
|
@@ -13889,7 +14262,18 @@ var SYS_TREE = {
|
|
|
13889
14262
|
slicc_opfs_ops: (listing) => `${listing.opfsOps ?? 0}
|
|
13890
14263
|
`,
|
|
13891
14264
|
slicc_cwd_checks: (listing) => `${listing.cwdChecks ?? 0}
|
|
13892
|
-
|
|
14265
|
+
`,
|
|
14266
|
+
slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
|
|
14267
|
+
`,
|
|
14268
|
+
slicc_rename_acks: (listing) => {
|
|
14269
|
+
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
14270
|
+
const median = samples[Math.floor(samples.length / 2)] ?? 0;
|
|
14271
|
+
const most = samples.at(-1) ?? 0;
|
|
14272
|
+
const waits = listing.renameAcks?.waits ?? 0;
|
|
14273
|
+
const queries = listing.renameAcks?.queries ?? 0;
|
|
14274
|
+
return `${listing.renameAcks?.acks ?? 0} ${median.toFixed(1)} ${most.toFixed(1)} ${waits} ${queries}
|
|
14275
|
+
`;
|
|
14276
|
+
}
|
|
13893
14277
|
}
|
|
13894
14278
|
};
|
|
13895
14279
|
function isSysFile(at) {
|
|
@@ -19721,7 +20105,7 @@ function sniffPg(start2) {
|
|
|
19721
20105
|
const length2 = int32(bytes, 0);
|
|
19722
20106
|
return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
|
|
19723
20107
|
}
|
|
19724
|
-
var
|
|
20108
|
+
var PLAIN2 = "SCRAM-SHA-256";
|
|
19725
20109
|
var PLUS = "SCRAM-SHA-256-PLUS";
|
|
19726
20110
|
var END_POINT = "p=tls-server-end-point,,";
|
|
19727
20111
|
var SASL = 10;
|
|
@@ -19843,7 +20227,7 @@ function pgLength(bytes, started) {
|
|
|
19843
20227
|
const length2 = int32(bytes, started ? 1 : 0);
|
|
19844
20228
|
return started ? 1 + length2 : length2;
|
|
19845
20229
|
}
|
|
19846
|
-
var MECHANISMS = /* @__PURE__ */ new Set([
|
|
20230
|
+
var MECHANISMS = /* @__PURE__ */ new Set([PLAIN2, PLUS]);
|
|
19847
20231
|
async function cleartext(message3, asks) {
|
|
19848
20232
|
const body = latin2(message3.subarray(5));
|
|
19849
20233
|
if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
|
|
@@ -19876,7 +20260,7 @@ function serverHeader(header4, server) {
|
|
|
19876
20260
|
function rewritten(first, header4) {
|
|
19877
20261
|
const parsed2 = clientFirstOf(first.data);
|
|
19878
20262
|
if (!parsed2 || parsed2.header === header4) return first;
|
|
19879
|
-
return { mechanism: header4 === END_POINT ? PLUS :
|
|
20263
|
+
return { mechanism: header4 === END_POINT ? PLUS : PLAIN2, data: `${header4}${parsed2.bare}` };
|
|
19880
20264
|
}
|
|
19881
20265
|
var PgClient = class {
|
|
19882
20266
|
clientFirst;
|
|
@@ -27494,7 +27878,7 @@ var RULE = new RegExp(
|
|
|
27494
27878
|
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
27495
27879
|
);
|
|
27496
27880
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
27497
|
-
var
|
|
27881
|
+
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
27498
27882
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
27499
27883
|
function failed2(errno3, error) {
|
|
27500
27884
|
return { error, errno: errno3 };
|
|
@@ -27521,7 +27905,7 @@ function splitWords(text) {
|
|
|
27521
27905
|
return words2;
|
|
27522
27906
|
}
|
|
27523
27907
|
function quoteWord(word) {
|
|
27524
|
-
return
|
|
27908
|
+
return PLAIN3.test(word) ? word : `'${word.replaceAll("'", `'\\''`)}'`;
|
|
27525
27909
|
}
|
|
27526
27910
|
function validWho(who) {
|
|
27527
27911
|
if (who === "ALL") return true;
|
|
@@ -29334,7 +29718,8 @@ var Launcher = class {
|
|
|
29334
29718
|
fsCalls: servedFsCalls(),
|
|
29335
29719
|
opfsCalls: this.rootFs.opfsCalls?.() ?? 0,
|
|
29336
29720
|
opfsOps: this.rootFs.opfsOps?.() ?? 0,
|
|
29337
|
-
cwdChecks: this.cwds.checks
|
|
29721
|
+
cwdChecks: this.cwds.checks,
|
|
29722
|
+
renameAcks: this.rootFs.renameWaits?.()
|
|
29338
29723
|
}),
|
|
29339
29724
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
29340
29725
|
crontab: (call) => this.crontab(pid, call),
|