@ai-ecoverse/slicc-kernel 1.143.4 → 1.143.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -287,7 +287,7 @@ function normal(path) {
287
287
  }
288
288
  return `/${parts.join("/")}`;
289
289
  }
290
- var GEN, RING, RING_SIZE, SLOT, SHARED_TTL_MS, DIRTY, FOREIGN, CHANGES_BYTES, ChangeView;
290
+ var GEN, RING, RING_SIZE, SLOT, SHARED_TTL_MS, RENAME_WAIT_MS, DIRTY, FOREIGN, RENAMES, CHANGES_BYTES, ChangeView;
291
291
  var init_changes = __esm({
292
292
  "src/fs/changes.ts"() {
293
293
  "use strict";
@@ -296,9 +296,11 @@ var init_changes = __esm({
296
296
  RING_SIZE = 4096;
297
297
  SLOT = 2;
298
298
  SHARED_TTL_MS = 100;
299
+ RENAME_WAIT_MS = 100;
299
300
  DIRTY = RING + RING_SIZE * SLOT;
300
301
  FOREIGN = DIRTY + 1;
301
- CHANGES_BYTES = (FOREIGN + 1) * 4;
302
+ RENAMES = FOREIGN + 1;
303
+ CHANGES_BYTES = (RENAMES + 1) * 4;
302
304
  ChangeView = class {
303
305
  view;
304
306
  constructor(sab) {
@@ -313,6 +315,13 @@ var init_changes = __esm({
313
315
  foreign() {
314
316
  return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
315
317
  }
318
+ renames() {
319
+ return this.view.length > RENAMES ? Atomics.load(this.view, RENAMES) : 0;
320
+ }
321
+ awaitRename(seen, ms) {
322
+ if (this.view.length > RENAMES) Atomics.wait(this.view, RENAMES, seen, ms);
323
+ return this.renames();
324
+ }
316
325
  changedSince(seen, path) {
317
326
  const now = Atomics.load(this.view, GEN);
318
327
  const distance = now - seen >>> 0;
@@ -730,7 +739,8 @@ var init_sync_fs_wire = __esm({
730
739
  "truncate",
731
740
  "chown",
732
741
  "lchown",
733
- "access"
742
+ "access",
743
+ "renames"
734
744
  ];
735
745
  HOLD_READ = 4;
736
746
  HOLD_WRITE = 8;
@@ -747,7 +757,8 @@ var init_sync_fs_wire = __esm({
747
757
  "readlink",
748
758
  "statfs",
749
759
  "kept",
750
- "access"
760
+ "access",
761
+ "renames"
751
762
  ]);
752
763
  }
753
764
  });
@@ -966,6 +977,7 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
966
977
  const entry = (p) => [p, p.slice(0, p.lastIndexOf("/")) || "/"];
967
978
  return {
968
979
  ...bridge.changes ? { changes: bridge.changes } : {},
980
+ ...bridge.renames ? { renames: bridge.renames.bind(bridge) } : {},
969
981
  readFile: (p) => bridge.readFile(p),
970
982
  readdir: (p) => bridge.readdir(p),
971
983
  readdirStat: (p) => {
@@ -1082,6 +1094,7 @@ var init_wasi_files = __esm({
1082
1094
  seen = 0;
1083
1095
  maxFile;
1084
1096
  handle;
1097
+ moved;
1085
1098
  constructor(fs, path, empty, maxFile, size, version, watch) {
1086
1099
  this.fs = fs;
1087
1100
  this.where = path;
@@ -1090,7 +1103,11 @@ var init_wasi_files = __esm({
1090
1103
  this.watch = watch;
1091
1104
  this.seen = watch?.seen ?? watch?.view.now() ?? 0;
1092
1105
  if (size !== void 0 && pread && pwrite && truncate) {
1093
- const io = { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };
1106
+ const io = {
1107
+ pread: (_, ...rest2) => this.retried(() => pread.call(fs, this.where, ...rest2)),
1108
+ pwrite: (_, ...rest2) => this.retried(() => pwrite.call(fs, this.where, ...rest2)),
1109
+ truncate: (_, size2) => this.retried(() => truncate.call(fs, this.where, size2))
1110
+ };
1094
1111
  this.ranged = new RangedFile(io, path, size, version, watch);
1095
1112
  if (empty) this.truncate(0);
1096
1113
  } else if (empty) {
@@ -1102,6 +1119,14 @@ var init_wasi_files = __esm({
1102
1119
  get path() {
1103
1120
  return this.where;
1104
1121
  }
1122
+ retried(op) {
1123
+ try {
1124
+ return op();
1125
+ } catch (err) {
1126
+ if (err.code !== "ENOENT" || !this.moved?.(true)) throw err;
1127
+ return op();
1128
+ }
1129
+ }
1105
1130
  set path(path) {
1106
1131
  this.where = path;
1107
1132
  if (this.ranged) this.ranged.path = path;
@@ -1125,7 +1150,7 @@ var init_wasi_files = __esm({
1125
1150
  }
1126
1151
  if (!this.data) {
1127
1152
  this.seen = view?.now() ?? 0;
1128
- this.data = this.fs.readFile(this.path);
1153
+ this.data = this.retried(() => this.fs.readFile(this.path));
1129
1154
  this.length = this.data.length;
1130
1155
  }
1131
1156
  return this.data;
@@ -1166,8 +1191,9 @@ var init_wasi_files = __esm({
1166
1191
  append(bytes) {
1167
1192
  const { append } = this.fs;
1168
1193
  if (!append || this.orphaned) return void 0;
1194
+ this.moved?.(false);
1169
1195
  this.flush();
1170
- const end = append.call(this.fs, this.path, bytes);
1196
+ const end = this.retried(() => append.call(this.fs, this.path, bytes));
1171
1197
  if (!this.ranged) {
1172
1198
  this.data = void 0;
1173
1199
  this.length = 0;
@@ -1215,11 +1241,17 @@ var init_wasi_files = __esm({
1215
1241
  }
1216
1242
  flush() {
1217
1243
  if (this.orphaned || !this.dirty) return;
1244
+ this.moved?.(false);
1218
1245
  if (this.ranged) this.ranged.flush();
1219
1246
  else if (!this.data) return;
1220
- else if (this.whole || !this.fs.pwrite)
1221
- this.fs.writeFile(this.path, this.data.slice(0, this.length), true);
1222
- else this.fs.pwrite(this.path, this.from, this.data.slice(this.from, this.to), true);
1247
+ else if (this.whole || !this.fs.pwrite) {
1248
+ const whole = this.data.slice(0, this.length);
1249
+ this.retried(() => this.fs.writeFile(this.path, whole, true));
1250
+ } else {
1251
+ const { pwrite } = this.fs;
1252
+ const run = this.data.slice(this.from, this.to);
1253
+ this.retried(() => pwrite.call(this.fs, this.path, this.from, run, true));
1254
+ }
1223
1255
  this.dirty = false;
1224
1256
  this.whole = false;
1225
1257
  this.from = Infinity;
@@ -3061,6 +3093,7 @@ var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY2, O_RDWR2, O_APPEND2, SEALED_PATH, CLIP
3061
3093
  var init_wasi_fds = __esm({
3062
3094
  "src/process/wasi/wasi-fds.ts"() {
3063
3095
  "use strict";
3096
+ init_changes();
3064
3097
  init_ranged();
3065
3098
  init_fd_table();
3066
3099
  init_sync_fs_wire();
@@ -3081,9 +3114,29 @@ var init_wasi_fds = __esm({
3081
3114
  ids = /* @__PURE__ */ new Map();
3082
3115
  kernel;
3083
3116
  fs;
3117
+ renamesSeen;
3084
3118
  constructor(kernel, fs) {
3085
3119
  this.kernel = kernel;
3086
3120
  this.fs = fs;
3121
+ this.renamesSeen = fs.changes?.renames() ?? 0;
3122
+ }
3123
+ ownRename(seq) {
3124
+ if (seq !== void 0 && seq === (this.renamesSeen + 1 | 0)) this.renamesSeen = seq;
3125
+ }
3126
+ followRenames(missing2 = false) {
3127
+ const view = this.fs.changes;
3128
+ let now = view?.renames() ?? 0;
3129
+ if (missing2 && view && now === this.renamesSeen) now = view.awaitRename(now, RENAME_WAIT_MS);
3130
+ if (now === this.renamesSeen || !this.fs.renames) return false;
3131
+ const held2 = [...this.buffers].filter(([, b]) => !b.isOrphan()).map(([p]) => p);
3132
+ if (held2.length === 0) {
3133
+ this.renamesSeen = now;
3134
+ return false;
3135
+ }
3136
+ const { now: seen, renames } = this.fs.renames(this.renamesSeen, held2);
3137
+ this.renamesSeen = seen;
3138
+ for (const [from, to] of renames) this.renamed(from, to, void 0, true);
3139
+ return renames.length > 0;
3087
3140
  }
3088
3141
  setup(cwd, inherited, root = false) {
3089
3142
  for (const fd of [0, 1, 2]) this.table.set(fd, this.stdioEntry(fd));
@@ -3283,6 +3336,7 @@ var init_wasi_fds = __esm({
3283
3336
  get(fd) {
3284
3337
  const e = this.find(fd);
3285
3338
  if (!e) throw new WasiError("EBADF");
3339
+ if (e.type === "file") this.followRenames();
3286
3340
  return e;
3287
3341
  }
3288
3342
  preopen(fd) {
@@ -3603,9 +3657,9 @@ var init_wasi_fds = __esm({
3603
3657
  buffer.orphan();
3604
3658
  this.forget(buffer);
3605
3659
  }
3606
- renamed(from, to, replacedLinked) {
3660
+ renamed(from, to, replacedLinked, foreign = false) {
3607
3661
  if (from === to) return;
3608
- if (this.shared) this.kernel.call({ op: "fd-path-renamed", from, to });
3662
+ if (this.shared && !foreign) this.kernel.call({ op: "fd-path-renamed", from, to });
3609
3663
  for (const e of this.table.values()) {
3610
3664
  if (e.type === "kernel" && e.path !== void 0 && within(e.path, from)) {
3611
3665
  e.path = to + e.path.slice(from.length);
@@ -3613,6 +3667,7 @@ var init_wasi_fds = __esm({
3613
3667
  }
3614
3668
  const moved = [];
3615
3669
  for (const [p, buffer] of this.buffers) {
3670
+ if (foreign && buffer.isOrphan()) continue;
3616
3671
  if (within(p, from)) moved.push([p, buffer]);
3617
3672
  else if (within(p, to)) {
3618
3673
  this.detach(buffer, replacedLinked);
@@ -3754,6 +3809,7 @@ var init_wasi_fds = __esm({
3754
3809
  }
3755
3810
  file(path, existing, oflags, rights, fdflags, mode, created = false) {
3756
3811
  const { readable: readable3, writable: writable2 } = openAccess(existing, oflags, rights);
3812
+ this.followRenames();
3757
3813
  let buffer = created ? void 0 : this.buffers.get(path);
3758
3814
  if (buffer?.handle !== void 0 && this.fs.kept?.(buffer.handle)) {
3759
3815
  this.buffers.delete(path);
@@ -3801,6 +3857,7 @@ var init_wasi_fds = __esm({
3801
3857
  st
3802
3858
  );
3803
3859
  const buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version, watch);
3860
+ buffer.moved = (missing2) => this.followRenames(missing2);
3804
3861
  buffer.handle = handle;
3805
3862
  this.buffers.set(path, buffer);
3806
3863
  const id = this.identity(st);
@@ -4976,6 +5033,7 @@ var init_wasi_host = __esm({
4976
5033
  startCwd;
4977
5034
  interruptWakes = false;
4978
5035
  strictEpoll = false;
5036
+ cwdFd = false;
4979
5037
  entered = false;
4980
5038
  enteredSignals = 0;
4981
5039
  raisedOnEntry;
@@ -5606,8 +5664,9 @@ var init_wasi_host = __esm({
5606
5664
  const to = at(fd2, p2, l2);
5607
5665
  fds.flushPath(from);
5608
5666
  const replaced = fds.holdsUnder(to) ? linkedElsewhere(o.fs, to) : void 0;
5609
- o.fs.rename(from, to);
5667
+ const seq = o.fs.rename(from, to);
5610
5668
  fds.renamed(from, to, replaced);
5669
+ fds.ownRename(typeof seq === "number" ? seq : void 0);
5611
5670
  },
5612
5671
  path_symlink: (tp, tl, dirfd, p, l) => {
5613
5672
  const path = at(dirfd, p, l);
@@ -6725,7 +6784,7 @@ var KERNEL_VERSION, OS_RELEASE;
6725
6784
  var init_version = __esm({
6726
6785
  "src/version.ts"() {
6727
6786
  "use strict";
6728
- KERNEL_VERSION = true ? "1.143.4" : "0.0.0-dev";
6787
+ KERNEL_VERSION = true ? "1.143.6" : "0.0.0-dev";
6729
6788
  OS_RELEASE = "6.0.0-slicc";
6730
6789
  }
6731
6790
  });
@@ -8075,7 +8134,9 @@ function createSyncFsSabBridge(transport, opts = {}) {
8075
8134
  run({ op: "rm", path }, path);
8076
8135
  },
8077
8136
  rename: (from, to) => {
8078
- run({ op: "rename", path: from, arg2: to }, from);
8137
+ const r = run({ op: "rename", path: from, arg2: to }, from);
8138
+ const seq = r.ok && r.kind === "json" ? r.json.seq : void 0;
8139
+ return typeof seq === "number" ? seq : void 0;
8079
8140
  },
8080
8141
  link: (from, to, follow3) => {
8081
8142
  run({ op: "link", path: from, arg2: to, ...follow3 ? { mode: 1 } : {} }, from);
@@ -8156,7 +8217,11 @@ function createSyncFsSabBridge(transport, opts = {}) {
8156
8217
  run({ op: "hold", path, mode, ...handle !== void 0 ? { handle } : {} }, path);
8157
8218
  return void 0;
8158
8219
  },
8159
- statfs: (path = "/") => parseSyncFsUsage(json2({ op: "statfs", path }, path))
8220
+ statfs: (path = "/") => parseSyncFsUsage(json2({ op: "statfs", path }, path)),
8221
+ renames: (since, held2) => json2(
8222
+ { op: "renames", path: "/", offset: since, arg2: JSON.stringify(held2) },
8223
+ "/"
8224
+ )
8160
8225
  };
8161
8226
  }
8162
8227
  var UNCOUNTED_OPS, calls, looks, SPIN_MS, SPIN_STRIDE, SPIN_STRIDES, SPIN_CORES, spinning, SPIN_CAP_MS;
@@ -8353,12 +8418,130 @@ function freshState(stat) {
8353
8418
  const base = { len: 0, loaded: false, dirty: false, openCount: 0 };
8354
8419
  return stat ? { stat, statAt: syncCallCount(), filledAt: performance.now(), seenAt: syncEpoch(), ...base } : base;
8355
8420
  }
8421
+ function inCache(Fs, node) {
8422
+ const table = Fs.nameTable;
8423
+ const parent = node.parent;
8424
+ const hash = Fs.hashName?.(parent.id ?? 0, node.name);
8425
+ if (!table || hash === void 0) return true;
8426
+ let at = table[hash];
8427
+ while (at) {
8428
+ if (at === node) return true;
8429
+ at = at.name_next;
8430
+ }
8431
+ return false;
8432
+ }
8433
+ function heldUnder(held2, from) {
8434
+ let moving = held2;
8435
+ while (moving && moving !== moving.mount.root && liveNodePath(moving) !== from) {
8436
+ moving = moving.parent;
8437
+ }
8438
+ return moving && moving !== moving.mount.root && liveNodePath(moving) === from ? moving : void 0;
8439
+ }
8440
+ function relinked(Fs, moving, to) {
8441
+ const slash = to.lastIndexOf("/");
8442
+ let dir;
8443
+ try {
8444
+ dir = Fs.lookupPath?.(slash <= 0 ? "/" : to.slice(0, slash)).node;
8445
+ } catch {
8446
+ }
8447
+ if (!dir || dir.mount !== moving.mount) return;
8448
+ const name2 = to.slice(slash + 1);
8449
+ try {
8450
+ const existing = Fs.lookupNode?.(dir, name2);
8451
+ if (existing && existing !== moving) Fs.hashRemoveNode?.(existing);
8452
+ } catch {
8453
+ }
8454
+ moving.parent.live.listed = void 0;
8455
+ dir.live.listed = void 0;
8456
+ Fs.hashRemoveNode?.(moving);
8457
+ moving.name = name2;
8458
+ moving.parent = dir;
8459
+ Fs.hashAddNode?.(moving);
8460
+ moving.live.stat = void 0;
8461
+ }
8462
+ function renameFollower(Fs, bridgeOf, call2) {
8463
+ const open = /* @__PURE__ */ new Set();
8464
+ const seen = /* @__PURE__ */ new Map();
8465
+ const follow3 = (node, missing2 = false) => {
8466
+ const bridge = bridgeOf(node);
8467
+ const view = bridge.changes;
8468
+ const since = seen.get(bridge);
8469
+ let now = view?.renames() ?? 0;
8470
+ if (missing2 && view && now === since) now = view.awaitRename(now, RENAME_WAIT_MS);
8471
+ const ask = bridge.renames?.bind(bridge);
8472
+ if (since === void 0 || now === since || !ask) return false;
8473
+ const held2 = [...open].filter((n) => !n.live.orphan && bridgeOf(n) === bridge);
8474
+ if (held2.length === 0) {
8475
+ seen.set(bridge, now);
8476
+ return false;
8477
+ }
8478
+ const reply = call2(
8479
+ () => ask(
8480
+ since,
8481
+ held2.map((n) => liveNodePath(n))
8482
+ )
8483
+ );
8484
+ seen.set(bridge, reply.now);
8485
+ for (const [from, to] of reply.renames) {
8486
+ for (const n of held2) {
8487
+ const moving = heldUnder(n, from);
8488
+ if (moving && inCache(Fs, moving)) relinked(Fs, moving, to);
8489
+ }
8490
+ }
8491
+ return reply.renames.length > 0;
8492
+ };
8493
+ return {
8494
+ open,
8495
+ follow: follow3,
8496
+ track(node, on) {
8497
+ if (!on) {
8498
+ open.delete(node);
8499
+ return;
8500
+ }
8501
+ follow3(node);
8502
+ open.add(node);
8503
+ },
8504
+ watchRenames(bridge) {
8505
+ if (!seen.has(bridge)) seen.set(bridge, bridge.changes?.renames() ?? 0);
8506
+ },
8507
+ ownRename(bridge, seq) {
8508
+ const since = seen.get(bridge);
8509
+ if (seq !== void 0 && since !== void 0 && seq === (since + 1 | 0))
8510
+ seen.set(bridge, seq);
8511
+ }
8512
+ };
8513
+ }
8514
+ function followingOnce(write2, follow3) {
8515
+ try {
8516
+ write2();
8517
+ } catch (err) {
8518
+ if (err.errno !== wasiErrno("ENOENT") || !follow3()) throw err;
8519
+ write2();
8520
+ }
8521
+ }
8522
+ function renameThrough(h, node, from, to) {
8523
+ const seq = h.call(() => h.bridgeOf(node).rename(from, to));
8524
+ h.ownRename(h.bridgeOf(node), typeof seq === "number" ? seq : void 0);
8525
+ }
8526
+ function heldStream(h, stream, change) {
8527
+ const s = stream.node.live;
8528
+ if ((stream.flags & 3) === 0 || s.orphan) return;
8529
+ const before = s.writers ?? 0;
8530
+ s.writers = Math.max(0, before + change);
8531
+ if (before === 0 !== (s.writers === 0)) {
8532
+ try {
8533
+ h.bridgeOf(stream.node).hold?.(liveNodePath(stream.node), s.writers > 0);
8534
+ } catch {
8535
+ }
8536
+ }
8537
+ }
8356
8538
  function createHelpers(Fs, ops) {
8357
8539
  const bridgeOf = (node) => node.mount.opts.bridge;
8358
8540
  const fileIo = (node) => pinnedIo2(bridgeOf(node), node.live.handle);
8359
8541
  const dirty = /* @__PURE__ */ new Set();
8360
8542
  const handled = /* @__PURE__ */ new Set();
8361
8543
  const linked = linkedStates(bridgeOf);
8544
+ const renames = renameFollower(Fs, bridgeOf, (fn) => call2(fn));
8362
8545
  function markDirty(node) {
8363
8546
  node.live.dirty = true;
8364
8547
  dirty.add(node);
@@ -8451,11 +8634,9 @@ function createHelpers(Fs, ops) {
8451
8634
  function flushNode(node) {
8452
8635
  const s = node.live;
8453
8636
  if (!s.dirty || stale(s) || !(s.data || s.ranged)) return;
8454
- if (s.ranged) call2(() => s.ranged?.flush());
8455
- else {
8456
- const bytes = s.data.slice(0, s.len);
8457
- call2(() => fileIo(node).writeFile(liveNodePath(linked.holder(node)), bytes, true));
8458
- }
8637
+ const whole = () => s.data.slice(0, s.len);
8638
+ const write2 = () => s.ranged ? call2(() => s.ranged?.flush()) : call2(() => fileIo(node).writeFile(liveNodePath(linked.holder(node)), whole(), true));
8639
+ followingOnce(write2, () => renames.follow(node, true));
8459
8640
  s.dirty = false;
8460
8641
  s.stat = void 0;
8461
8642
  }
@@ -8503,6 +8684,7 @@ function createHelpers(Fs, ops) {
8503
8684
  bridgeOf,
8504
8685
  handled,
8505
8686
  linked,
8687
+ ...renames,
8506
8688
  call: call2,
8507
8689
  metadataCall,
8508
8690
  makeNode,
@@ -8662,7 +8844,7 @@ function createNodeOps(h) {
8662
8844
  const from = liveNodePath(oldNode);
8663
8845
  const to = childPath(newDir, newName);
8664
8846
  flushNode(oldNode);
8665
- call2(() => bridgeOf(oldNode).rename(from, to));
8847
+ renameThrough(h, oldNode, from, to);
8666
8848
  try {
8667
8849
  const existing = Fs.lookupNode?.(newDir, newName);
8668
8850
  if (existing && existing !== oldNode) Fs.hashRemoveNode?.(existing);
@@ -8757,21 +8939,11 @@ function dropOpen(s) {
8757
8939
  }
8758
8940
  function createStreamOps(h) {
8759
8941
  const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf, rangedOf } = h;
8760
- const held2 = (stream, change) => {
8761
- const s = stream.node.live;
8762
- if ((stream.flags & 3) === 0 || s.orphan) return;
8763
- const before = s.writers ?? 0;
8764
- s.writers = Math.max(0, before + change);
8765
- if (before === 0 !== (s.writers === 0)) {
8766
- try {
8767
- bridgeOf(stream.node).hold?.(liveNodePath(stream.node), s.writers > 0);
8768
- } catch {
8769
- }
8770
- }
8771
- };
8942
+ const held2 = (stream, change) => heldStream(h, stream, change);
8772
8943
  const opened2 = (node, on, want = 0) => {
8773
8944
  const s = node.live;
8774
8945
  try {
8946
+ h.track(node, on);
8775
8947
  const handle = holdLive(bridgeOf(node), node, on, want);
8776
8948
  s.handle = on ? handle : void 0;
8777
8949
  h.linked.opening(node, on);
@@ -8867,6 +9039,7 @@ function createStreamOps(h) {
8867
9039
  if (!Fs.isFile(node.mode)) return;
8868
9040
  const s = node.live;
8869
9041
  if (!dropOpen(s)) return;
9042
+ h.follow(node);
8870
9043
  if (s.openCount > 0) {
8871
9044
  held2(stream, -1);
8872
9045
  return;
@@ -8880,12 +9053,14 @@ function createStreamOps(h) {
8880
9053
  s.len = 0;
8881
9054
  s.loaded = false;
8882
9055
  held2(stream, -1);
9056
+ h.track(node, false);
8883
9057
  if (s.handle !== void 0) opened2(node, false);
8884
9058
  }
8885
9059
  },
8886
9060
  read(stream, buffer, offset, length, position) {
8887
9061
  const node = stream.node;
8888
9062
  if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(wasiErrno("EISDIR"));
9063
+ h.follow(node);
8889
9064
  const ranged = rangedOf(node);
8890
9065
  if (ranged) {
8891
9066
  const out2 = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, Math.max(0, length));
@@ -8903,6 +9078,7 @@ function createStreamOps(h) {
8903
9078
  const node = stream.node;
8904
9079
  if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(wasiErrno("EISDIR"));
8905
9080
  if (length <= 0) return 0;
9081
+ h.follow(node);
8906
9082
  const s = node.live;
8907
9083
  const end = position + length;
8908
9084
  if (s.maxFile !== void 0 && end > s.maxFile) throw new Fs.ErrnoError(wasiErrno("EFBIG"));
@@ -8934,6 +9110,7 @@ function createStreamOps(h) {
8934
9110
  return pos;
8935
9111
  },
8936
9112
  fsync(stream) {
9113
+ h.follow(stream.node);
8937
9114
  flushNode(stream.node);
8938
9115
  }
8939
9116
  };
@@ -8968,6 +9145,7 @@ function createLiveVfsPlugin(Fs) {
8968
9145
  flushDirty: () => h.flushDirty(),
8969
9146
  mount(mount) {
8970
9147
  const st = h.call(() => mount.opts.bridge.stat(mount.opts.root));
9148
+ h.watchRenames(mount.opts.bridge);
8971
9149
  if (!st.isDirectory) throw new Fs.ErrnoError(wasiErrno("ENOTDIR"));
8972
9150
  const root = h.makeNode(null, "/", st);
8973
9151
  root.mode = modeFromStat(st, mount.opts.bridge.owners === true);
@@ -17317,7 +17495,7 @@ function posixSignal(sig) {
17317
17495
  function nsToMs(ns) {
17318
17496
  return Math.ceil(Number(ns) / 1e6);
17319
17497
  }
17320
- var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON2, ECHO2, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, MAIN_HANDLE, WasixHost;
17498
+ var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON2, ECHO2, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, CWD_FD_LIBC, MAIN_HANDLE, WasixHost;
17321
17499
  var init_wasix_host = __esm({
17322
17500
  "src/process/wasi/wasix-host.ts"() {
17323
17501
  "use strict";
@@ -17342,6 +17520,7 @@ var init_wasix_host = __esm({
17342
17520
  FUTEX_SLICE_MS = 50;
17343
17521
  EINTR_LIBC = 22;
17344
17522
  STRICT_EPOLL_LIBC = 29;
17523
+ CWD_FD_LIBC = 41;
17345
17524
  MAIN_HANDLE = 2147483647;
17346
17525
  WasixHost = class _WasixHost {
17347
17526
  process;
@@ -17360,7 +17539,9 @@ var init_wasix_host = __esm({
17360
17539
  driver,
17361
17540
  () => (this.threads?.tid ?? MAIN_TID) !== MAIN_TID
17362
17541
  );
17363
- if (module) host.strictEpoll = (libcVersion(module) ?? 0) >= STRICT_EPOLL_LIBC;
17542
+ const libc = module ? libcVersion(module) ?? 0 : void 0;
17543
+ if (libc !== void 0) host.strictEpoll = libc >= STRICT_EPOLL_LIBC;
17544
+ if (libc !== void 0) host.cwdFd = libc >= CWD_FD_LIBC;
17364
17545
  if (module && !WebAssembly.Module.imports(module).some((i) => i.name === "fd_fdflags_set")) {
17365
17546
  host.fds.implicitCloexec = true;
17366
17547
  host.interruptWakes = (libcVersion(module) ?? 0) < EINTR_LIBC;
@@ -17500,6 +17681,7 @@ var init_wasix_host = __esm({
17500
17681
  mem.view().setUint32(out, host.o.parent?.() ?? host.o.ppid ?? 1, true);
17501
17682
  },
17502
17683
  getcwd: (buf, lenPtr) => {
17684
+ if (host.cwdFd && host.fds.held && !host.fds.held.alive()) return E.NOENT;
17503
17685
  const bytes = new TextEncoder().encode(host.cwd);
17504
17686
  const max = mem.view().getUint32(lenPtr, true);
17505
17687
  mem.view().setUint32(lenPtr, bytes.length, true);