@ai-ecoverse/slicc-kernel 1.146.2 → 1.146.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -3305,7 +3305,7 @@ function satisfies(version, range2) {
3305
3305
  }
3306
3306
 
3307
3307
  // src/version.ts
3308
- var KERNEL_VERSION = true ? "1.146.2" : "0.0.0-dev";
3308
+ var KERNEL_VERSION = true ? "1.146.4" : "0.0.0-dev";
3309
3309
  var OS_RELEASE = "6.0.0-slicc";
3310
3310
  function procVersion() {
3311
3311
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -4177,6 +4177,55 @@ var Crontabs = class {
4177
4177
 
4178
4178
  // src/fs/unlinked.ts
4179
4179
  var UNLINKED_DIR = ".slicc-unlinked";
4180
+ var PathMarks = class {
4181
+ gen = 0;
4182
+ floor = 0;
4183
+ touched = /* @__PURE__ */ new Map();
4184
+ flying = /* @__PURE__ */ new Map();
4185
+ generation() {
4186
+ return this.gen;
4187
+ }
4188
+ touch(target) {
4189
+ this.gen += 1;
4190
+ this.touched.delete(target);
4191
+ this.touched.set(target, this.gen);
4192
+ if (this.touched.size <= TOUCHED_MAX) return;
4193
+ const [oldest, at] = this.touched.entries().next().value;
4194
+ this.touched.delete(oldest);
4195
+ this.floor = at;
4196
+ }
4197
+ changedSince(path, gen) {
4198
+ if (gen < this.floor) return true;
4199
+ for (let p = path; this.touched.size > 0; p = parentOf2(p)) {
4200
+ if ((this.touched.get(p) ?? 0) > gen) return true;
4201
+ if (p === "/") return false;
4202
+ }
4203
+ return false;
4204
+ }
4205
+ async around(paths, op) {
4206
+ for (const p of paths) {
4207
+ this.flying.set(p, (this.flying.get(p) ?? 0) + 1);
4208
+ this.touch(p);
4209
+ }
4210
+ try {
4211
+ return await op();
4212
+ } finally {
4213
+ for (const p of paths) {
4214
+ const n = (this.flying.get(p) ?? 1) - 1;
4215
+ if (n > 0) this.flying.set(p, n);
4216
+ else this.flying.delete(p);
4217
+ this.touch(p);
4218
+ }
4219
+ }
4220
+ }
4221
+ inFlight(path) {
4222
+ for (let p = path; this.flying.size > 0; p = parentOf2(p)) {
4223
+ if (this.flying.has(p)) return true;
4224
+ if (p === "/") return false;
4225
+ }
4226
+ return false;
4227
+ }
4228
+ };
4180
4229
  function pidOwner(proc) {
4181
4230
  return {
4182
4231
  id: `p${proc.pid}`,
@@ -4243,14 +4292,13 @@ var UnlinkedKeeper = class {
4243
4292
  queue = Promise.resolve();
4244
4293
  count = 0;
4245
4294
  replacing = /* @__PURE__ */ new Map();
4246
- gen = 0;
4247
- floor = 0;
4248
- touched = /* @__PURE__ */ new Map();
4295
+ marks;
4249
4296
  replaced = 0;
4250
4297
  links = /* @__PURE__ */ new Map();
4251
4298
  linked = /* @__PURE__ */ new Map();
4252
4299
  dirOwner;
4253
4300
  constructor(fs, holders, rootOf, options = {}) {
4301
+ this.marks = options.marks ?? new PathMarks();
4254
4302
  const { locks, owner } = options;
4255
4303
  this.dirOwner = options.dirOwner;
4256
4304
  this.fs = fs;
@@ -4272,7 +4320,6 @@ var UnlinkedKeeper = class {
4272
4320
  const { replacing } = this;
4273
4321
  const replace = async (target, op) => {
4274
4322
  const { promise, resolve: resolve2 } = Promise.withResolvers();
4275
- keeper.touch(target);
4276
4323
  let mine;
4277
4324
  const gated = () => {
4278
4325
  const before = replacing.get(target);
@@ -4283,10 +4330,9 @@ var UnlinkedKeeper = class {
4283
4330
  if (mine) mine.sealed = true;
4284
4331
  };
4285
4332
  try {
4286
- await op(gated, sealed);
4333
+ await keeper.marks.around([target], () => op(gated, sealed));
4287
4334
  } finally {
4288
4335
  keeper.replaced += 1;
4289
- keeper.touch(target);
4290
4336
  resolve2();
4291
4337
  if (mine && replacing.get(target) === mine) replacing.delete(target);
4292
4338
  }
@@ -4337,25 +4383,15 @@ var UnlinkedKeeper = class {
4337
4383
  const target = fs.resolvePath("/", to);
4338
4384
  const source = fs.resolvePath("/", from);
4339
4385
  if (target === source) return fs.rename(from, to);
4340
- keeper.touch(source);
4341
- try {
4342
- await replace(target, async (gated, sealed) => {
4386
+ await keeper.marks.around(
4387
+ [source],
4388
+ () => replace(target, async (gated, sealed) => {
4343
4389
  const pinned = await keeper.pin(target, gated, sealed);
4344
4390
  await keeper.settle(pinned, () => fs.rename(from, to));
4345
- });
4346
- } finally {
4347
- keeper.touch(source);
4348
- }
4349
- },
4350
- async symlink(target, path, owner) {
4351
- const at = fs.resolvePath("/", path);
4352
- keeper.touch(at);
4353
- try {
4354
- await fs.symlink(target, path, owner);
4355
- } finally {
4356
- keeper.touch(at);
4357
- }
4391
+ })
4392
+ );
4358
4393
  },
4394
+ symlink: (target, path, owner) => keeper.marks.around([fs.resolvePath("/", path)], () => fs.symlink(target, path, owner)),
4359
4395
  readdir: async (path) => visible(await fs.readdir(path)),
4360
4396
  readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR).map(([name2, st]) => [name2, st && counted3(st)])
4361
4397
  };
@@ -4367,24 +4403,13 @@ var UnlinkedKeeper = class {
4367
4403
  }
4368
4404
  }
4369
4405
  generation() {
4370
- return this.gen;
4406
+ return this.marks.generation();
4371
4407
  }
4372
4408
  changedSince(path, gen) {
4373
- if (gen < this.floor) return true;
4374
- for (let p = path; this.touched.size > 0; p = parentOf2(p)) {
4375
- if ((this.touched.get(p) ?? 0) > gen) return true;
4376
- if (p === "/") return false;
4377
- }
4378
- return false;
4409
+ return this.marks.changedSince(path, gen);
4379
4410
  }
4380
- touch(target) {
4381
- this.gen += 1;
4382
- this.touched.delete(target);
4383
- this.touched.set(target, this.gen);
4384
- if (this.touched.size <= TOUCHED_MAX) return;
4385
- const [oldest, at] = this.touched.entries().next().value;
4386
- this.touched.delete(oldest);
4387
- this.floor = at;
4411
+ inFlight(path) {
4412
+ return this.marks.inFlight(path);
4388
4413
  }
4389
4414
  missed(path) {
4390
4415
  for (let p = path; this.replacing.size > 0; p = parentOf2(p)) {
@@ -6361,16 +6386,16 @@ var FreshModules = class {
6361
6386
  if (size < MAGIC.length && this.fresh.has(normalizePath(path))) await decide(path);
6362
6387
  };
6363
6388
  }
6364
- const bound2 = /* @__PURE__ */ new WeakMap();
6389
+ const bound3 = /* @__PURE__ */ new WeakMap();
6365
6390
  return new Proxy(fs, {
6366
6391
  get(target, key, receiver) {
6367
6392
  if (Object.hasOwn(overrides, key)) return overrides[key];
6368
6393
  const value2 = Reflect.get(target, key, receiver);
6369
6394
  if (typeof value2 !== "function") return value2;
6370
- let method = bound2.get(value2);
6395
+ let method = bound3.get(value2);
6371
6396
  if (method === void 0) {
6372
6397
  method = value2.bind(target);
6373
- bound2.set(value2, method);
6398
+ bound3.set(value2, method);
6374
6399
  }
6375
6400
  return method;
6376
6401
  }
@@ -8013,6 +8038,12 @@ var HeldSet = class extends Set {
8013
8038
  holds2.onIdle = this.idle;
8014
8039
  return super.add(holds2);
8015
8040
  }
8041
+ doubt(paths, over) {
8042
+ for (const holds2 of this) {
8043
+ for (const path of paths) holds2.doubt(path, true);
8044
+ if (over !== void 0) holds2.doubt(over);
8045
+ }
8046
+ }
8016
8047
  delete(holds2) {
8017
8048
  const removed = super.delete(holds2);
8018
8049
  for (const path of /* @__PURE__ */ new Set([...holds2.keys(), ...holds2.opens.keys()])) this.idle(path);
@@ -8034,6 +8065,9 @@ var HeldPaths = class extends Map {
8034
8065
  uses = /* @__PURE__ */ new Map();
8035
8066
  lastHandle = 0;
8036
8067
  owning;
8068
+ bound = /* @__PURE__ */ new Map();
8069
+ doubted = /* @__PURE__ */ new Map();
8070
+ doubts = 0;
8037
8071
  onIdle;
8038
8072
  keyOf(path) {
8039
8073
  return this.aliases.get(path) ?? path;
@@ -8054,6 +8088,21 @@ var HeldPaths = class extends Map {
8054
8088
  handlesAt(path) {
8055
8089
  return [...this.handles].filter(([, key]) => key === path).map(([id2]) => id2);
8056
8090
  }
8091
+ doubt(over, exact = false) {
8092
+ if (this.bound.size === 0) return;
8093
+ for (const [handle, key] of this.handles) {
8094
+ if (!this.bound.has(handle) || this.keptHandles.has(handle)) continue;
8095
+ if (exact ? key === over : within5(key, over)) this.doubted.set(handle, ++this.doubts);
8096
+ }
8097
+ }
8098
+ boundIno(handle) {
8099
+ const doubt = this.doubted.get(handle);
8100
+ const ino = this.bound.get(handle);
8101
+ return doubt === void 0 || ino === void 0 ? void 0 : { ino, doubt };
8102
+ }
8103
+ trust(handle, doubt) {
8104
+ if (this.doubted.get(handle) === doubt) this.doubted.delete(handle);
8105
+ }
8057
8106
  keptFor(handle) {
8058
8107
  return this.keptHandles.get(handle);
8059
8108
  }
@@ -8090,8 +8139,16 @@ var HeldPaths = class extends Map {
8090
8139
  for (const file of [...this.uses.keys()]) this.letGo(file, true);
8091
8140
  this.keptHandles.clear();
8092
8141
  }
8093
- hold(path, on, open = false, real, handle) {
8094
- if (open) return this.holdOpen(path, on, real, handle);
8142
+ hold(path, on, open = false, real, handle, ino) {
8143
+ if (open) {
8144
+ const made2 = this.holdOpen(path, on, real, handle);
8145
+ if (handle !== void 0) {
8146
+ this.bound.delete(handle);
8147
+ this.doubted.delete(handle);
8148
+ }
8149
+ if (made2 !== void 0 && ino !== void 0) this.bound.set(made2, ino);
8150
+ return made2;
8151
+ }
8095
8152
  this.holdWrite(path, on);
8096
8153
  return void 0;
8097
8154
  }
@@ -9768,13 +9825,24 @@ async function holdOp(entry, path, req) {
9768
9825
  const real = await entry.fs.realpath?.(path, true).catch(() => path);
9769
9826
  await entry.source?.open(path, real);
9770
9827
  await stillThere(entry, path, req);
9771
- if (!r || !r.missed(path) && !r.changedSince(path, gen))
9772
- return json2(entry.hold?.(path, on, open, real) ?? null);
9828
+ if (req.nofollow && !await ownEntry(entry, path, real ?? path)) continue;
9829
+ if (!r || !r.missed(path) && !r.changedSince(path, gen) && !r.inFlight?.(path))
9830
+ return json2(entry.hold?.(path, on, open, real, void 0, req.ino) ?? null);
9773
9831
  }
9774
9832
  }
9775
9833
  entry.hold?.(path, on, open, void 0, req.handle);
9776
9834
  return done;
9777
9835
  }
9836
+ async function ownEntry(entry, path, real) {
9837
+ const own = await entry.fs.realpath?.(path, false).catch((err) => {
9838
+ if (err.code !== "ENOENT") throw err;
9839
+ return path;
9840
+ });
9841
+ if (own !== void 0 && own !== real) return false;
9842
+ const st = await entry.fs.lstat(path);
9843
+ if (st.isSymbolicLink) throw syncError("ELOOP", path);
9844
+ return true;
9845
+ }
9778
9846
  async function followed(g, path) {
9779
9847
  const st = await g.fs.lstat(path).catch(() => void 0);
9780
9848
  if (st?.isSymbolicLink && !trustedLink(permOf(st), g.links)) deny(g, "follow", path);
@@ -9909,10 +9977,26 @@ async function linkedElsewhere(fs, path, from) {
9909
9977
  return !(source && source.ino === st.ino && source.dev === st.dev);
9910
9978
  }
9911
9979
  async function keptOr(entry, path, handle) {
9912
- if (handle !== void 0) return entry.keptFor?.(handle)?.hidden ?? path;
9980
+ if (handle !== void 0) {
9981
+ const hidden = entry.keptFor?.(handle)?.hidden;
9982
+ if (hidden !== void 0) return hidden;
9983
+ await bound(entry, path, handle);
9984
+ return path;
9985
+ }
9913
9986
  const kept = entry.unlinked?.(path);
9914
9987
  return kept && !await entry.fs.exists(path) ? kept.hidden : path;
9915
9988
  }
9989
+ async function bound(entry, path, handle) {
9990
+ const bound3 = entry.boundIno?.(handle);
9991
+ if (bound3 === void 0) return;
9992
+ const now = await entry.fs.stat(path).catch(() => void 0);
9993
+ if (now?.ino === bound3.ino) {
9994
+ entry.trust?.(handle, bound3.doubt);
9995
+ return;
9996
+ }
9997
+ staleFds++;
9998
+ throw syncError("ESTALE", path);
9999
+ }
9916
10000
  async function keptStat(entry, req) {
9917
10001
  const hidden = entry.keptFor?.(req.handle ?? -1)?.hidden;
9918
10002
  if (hidden === void 0)
@@ -9939,6 +10023,10 @@ var served = 0;
9939
10023
  function servedFsCalls() {
9940
10024
  return served;
9941
10025
  }
10026
+ var staleFds = 0;
10027
+ function staleFdCount() {
10028
+ return staleFds;
10029
+ }
9942
10030
  async function dispatchSyncFs(req) {
9943
10031
  served++;
9944
10032
  const entry = resolveSyncFsToken(req.token);
@@ -10714,6 +10802,8 @@ var SYS_TREE = {
10714
10802
  slicc_cwd_checks: (listing) => `${listing.cwdChecks ?? 0}
10715
10803
  `,
10716
10804
  slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
10805
+ `,
10806
+ slicc_stale_fds: (listing) => `${listing.staleFds ?? 0}
10717
10807
  `,
10718
10808
  slicc_rename_acks: (listing) => {
10719
10809
  const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
@@ -15226,7 +15316,7 @@ async function writeAll2(file, bytes) {
15226
15316
  const write = file.write;
15227
15317
  for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
15228
15318
  }
15229
- function bound(file, key) {
15319
+ function bound2(file, key) {
15230
15320
  const method = file[key];
15231
15321
  return typeof method === "function" ? { [key]: method.bind(file) } : {};
15232
15322
  }
@@ -15318,9 +15408,9 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
15318
15408
  later(stream2.idle());
15319
15409
  };
15320
15410
  return new OpenFile({
15321
- ...bound(file, "read"),
15322
- ...bound(file, "peek"),
15323
- ...bound(file, "stat"),
15411
+ ...bound2(file, "read"),
15412
+ ...bound2(file, "peek"),
15413
+ ...bound2(file, "stat"),
15324
15414
  poll: () => {
15325
15415
  const state = pollFile(file);
15326
15416
  return quiet3() ? state : { ...state, writable: false };
@@ -21039,7 +21129,9 @@ function holdingToken(opts, holds2, caller) {
21039
21129
  ...opts.statfs ? { statfs: opts.statfs } : {},
21040
21130
  ...opts.renames ? { renames: opts.renames } : {},
21041
21131
  ...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
21042
- hold: (path, on, open, real, handle) => holds2.hold(path, on, open, real, handle),
21132
+ hold: (path, on, open, real, handle, ino) => holds2.hold(path, on, open, real, handle, ino),
21133
+ boundIno: holds2.boundIno.bind(holds2),
21134
+ trust: holds2.trust.bind(holds2),
21043
21135
  keptFor: (handle) => holds2.keptFor(handle),
21044
21136
  unlinked: (path) => holds2.keptAt(path),
21045
21137
  gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
@@ -27988,6 +28080,7 @@ var Launcher = class {
27988
28080
  fstabRetries;
27989
28081
  inserted = /* @__PURE__ */ new Map();
27990
28082
  openFiles = /* @__PURE__ */ new Set();
28083
+ pathMarks = new PathMarks();
27991
28084
  deciding = /* @__PURE__ */ new Map();
27992
28085
  identities = { asked: 0, timedOut: 0 };
27993
28086
  nodes;
@@ -28108,6 +28201,7 @@ var Launcher = class {
28108
28201
  this.openFiles.add(this.nodes);
28109
28202
  options.fs.onPeer?.(() => this.flushOpen());
28110
28203
  options.fs.remoteChanges?.((change) => {
28204
+ this.held.doubt(change.paths, change.moved?.to);
28111
28205
  if (change.moved) this.moved(change.moved.from, change.moved.to);
28112
28206
  this.changes.flush();
28113
28207
  this.cwds.touched(change.paths, change.trees);
@@ -28122,6 +28216,7 @@ var Launcher = class {
28122
28216
  locks: webLocks(),
28123
28217
  busy: (path) => [...this.openFiles].some((nodes) => nodes.holds(path)),
28124
28218
  owner: options.unlinkOwner,
28219
+ marks: this.pathMarks,
28125
28220
  ...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
28126
28221
  }
28127
28222
  );
@@ -29119,7 +29214,8 @@ var Launcher = class {
29119
29214
  opfsCalls: this.rootFs.opfsCalls?.() ?? 0,
29120
29215
  opfsOps: this.rootFs.opfsOps?.() ?? 0,
29121
29216
  cwdChecks: this.cwds.checks,
29122
- renameAcks: this.rootFs.renameWaits?.()
29217
+ renameAcks: this.rootFs.renameWaits?.(),
29218
+ staleFds: staleFdCount()
29123
29219
  }),
29124
29220
  sudo: (call, signal) => this.sudo(pid, call, signal),
29125
29221
  crontab: (call) => this.crontab(pid, call),
@@ -30043,6 +30139,7 @@ var Launcher = class {
30043
30139
  locks: webLocks(),
30044
30140
  busy: (path) => [...this.openFiles].some((open) => open.holds(path)),
30045
30141
  owner: this.unlinkOwnerOption,
30142
+ marks: this.pathMarks,
30046
30143
  ...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
30047
30144
  }
30048
30145
  );
@@ -30096,6 +30193,7 @@ var Launcher = class {
30096
30193
  this.renameLog.add(from, to);
30097
30194
  if (source) return;
30098
30195
  for (const nodes of this.openFiles) nodes.renamed(from, to);
30196
+ for (const holds2 of this.held) holds2.renamed(from, to);
30099
30197
  this.watchers.moved(from, to);
30100
30198
  }
30101
30199
  processChain(fs, nodes, unlinked) {