@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.
@@ -561,7 +561,7 @@ function normal(path) {
561
561
  }
562
562
  return `/${parts.join("/")}`;
563
563
  }
564
- var GEN, RING, RING_SIZE, SLOT, SHARED_TTL_MS, DIRTY, FOREIGN, CHANGES_BYTES, ChangeView;
564
+ var GEN, RING, RING_SIZE, SLOT, SHARED_TTL_MS, RENAME_WAIT_MS, DIRTY, FOREIGN, RENAMES, CHANGES_BYTES, ChangeView;
565
565
  var init_changes = __esm({
566
566
  "src/fs/changes.ts"() {
567
567
  "use strict";
@@ -570,9 +570,11 @@ var init_changes = __esm({
570
570
  RING_SIZE = 4096;
571
571
  SLOT = 2;
572
572
  SHARED_TTL_MS = 100;
573
+ RENAME_WAIT_MS = 100;
573
574
  DIRTY = RING + RING_SIZE * SLOT;
574
575
  FOREIGN = DIRTY + 1;
575
- CHANGES_BYTES = (FOREIGN + 1) * 4;
576
+ RENAMES = FOREIGN + 1;
577
+ CHANGES_BYTES = (RENAMES + 1) * 4;
576
578
  ChangeView = class {
577
579
  view;
578
580
  constructor(sab) {
@@ -587,6 +589,13 @@ var init_changes = __esm({
587
589
  foreign() {
588
590
  return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
589
591
  }
592
+ renames() {
593
+ return this.view.length > RENAMES ? Atomics.load(this.view, RENAMES) : 0;
594
+ }
595
+ awaitRename(seen, ms) {
596
+ if (this.view.length > RENAMES) Atomics.wait(this.view, RENAMES, seen, ms);
597
+ return this.renames();
598
+ }
590
599
  changedSince(seen, path) {
591
600
  const now = Atomics.load(this.view, GEN);
592
601
  const distance = now - seen >>> 0;
@@ -1163,7 +1172,8 @@ var init_sync_fs_wire = __esm({
1163
1172
  "truncate",
1164
1173
  "chown",
1165
1174
  "lchown",
1166
- "access"
1175
+ "access",
1176
+ "renames"
1167
1177
  ];
1168
1178
  HOLD_READ = 4;
1169
1179
  HOLD_WRITE = 8;
@@ -1180,7 +1190,8 @@ var init_sync_fs_wire = __esm({
1180
1190
  "readlink",
1181
1191
  "statfs",
1182
1192
  "kept",
1183
- "access"
1193
+ "access",
1194
+ "renames"
1184
1195
  ]);
1185
1196
  }
1186
1197
  });
@@ -1372,7 +1383,9 @@ function createSyncFsSabBridge(transport, opts = {}) {
1372
1383
  run({ op: "rm", path }, path);
1373
1384
  },
1374
1385
  rename: (from, to) => {
1375
- run({ op: "rename", path: from, arg2: to }, from);
1386
+ const r = run({ op: "rename", path: from, arg2: to }, from);
1387
+ const seq = r.ok && r.kind === "json" ? r.json.seq : void 0;
1388
+ return typeof seq === "number" ? seq : void 0;
1376
1389
  },
1377
1390
  link: (from, to, follow3) => {
1378
1391
  run({ op: "link", path: from, arg2: to, ...follow3 ? { mode: 1 } : {} }, from);
@@ -1453,7 +1466,11 @@ function createSyncFsSabBridge(transport, opts = {}) {
1453
1466
  run({ op: "hold", path, mode, ...handle !== void 0 ? { handle } : {} }, path);
1454
1467
  return void 0;
1455
1468
  },
1456
- statfs: (path = "/") => parseSyncFsUsage(json2({ op: "statfs", path }, path))
1469
+ statfs: (path = "/") => parseSyncFsUsage(json2({ op: "statfs", path }, path)),
1470
+ renames: (since, held2) => json2(
1471
+ { op: "renames", path: "/", offset: since, arg2: JSON.stringify(held2) },
1472
+ "/"
1473
+ )
1457
1474
  };
1458
1475
  }
1459
1476
  var UNCOUNTED_OPS, calls, looks, SPIN_MS, SPIN_STRIDE, SPIN_STRIDES, SPIN_CORES, spinning, SPIN_CAP_MS;
@@ -1650,12 +1667,130 @@ function freshState(stat) {
1650
1667
  const base = { len: 0, loaded: false, dirty: false, openCount: 0 };
1651
1668
  return stat ? { stat, statAt: syncCallCount(), filledAt: performance.now(), seenAt: syncEpoch(), ...base } : base;
1652
1669
  }
1670
+ function inCache(Fs, node) {
1671
+ const table = Fs.nameTable;
1672
+ const parent = node.parent;
1673
+ const hash = Fs.hashName?.(parent.id ?? 0, node.name);
1674
+ if (!table || hash === void 0) return true;
1675
+ let at = table[hash];
1676
+ while (at) {
1677
+ if (at === node) return true;
1678
+ at = at.name_next;
1679
+ }
1680
+ return false;
1681
+ }
1682
+ function heldUnder(held2, from) {
1683
+ let moving = held2;
1684
+ while (moving && moving !== moving.mount.root && liveNodePath(moving) !== from) {
1685
+ moving = moving.parent;
1686
+ }
1687
+ return moving && moving !== moving.mount.root && liveNodePath(moving) === from ? moving : void 0;
1688
+ }
1689
+ function relinked(Fs, moving, to) {
1690
+ const slash = to.lastIndexOf("/");
1691
+ let dir;
1692
+ try {
1693
+ dir = Fs.lookupPath?.(slash <= 0 ? "/" : to.slice(0, slash)).node;
1694
+ } catch {
1695
+ }
1696
+ if (!dir || dir.mount !== moving.mount) return;
1697
+ const name2 = to.slice(slash + 1);
1698
+ try {
1699
+ const existing = Fs.lookupNode?.(dir, name2);
1700
+ if (existing && existing !== moving) Fs.hashRemoveNode?.(existing);
1701
+ } catch {
1702
+ }
1703
+ moving.parent.live.listed = void 0;
1704
+ dir.live.listed = void 0;
1705
+ Fs.hashRemoveNode?.(moving);
1706
+ moving.name = name2;
1707
+ moving.parent = dir;
1708
+ Fs.hashAddNode?.(moving);
1709
+ moving.live.stat = void 0;
1710
+ }
1711
+ function renameFollower(Fs, bridgeOf, call2) {
1712
+ const open = /* @__PURE__ */ new Set();
1713
+ const seen = /* @__PURE__ */ new Map();
1714
+ const follow3 = (node, missing2 = false) => {
1715
+ const bridge = bridgeOf(node);
1716
+ const view = bridge.changes;
1717
+ const since = seen.get(bridge);
1718
+ let now = view?.renames() ?? 0;
1719
+ if (missing2 && view && now === since) now = view.awaitRename(now, RENAME_WAIT_MS);
1720
+ const ask = bridge.renames?.bind(bridge);
1721
+ if (since === void 0 || now === since || !ask) return false;
1722
+ const held2 = [...open].filter((n) => !n.live.orphan && bridgeOf(n) === bridge);
1723
+ if (held2.length === 0) {
1724
+ seen.set(bridge, now);
1725
+ return false;
1726
+ }
1727
+ const reply = call2(
1728
+ () => ask(
1729
+ since,
1730
+ held2.map((n) => liveNodePath(n))
1731
+ )
1732
+ );
1733
+ seen.set(bridge, reply.now);
1734
+ for (const [from, to] of reply.renames) {
1735
+ for (const n of held2) {
1736
+ const moving = heldUnder(n, from);
1737
+ if (moving && inCache(Fs, moving)) relinked(Fs, moving, to);
1738
+ }
1739
+ }
1740
+ return reply.renames.length > 0;
1741
+ };
1742
+ return {
1743
+ open,
1744
+ follow: follow3,
1745
+ track(node, on) {
1746
+ if (!on) {
1747
+ open.delete(node);
1748
+ return;
1749
+ }
1750
+ follow3(node);
1751
+ open.add(node);
1752
+ },
1753
+ watchRenames(bridge) {
1754
+ if (!seen.has(bridge)) seen.set(bridge, bridge.changes?.renames() ?? 0);
1755
+ },
1756
+ ownRename(bridge, seq) {
1757
+ const since = seen.get(bridge);
1758
+ if (seq !== void 0 && since !== void 0 && seq === (since + 1 | 0))
1759
+ seen.set(bridge, seq);
1760
+ }
1761
+ };
1762
+ }
1763
+ function followingOnce(write2, follow3) {
1764
+ try {
1765
+ write2();
1766
+ } catch (err) {
1767
+ if (err.errno !== wasiErrno("ENOENT") || !follow3()) throw err;
1768
+ write2();
1769
+ }
1770
+ }
1771
+ function renameThrough(h, node, from, to) {
1772
+ const seq = h.call(() => h.bridgeOf(node).rename(from, to));
1773
+ h.ownRename(h.bridgeOf(node), typeof seq === "number" ? seq : void 0);
1774
+ }
1775
+ function heldStream(h, stream, change) {
1776
+ const s = stream.node.live;
1777
+ if ((stream.flags & 3) === 0 || s.orphan) return;
1778
+ const before = s.writers ?? 0;
1779
+ s.writers = Math.max(0, before + change);
1780
+ if (before === 0 !== (s.writers === 0)) {
1781
+ try {
1782
+ h.bridgeOf(stream.node).hold?.(liveNodePath(stream.node), s.writers > 0);
1783
+ } catch {
1784
+ }
1785
+ }
1786
+ }
1653
1787
  function createHelpers(Fs, ops) {
1654
1788
  const bridgeOf = (node) => node.mount.opts.bridge;
1655
1789
  const fileIo = (node) => pinnedIo(bridgeOf(node), node.live.handle);
1656
1790
  const dirty = /* @__PURE__ */ new Set();
1657
1791
  const handled = /* @__PURE__ */ new Set();
1658
1792
  const linked = linkedStates(bridgeOf);
1793
+ const renames = renameFollower(Fs, bridgeOf, (fn) => call2(fn));
1659
1794
  function markDirty(node) {
1660
1795
  node.live.dirty = true;
1661
1796
  dirty.add(node);
@@ -1748,11 +1883,9 @@ function createHelpers(Fs, ops) {
1748
1883
  function flushNode(node) {
1749
1884
  const s = node.live;
1750
1885
  if (!s.dirty || stale(s) || !(s.data || s.ranged)) return;
1751
- if (s.ranged) call2(() => s.ranged?.flush());
1752
- else {
1753
- const bytes = s.data.slice(0, s.len);
1754
- call2(() => fileIo(node).writeFile(liveNodePath(linked.holder(node)), bytes, true));
1755
- }
1886
+ const whole = () => s.data.slice(0, s.len);
1887
+ const write2 = () => s.ranged ? call2(() => s.ranged?.flush()) : call2(() => fileIo(node).writeFile(liveNodePath(linked.holder(node)), whole(), true));
1888
+ followingOnce(write2, () => renames.follow(node, true));
1756
1889
  s.dirty = false;
1757
1890
  s.stat = void 0;
1758
1891
  }
@@ -1800,6 +1933,7 @@ function createHelpers(Fs, ops) {
1800
1933
  bridgeOf,
1801
1934
  handled,
1802
1935
  linked,
1936
+ ...renames,
1803
1937
  call: call2,
1804
1938
  metadataCall,
1805
1939
  makeNode,
@@ -1959,7 +2093,7 @@ function createNodeOps(h) {
1959
2093
  const from = liveNodePath(oldNode);
1960
2094
  const to = childPath(newDir, newName);
1961
2095
  flushNode(oldNode);
1962
- call2(() => bridgeOf(oldNode).rename(from, to));
2096
+ renameThrough(h, oldNode, from, to);
1963
2097
  try {
1964
2098
  const existing = Fs.lookupNode?.(newDir, newName);
1965
2099
  if (existing && existing !== oldNode) Fs.hashRemoveNode?.(existing);
@@ -2054,21 +2188,11 @@ function dropOpen(s) {
2054
2188
  }
2055
2189
  function createStreamOps(h) {
2056
2190
  const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf, rangedOf } = h;
2057
- const held2 = (stream, change) => {
2058
- const s = stream.node.live;
2059
- if ((stream.flags & 3) === 0 || s.orphan) return;
2060
- const before = s.writers ?? 0;
2061
- s.writers = Math.max(0, before + change);
2062
- if (before === 0 !== (s.writers === 0)) {
2063
- try {
2064
- bridgeOf(stream.node).hold?.(liveNodePath(stream.node), s.writers > 0);
2065
- } catch {
2066
- }
2067
- }
2068
- };
2191
+ const held2 = (stream, change) => heldStream(h, stream, change);
2069
2192
  const opened2 = (node, on, want = 0) => {
2070
2193
  const s = node.live;
2071
2194
  try {
2195
+ h.track(node, on);
2072
2196
  const handle = holdLive(bridgeOf(node), node, on, want);
2073
2197
  s.handle = on ? handle : void 0;
2074
2198
  h.linked.opening(node, on);
@@ -2164,6 +2288,7 @@ function createStreamOps(h) {
2164
2288
  if (!Fs.isFile(node.mode)) return;
2165
2289
  const s = node.live;
2166
2290
  if (!dropOpen(s)) return;
2291
+ h.follow(node);
2167
2292
  if (s.openCount > 0) {
2168
2293
  held2(stream, -1);
2169
2294
  return;
@@ -2177,12 +2302,14 @@ function createStreamOps(h) {
2177
2302
  s.len = 0;
2178
2303
  s.loaded = false;
2179
2304
  held2(stream, -1);
2305
+ h.track(node, false);
2180
2306
  if (s.handle !== void 0) opened2(node, false);
2181
2307
  }
2182
2308
  },
2183
2309
  read(stream, buffer, offset, length, position) {
2184
2310
  const node = stream.node;
2185
2311
  if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(wasiErrno("EISDIR"));
2312
+ h.follow(node);
2186
2313
  const ranged = rangedOf(node);
2187
2314
  if (ranged) {
2188
2315
  const out2 = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, Math.max(0, length));
@@ -2200,6 +2327,7 @@ function createStreamOps(h) {
2200
2327
  const node = stream.node;
2201
2328
  if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(wasiErrno("EISDIR"));
2202
2329
  if (length <= 0) return 0;
2330
+ h.follow(node);
2203
2331
  const s = node.live;
2204
2332
  const end = position + length;
2205
2333
  if (s.maxFile !== void 0 && end > s.maxFile) throw new Fs.ErrnoError(wasiErrno("EFBIG"));
@@ -2231,6 +2359,7 @@ function createStreamOps(h) {
2231
2359
  return pos;
2232
2360
  },
2233
2361
  fsync(stream) {
2362
+ h.follow(stream.node);
2234
2363
  flushNode(stream.node);
2235
2364
  }
2236
2365
  };
@@ -2265,6 +2394,7 @@ function createLiveVfsPlugin(Fs) {
2265
2394
  flushDirty: () => h.flushDirty(),
2266
2395
  mount(mount) {
2267
2396
  const st = h.call(() => mount.opts.bridge.stat(mount.opts.root));
2397
+ h.watchRenames(mount.opts.bridge);
2268
2398
  if (!st.isDirectory) throw new Fs.ErrnoError(wasiErrno("ENOTDIR"));
2269
2399
  const root = h.makeNode(null, "/", st);
2270
2400
  root.mode = modeFromStat(st, mount.opts.bridge.owners === true);
@@ -2783,7 +2913,7 @@ var KERNEL_VERSION, OS_RELEASE;
2783
2913
  var init_version = __esm({
2784
2914
  "src/version.ts"() {
2785
2915
  "use strict";
2786
- KERNEL_VERSION = true ? "1.143.4" : "0.0.0-dev";
2916
+ KERNEL_VERSION = true ? "1.143.6" : "0.0.0-dev";
2787
2917
  OS_RELEASE = "6.0.0-slicc";
2788
2918
  }
2789
2919
  });
@@ -7059,6 +7189,7 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
7059
7189
  const entry = (p) => [p, p.slice(0, p.lastIndexOf("/")) || "/"];
7060
7190
  return {
7061
7191
  ...bridge.changes ? { changes: bridge.changes } : {},
7192
+ ...bridge.renames ? { renames: bridge.renames.bind(bridge) } : {},
7062
7193
  readFile: (p) => bridge.readFile(p),
7063
7194
  readdir: (p) => bridge.readdir(p),
7064
7195
  readdirStat: (p) => {
@@ -7175,6 +7306,7 @@ var init_wasi_files = __esm({
7175
7306
  seen = 0;
7176
7307
  maxFile;
7177
7308
  handle;
7309
+ moved;
7178
7310
  constructor(fs, path, empty, maxFile, size, version, watch) {
7179
7311
  this.fs = fs;
7180
7312
  this.where = path;
@@ -7183,7 +7315,11 @@ var init_wasi_files = __esm({
7183
7315
  this.watch = watch;
7184
7316
  this.seen = watch?.seen ?? watch?.view.now() ?? 0;
7185
7317
  if (size !== void 0 && pread && pwrite && truncate) {
7186
- const io = { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };
7318
+ const io = {
7319
+ pread: (_, ...rest2) => this.retried(() => pread.call(fs, this.where, ...rest2)),
7320
+ pwrite: (_, ...rest2) => this.retried(() => pwrite.call(fs, this.where, ...rest2)),
7321
+ truncate: (_, size2) => this.retried(() => truncate.call(fs, this.where, size2))
7322
+ };
7187
7323
  this.ranged = new RangedFile(io, path, size, version, watch);
7188
7324
  if (empty) this.truncate(0);
7189
7325
  } else if (empty) {
@@ -7195,6 +7331,14 @@ var init_wasi_files = __esm({
7195
7331
  get path() {
7196
7332
  return this.where;
7197
7333
  }
7334
+ retried(op) {
7335
+ try {
7336
+ return op();
7337
+ } catch (err) {
7338
+ if (err.code !== "ENOENT" || !this.moved?.(true)) throw err;
7339
+ return op();
7340
+ }
7341
+ }
7198
7342
  set path(path) {
7199
7343
  this.where = path;
7200
7344
  if (this.ranged) this.ranged.path = path;
@@ -7218,7 +7362,7 @@ var init_wasi_files = __esm({
7218
7362
  }
7219
7363
  if (!this.data) {
7220
7364
  this.seen = view?.now() ?? 0;
7221
- this.data = this.fs.readFile(this.path);
7365
+ this.data = this.retried(() => this.fs.readFile(this.path));
7222
7366
  this.length = this.data.length;
7223
7367
  }
7224
7368
  return this.data;
@@ -7259,8 +7403,9 @@ var init_wasi_files = __esm({
7259
7403
  append(bytes) {
7260
7404
  const { append } = this.fs;
7261
7405
  if (!append || this.orphaned) return void 0;
7406
+ this.moved?.(false);
7262
7407
  this.flush();
7263
- const end = append.call(this.fs, this.path, bytes);
7408
+ const end = this.retried(() => append.call(this.fs, this.path, bytes));
7264
7409
  if (!this.ranged) {
7265
7410
  this.data = void 0;
7266
7411
  this.length = 0;
@@ -7308,11 +7453,17 @@ var init_wasi_files = __esm({
7308
7453
  }
7309
7454
  flush() {
7310
7455
  if (this.orphaned || !this.dirty) return;
7456
+ this.moved?.(false);
7311
7457
  if (this.ranged) this.ranged.flush();
7312
7458
  else if (!this.data) return;
7313
- else if (this.whole || !this.fs.pwrite)
7314
- this.fs.writeFile(this.path, this.data.slice(0, this.length), true);
7315
- else this.fs.pwrite(this.path, this.from, this.data.slice(this.from, this.to), true);
7459
+ else if (this.whole || !this.fs.pwrite) {
7460
+ const whole = this.data.slice(0, this.length);
7461
+ this.retried(() => this.fs.writeFile(this.path, whole, true));
7462
+ } else {
7463
+ const { pwrite } = this.fs;
7464
+ const run = this.data.slice(this.from, this.to);
7465
+ this.retried(() => pwrite.call(this.fs, this.path, this.from, run, true));
7466
+ }
7316
7467
  this.dirty = false;
7317
7468
  this.whole = false;
7318
7469
  this.from = Infinity;
@@ -8700,6 +8851,7 @@ var SYNTHETIC_DIRS2, O_NONBLOCK2, O_WRONLY5, O_RDWR5, O_APPEND3, SEALED_PATH2, C
8700
8851
  var init_wasi_fds = __esm({
8701
8852
  "src/process/wasi/wasi-fds.ts"() {
8702
8853
  "use strict";
8854
+ init_changes();
8703
8855
  init_ranged();
8704
8856
  init_fd_table();
8705
8857
  init_sync_fs_wire();
@@ -8720,9 +8872,29 @@ var init_wasi_fds = __esm({
8720
8872
  ids = /* @__PURE__ */ new Map();
8721
8873
  kernel;
8722
8874
  fs;
8875
+ renamesSeen;
8723
8876
  constructor(kernel, fs) {
8724
8877
  this.kernel = kernel;
8725
8878
  this.fs = fs;
8879
+ this.renamesSeen = fs.changes?.renames() ?? 0;
8880
+ }
8881
+ ownRename(seq) {
8882
+ if (seq !== void 0 && seq === (this.renamesSeen + 1 | 0)) this.renamesSeen = seq;
8883
+ }
8884
+ followRenames(missing2 = false) {
8885
+ const view = this.fs.changes;
8886
+ let now = view?.renames() ?? 0;
8887
+ if (missing2 && view && now === this.renamesSeen) now = view.awaitRename(now, RENAME_WAIT_MS);
8888
+ if (now === this.renamesSeen || !this.fs.renames) return false;
8889
+ const held2 = [...this.buffers].filter(([, b]) => !b.isOrphan()).map(([p]) => p);
8890
+ if (held2.length === 0) {
8891
+ this.renamesSeen = now;
8892
+ return false;
8893
+ }
8894
+ const { now: seen, renames } = this.fs.renames(this.renamesSeen, held2);
8895
+ this.renamesSeen = seen;
8896
+ for (const [from, to] of renames) this.renamed(from, to, void 0, true);
8897
+ return renames.length > 0;
8726
8898
  }
8727
8899
  setup(cwd, inherited, root = false) {
8728
8900
  for (const fd of [0, 1, 2]) this.table.set(fd, this.stdioEntry(fd));
@@ -8922,6 +9094,7 @@ var init_wasi_fds = __esm({
8922
9094
  get(fd) {
8923
9095
  const e = this.find(fd);
8924
9096
  if (!e) throw new WasiError("EBADF");
9097
+ if (e.type === "file") this.followRenames();
8925
9098
  return e;
8926
9099
  }
8927
9100
  preopen(fd) {
@@ -9242,9 +9415,9 @@ var init_wasi_fds = __esm({
9242
9415
  buffer.orphan();
9243
9416
  this.forget(buffer);
9244
9417
  }
9245
- renamed(from, to, replacedLinked) {
9418
+ renamed(from, to, replacedLinked, foreign = false) {
9246
9419
  if (from === to) return;
9247
- if (this.shared) this.kernel.call({ op: "fd-path-renamed", from, to });
9420
+ if (this.shared && !foreign) this.kernel.call({ op: "fd-path-renamed", from, to });
9248
9421
  for (const e of this.table.values()) {
9249
9422
  if (e.type === "kernel" && e.path !== void 0 && within(e.path, from)) {
9250
9423
  e.path = to + e.path.slice(from.length);
@@ -9252,6 +9425,7 @@ var init_wasi_fds = __esm({
9252
9425
  }
9253
9426
  const moved = [];
9254
9427
  for (const [p, buffer] of this.buffers) {
9428
+ if (foreign && buffer.isOrphan()) continue;
9255
9429
  if (within(p, from)) moved.push([p, buffer]);
9256
9430
  else if (within(p, to)) {
9257
9431
  this.detach(buffer, replacedLinked);
@@ -9393,6 +9567,7 @@ var init_wasi_fds = __esm({
9393
9567
  }
9394
9568
  file(path, existing, oflags, rights, fdflags, mode, created = false) {
9395
9569
  const { readable: readable3, writable: writable2 } = openAccess(existing, oflags, rights);
9570
+ this.followRenames();
9396
9571
  let buffer = created ? void 0 : this.buffers.get(path);
9397
9572
  if (buffer?.handle !== void 0 && this.fs.kept?.(buffer.handle)) {
9398
9573
  this.buffers.delete(path);
@@ -9440,6 +9615,7 @@ var init_wasi_fds = __esm({
9440
9615
  st
9441
9616
  );
9442
9617
  const buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version, watch);
9618
+ buffer.moved = (missing2) => this.followRenames(missing2);
9443
9619
  buffer.handle = handle;
9444
9620
  this.buffers.set(path, buffer);
9445
9621
  const id = this.identity(st);
@@ -10566,6 +10742,7 @@ var init_wasi_host = __esm({
10566
10742
  startCwd;
10567
10743
  interruptWakes = false;
10568
10744
  strictEpoll = false;
10745
+ cwdFd = false;
10569
10746
  entered = false;
10570
10747
  enteredSignals = 0;
10571
10748
  raisedOnEntry;
@@ -11196,8 +11373,9 @@ var init_wasi_host = __esm({
11196
11373
  const to = at(fd2, p2, l2);
11197
11374
  fds.flushPath(from);
11198
11375
  const replaced = fds.holdsUnder(to) ? linkedElsewhere(o.fs, to) : void 0;
11199
- o.fs.rename(from, to);
11376
+ const seq = o.fs.rename(from, to);
11200
11377
  fds.renamed(from, to, replaced);
11378
+ fds.ownRename(typeof seq === "number" ? seq : void 0);
11201
11379
  },
11202
11380
  path_symlink: (tp, tl, dirfd, p, l) => {
11203
11381
  const path = at(dirfd, p, l);
@@ -14164,7 +14342,7 @@ function posixSignal(sig) {
14164
14342
  function nsToMs(ns) {
14165
14343
  return Math.ceil(Number(ns) / 1e6);
14166
14344
  }
14167
- var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON, ECHO, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, MAIN_HANDLE, WasixHost;
14345
+ var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON, ECHO, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, CWD_FD_LIBC, MAIN_HANDLE, WasixHost;
14168
14346
  var init_wasix_host = __esm({
14169
14347
  "src/process/wasi/wasix-host.ts"() {
14170
14348
  "use strict";
@@ -14189,6 +14367,7 @@ var init_wasix_host = __esm({
14189
14367
  FUTEX_SLICE_MS = 50;
14190
14368
  EINTR_LIBC = 22;
14191
14369
  STRICT_EPOLL_LIBC = 29;
14370
+ CWD_FD_LIBC = 41;
14192
14371
  MAIN_HANDLE = 2147483647;
14193
14372
  WasixHost = class _WasixHost {
14194
14373
  process;
@@ -14207,7 +14386,9 @@ var init_wasix_host = __esm({
14207
14386
  driver,
14208
14387
  () => (this.threads?.tid ?? MAIN_TID) !== MAIN_TID
14209
14388
  );
14210
- if (module) host.strictEpoll = (libcVersion(module) ?? 0) >= STRICT_EPOLL_LIBC;
14389
+ const libc = module ? libcVersion(module) ?? 0 : void 0;
14390
+ if (libc !== void 0) host.strictEpoll = libc >= STRICT_EPOLL_LIBC;
14391
+ if (libc !== void 0) host.cwdFd = libc >= CWD_FD_LIBC;
14211
14392
  if (module && !WebAssembly.Module.imports(module).some((i) => i.name === "fd_fdflags_set")) {
14212
14393
  host.fds.implicitCloexec = true;
14213
14394
  host.interruptWakes = (libcVersion(module) ?? 0) < EINTR_LIBC;
@@ -14347,6 +14528,7 @@ var init_wasix_host = __esm({
14347
14528
  mem.view().setUint32(out, host.o.parent?.() ?? host.o.ppid ?? 1, true);
14348
14529
  },
14349
14530
  getcwd: (buf, lenPtr) => {
14531
+ if (host.cwdFd && host.fds.held && !host.fds.held.alive()) return E.NOENT;
14350
14532
  const bytes = new TextEncoder().encode(host.cwd);
14351
14533
  const max = mem.view().getUint32(lenPtr, true);
14352
14534
  mem.view().setUint32(lenPtr, bytes.length, true);