@ai-ecoverse/slicc-kernel 1.62.4 → 1.63.0

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.
@@ -633,9 +633,10 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
633
633
  rmdir: (p) => mutating(() => bridge.rmdir(p)),
634
634
  symlink: (target, link) => mutating(() => bridge.symlink(target, link), ...entry(link)),
635
635
  chmod: (p, mode) => rewriting(p, () => bridge.chmod(p, mode)),
636
- utimes: (p, a, m) => rewriting(p, () => bridge.utimes(p, a, m)),
637
- lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m), p),
636
+ utimes: (p, a, m, now2) => rewriting(p, () => bridge.utimes(p, a, m, now2)),
637
+ lutimes: (p, a, m, now2) => mutating(() => bridge.lutimes(p, a, m, now2), p),
638
638
  ...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
639
+ ...bridge.access ? { access: bridge.access.bind(bridge) } : {},
639
640
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
640
641
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
641
642
  ...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle, rewriting) } : {},
@@ -1151,6 +1152,82 @@ var init_cred = __esm({
1151
1152
  }
1152
1153
  });
1153
1154
 
1155
+ // src/realm/sync-fs-wire.ts
1156
+ function parseSyncFsUsage(json) {
1157
+ const u = json;
1158
+ if (!u || typeof u.quota !== "number" || typeof u.usage !== "number") return null;
1159
+ return { quota: u.quota, usage: u.usage };
1160
+ }
1161
+ function syncError(code2, label) {
1162
+ return Object.assign(new Error(`${code2}: ${label}`), { code: code2 });
1163
+ }
1164
+ function parseSyncFsStat(json) {
1165
+ const s = json;
1166
+ if (!s || typeof s.isFile !== "boolean" || typeof s.isDirectory !== "boolean" || typeof s.size !== "number") {
1167
+ return null;
1168
+ }
1169
+ return {
1170
+ isFile: s.isFile,
1171
+ isDirectory: s.isDirectory,
1172
+ isSymbolicLink: s.isSymbolicLink,
1173
+ size: s.size,
1174
+ ...typeof s.mode === "number" ? { mode: s.mode } : {},
1175
+ ...typeof s.mtimeMs === "number" ? { mtimeMs: s.mtimeMs } : {},
1176
+ ...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
1177
+ ...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
1178
+ ...typeof s.ino === "number" ? { ino: s.ino } : {},
1179
+ ...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
1180
+ ...typeof s.dev === "number" ? { dev: s.dev } : {},
1181
+ ...s.readonly === true ? { readonly: true } : {},
1182
+ ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
1183
+ ...s.ranged === true ? { ranged: true } : {},
1184
+ ...s.linkable === true ? { linkable: true } : {},
1185
+ ...typeof s.version === "string" ? { version: s.version } : {},
1186
+ ...typeof s.uid === "number" ? { uid: s.uid } : {},
1187
+ ...typeof s.gid === "number" ? { gid: s.gid } : {}
1188
+ };
1189
+ }
1190
+ var SYNC_FS_OPS, HOLD_READ, HOLD_WRITE, HOLD_CREATED, SYNC_FS_REQUEST_TIMEOUT_MS;
1191
+ var init_sync_fs_wire = __esm({
1192
+ "src/realm/sync-fs-wire.ts"() {
1193
+ "use strict";
1194
+ SYNC_FS_OPS = [
1195
+ "read",
1196
+ "write",
1197
+ "exists",
1198
+ "stat",
1199
+ "lstat",
1200
+ "readdir",
1201
+ "readdir-stat",
1202
+ "mkdir",
1203
+ "rm",
1204
+ "rename",
1205
+ "link",
1206
+ "unlink",
1207
+ "rmdir",
1208
+ "symlink",
1209
+ "readlink",
1210
+ "chmod",
1211
+ "utimes",
1212
+ "lutimes",
1213
+ "statfs",
1214
+ "hold",
1215
+ "create",
1216
+ "kept",
1217
+ "pread",
1218
+ "pwrite",
1219
+ "truncate",
1220
+ "chown",
1221
+ "lchown",
1222
+ "access"
1223
+ ];
1224
+ HOLD_READ = 4;
1225
+ HOLD_WRITE = 8;
1226
+ HOLD_CREATED = 16;
1227
+ SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
1228
+ }
1229
+ });
1230
+
1154
1231
  // src/process/wasi/wasi-fds.ts
1155
1232
  function stdioAlias(path) {
1156
1233
  const m = /^\/dev\/(?:(stdin)|(stdout)|(stderr)|fd\/(\d+))$/.exec(path);
@@ -1197,6 +1274,11 @@ function entryOf(info) {
1197
1274
  append: ((info.flags ?? 0) & O_APPEND) !== 0
1198
1275
  };
1199
1276
  }
1277
+ function wantOf(oflags, rights) {
1278
+ const write2 = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
1279
+ const read2 = (rights & RIGHTS.FD_READ) !== 0n || !write2;
1280
+ return (read2 ? 4 : 0) | (write2 ? 2 : 0);
1281
+ }
1200
1282
  function openAccess(existing, oflags, rights) {
1201
1283
  const readonly = existing?.readonly === true;
1202
1284
  const mutating = readonly ? OFLAGS.TRUNC : OFLAGS.CREAT | OFLAGS.TRUNC;
@@ -1225,6 +1307,7 @@ var SYNTHETIC_DIRS, O_NONBLOCK, O_WRONLY, O_RDWR, O_APPEND, DEVICES, WasiFds, GE
1225
1307
  var init_wasi_fds = __esm({
1226
1308
  "src/process/wasi/wasi-fds.ts"() {
1227
1309
  "use strict";
1310
+ init_sync_fs_wire();
1228
1311
  init_wasi_abi();
1229
1312
  init_wasi_files();
1230
1313
  SYNTHETIC_DIRS = ["usr", "bin"];
@@ -1765,32 +1848,42 @@ var init_wasi_fds = __esm({
1765
1848
  buffer = void 0;
1766
1849
  }
1767
1850
  buffer ??= this.sharing(path, existing);
1851
+ const want = wantOf(oflags, rights);
1768
1852
  if (buffer) {
1853
+ if (this.fs.owners) this.fs.access?.(path, want, "open");
1769
1854
  if (oflags & OFLAGS.TRUNC) buffer.truncate(0);
1770
1855
  } else {
1771
- const made = !existing && this.createNew(path, oflags);
1772
- const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
1773
- if (existing?.ranged) this.fs.invalidate?.();
1774
- const st = existing?.ranged || !existing ? this.fs.stat(path) : existing;
1775
- const ranged = st.ranged ? st.size : void 0;
1776
- const handle = this.fs.hold?.(path, true, true);
1777
- const io = handle !== void 0 && this.fs.pinned ? this.fs.pinned(handle) : this.fs;
1778
- buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
1779
- buffer.handle = handle;
1780
- this.buffers.set(path, buffer);
1781
- const id = this.identity(st);
1782
- if (id !== void 0) this.know(buffer, id);
1856
+ buffer = this.freshBuffer(path, existing, oflags, want);
1783
1857
  }
1784
1858
  buffer.opens++;
1785
1859
  return new LocalFile(buffer, readable2, writable2, (fdflags & FDFLAGS.APPEND) !== 0);
1786
1860
  }
1861
+ freshBuffer(path, existing, oflags, want) {
1862
+ const made = !existing && this.createNew(path, oflags);
1863
+ const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
1864
+ if (existing?.ranged) this.fs.invalidate?.();
1865
+ const st = existing?.ranged || !existing ? this.fs.stat(path) : existing;
1866
+ const ranged = st.ranged ? st.size : void 0;
1867
+ const asked = (want & 4 ? HOLD_READ : 0) | (want & 2 ? HOLD_WRITE : 0) | (made ? HOLD_CREATED : 0);
1868
+ const handle = this.fs.hold?.(path, true, true, void 0, this.fs.owners ? asked : 0);
1869
+ const io = handle !== void 0 && this.fs.pinned ? this.fs.pinned(handle) : this.fs;
1870
+ const buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
1871
+ buffer.handle = handle;
1872
+ this.buffers.set(path, buffer);
1873
+ const id = this.identity(st);
1874
+ if (id !== void 0) this.know(buffer, id);
1875
+ return buffer;
1876
+ }
1787
1877
  kernelFile(path, existing, oflags, rights, fdflags) {
1788
1878
  const { readable: readable2, writable: writable2 } = openAccess(existing, oflags, rights);
1789
1879
  const append = (fdflags & FDFLAGS.APPEND) !== 0;
1790
1880
  const flags = (writable2 ? readable2 ? O_RDWR : O_WRONLY : 0) | (append ? O_APPEND : 0);
1791
1881
  const made = !existing && this.createNew(path, oflags);
1792
1882
  const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
1793
- const fd = this.kernel.sys.openVfs(path, flags, 0, truncate ? { truncate } : {});
1883
+ const fd = this.kernel.sys.openVfs(path, flags, 0, {
1884
+ ...truncate ? { truncate } : {},
1885
+ ...made ? { created: true } : {}
1886
+ });
1794
1887
  const ino = writable2 ? this.openedIno(fd) ?? this.inoOf(path) : void 0;
1795
1888
  if (truncate) this.fs.touched?.(path, ino);
1796
1889
  this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append, path, ino });
@@ -2183,7 +2276,7 @@ function wrap(table) {
2183
2276
  }
2184
2277
  return out;
2185
2278
  }
2186
- var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
2279
+ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
2187
2280
  var init_wasi_host = __esm({
2188
2281
  "src/process/wasi/wasi-host.ts"() {
2189
2282
  "use strict";
@@ -2205,6 +2298,7 @@ var init_wasi_host = __esm({
2205
2298
  IDS = ["ruid", "euid", "suid", "rgid", "egid", "sgid"];
2206
2299
  NS_PER_MS = 1000000n;
2207
2300
  AT_SYMLINK_NOFOLLOW = 1;
2301
+ AT_EACCESS = 2;
2208
2302
  ROOT_IDS = Object.freeze({ uid: 0, gid: 0 });
2209
2303
  GONE = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
2210
2304
  S_IFIFO = 4096;
@@ -2332,6 +2426,18 @@ var init_wasi_host = __esm({
2332
2426
  const path = at(dirfd, p, l);
2333
2427
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW) === 0), out);
2334
2428
  },
2429
+ path_access: (dirfd, p, l, amode, flags) => {
2430
+ const path = at(dirfd, p, l);
2431
+ const nofollow = (flags & AT_SYMLINK_NOFOLLOW) !== 0;
2432
+ if (deviceOf(path)) {
2433
+ if (this.o.fs.owners && amode & 1) throw new WasiError("EACCES");
2434
+ return;
2435
+ }
2436
+ pathOwned(path, !nofollow);
2437
+ if (!this.o.fs.owners) return;
2438
+ const kind = flags & AT_EACCESS ? "eaccess" : "access";
2439
+ this.o.fs.access?.(path, amode & 7, kind, nofollow);
2440
+ },
2335
2441
  fd_chmod: (fd, mode) => void this.o.fs.chmod(pathOf(fd), mode & 4095),
2336
2442
  path_chmod: (dirfd, p, l, mode, flags) => void this.o.fs.chmod(target(at(dirfd, p, l), flags), mode & 4095),
2337
2443
  umask: (mask, out) => {
@@ -2856,6 +2962,8 @@ var init_wasi_host = __esm({
2856
2962
  return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
2857
2963
  }
2858
2964
  setTimes(path, atim, mtim, flags, follow2 = true) {
2965
+ const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
2966
+ if (this.o.fs.owners && (flags & asked) === 0) return;
2859
2967
  const now = Date.now();
2860
2968
  let current;
2861
2969
  const statOf = follow2 ? this.o.fs.stat.bind(this.o.fs) : this.o.fs.lstat.bind(this.o.fs);
@@ -2868,7 +2976,8 @@ var init_wasi_host = __esm({
2868
2976
  this.o.fs,
2869
2977
  path,
2870
2978
  pick(FSTFLAGS.ATIM, FSTFLAGS.ATIM_NOW, atim, "atimeMs"),
2871
- pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs")
2979
+ pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs"),
2980
+ (flags & (FSTFLAGS.ATIM | FSTFLAGS.MTIM)) === 0
2872
2981
  );
2873
2982
  }
2874
2983
  readdir(fd, buf, len, cookie, usedPtr) {
@@ -3562,78 +3671,6 @@ var init_signals = __esm({
3562
3671
  }
3563
3672
  });
3564
3673
 
3565
- // src/realm/sync-fs-wire.ts
3566
- function parseSyncFsUsage(json) {
3567
- const u = json;
3568
- if (!u || typeof u.quota !== "number" || typeof u.usage !== "number") return null;
3569
- return { quota: u.quota, usage: u.usage };
3570
- }
3571
- function syncError(code2, label) {
3572
- return Object.assign(new Error(`${code2}: ${label}`), { code: code2 });
3573
- }
3574
- function parseSyncFsStat(json) {
3575
- const s = json;
3576
- if (!s || typeof s.isFile !== "boolean" || typeof s.isDirectory !== "boolean" || typeof s.size !== "number") {
3577
- return null;
3578
- }
3579
- return {
3580
- isFile: s.isFile,
3581
- isDirectory: s.isDirectory,
3582
- isSymbolicLink: s.isSymbolicLink,
3583
- size: s.size,
3584
- ...typeof s.mode === "number" ? { mode: s.mode } : {},
3585
- ...typeof s.mtimeMs === "number" ? { mtimeMs: s.mtimeMs } : {},
3586
- ...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
3587
- ...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
3588
- ...typeof s.ino === "number" ? { ino: s.ino } : {},
3589
- ...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
3590
- ...typeof s.dev === "number" ? { dev: s.dev } : {},
3591
- ...s.readonly === true ? { readonly: true } : {},
3592
- ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
3593
- ...s.ranged === true ? { ranged: true } : {},
3594
- ...s.linkable === true ? { linkable: true } : {},
3595
- ...typeof s.version === "string" ? { version: s.version } : {},
3596
- ...typeof s.uid === "number" ? { uid: s.uid } : {},
3597
- ...typeof s.gid === "number" ? { gid: s.gid } : {}
3598
- };
3599
- }
3600
- var SYNC_FS_OPS, SYNC_FS_REQUEST_TIMEOUT_MS;
3601
- var init_sync_fs_wire = __esm({
3602
- "src/realm/sync-fs-wire.ts"() {
3603
- "use strict";
3604
- SYNC_FS_OPS = [
3605
- "read",
3606
- "write",
3607
- "exists",
3608
- "stat",
3609
- "lstat",
3610
- "readdir",
3611
- "readdir-stat",
3612
- "mkdir",
3613
- "rm",
3614
- "rename",
3615
- "link",
3616
- "unlink",
3617
- "rmdir",
3618
- "symlink",
3619
- "readlink",
3620
- "chmod",
3621
- "utimes",
3622
- "lutimes",
3623
- "statfs",
3624
- "hold",
3625
- "create",
3626
- "kept",
3627
- "pread",
3628
- "pwrite",
3629
- "truncate",
3630
- "chown",
3631
- "lchown"
3632
- ];
3633
- SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
3634
- }
3635
- });
3636
-
3637
3674
  // src/process/js/js-kernel.ts
3638
3675
  function untilAborted(work, signal) {
3639
3676
  if (!signal) return work;
@@ -4661,15 +4698,15 @@ function createSyncFsSabBridge(transport, opts = {}) {
4661
4698
  chmod: (path, mode) => {
4662
4699
  changing({ op: "chmod", path, mode }, path);
4663
4700
  },
4664
- utimes: (path, atimeMs, mtimeMs) => {
4665
- changing({ op: "utimes", path, atimeMs, mtimeMs }, path);
4701
+ utimes: (path, atimeMs, mtimeMs, now) => {
4702
+ changing({ op: "utimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
4666
4703
  },
4667
4704
  identify: () => {
4668
4705
  identity = { identity: true };
4669
4706
  },
4670
4707
  identified: () => last,
4671
- lutimes: (path, atimeMs, mtimeMs) => {
4672
- run({ op: "lutimes", path, atimeMs, mtimeMs }, path);
4708
+ lutimes: (path, atimeMs, mtimeMs, now) => {
4709
+ run({ op: "lutimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
4673
4710
  },
4674
4711
  create: (path, mode) => {
4675
4712
  run({ op: "create", path, ...mode !== void 0 ? { mode } : {} }, path);
@@ -4679,9 +4716,12 @@ function createSyncFsSabBridge(transport, opts = {}) {
4679
4716
  changing({ op: follow2 ? "chown" : "lchown", path, ...ids }, path);
4680
4717
  },
4681
4718
  ...opts.owners ? { owners: true } : {},
4682
- hold: (path, held, open, handle) => {
4719
+ access: (path, mode, kind = "access", nofollow) => {
4720
+ run({ op: "access", path, mode, arg2: kind, ...nofollow ? { nofollow } : {} }, path);
4721
+ },
4722
+ hold: (path, held, open, handle, want = 0) => {
4683
4723
  const mode = (held ? 1 : 0) | (open ? 2 : 0);
4684
- if (mode === 3) return json({ op: "hold", path, mode }, path);
4724
+ if (mode === 3) return json({ op: "hold", path, mode: mode | want }, path);
4685
4725
  run({ op: "hold", path, mode, ...handle !== void 0 ? { handle } : {} }, path);
4686
4726
  return void 0;
4687
4727
  },
@@ -5700,6 +5740,19 @@ function toMs(v) {
5700
5740
  if (v === void 0 || v === null) return void 0;
5701
5741
  return v instanceof Date ? v.getTime() : v;
5702
5742
  }
5743
+ function wantOf2(flags) {
5744
+ const mode = flags & O_ACCMODE;
5745
+ const read2 = mode === 1 ? 0 : HOLD_READ;
5746
+ const write2 = mode !== 0 || (flags & O_TRUNC) !== 0 ? HOLD_WRITE : 0;
5747
+ return read2 | write2;
5748
+ }
5749
+ function accessOf(want) {
5750
+ return (want & HOLD_READ ? 4 : 0) | (want & HOLD_WRITE ? 2 : 0);
5751
+ }
5752
+ function refusal(err) {
5753
+ const code2 = err?.code;
5754
+ return code2 === "EACCES" || code2 === "EPERM";
5755
+ }
5703
5756
  function linkedStates(bridgeOf) {
5704
5757
  const opens = /* @__PURE__ */ new Map();
5705
5758
  const byId = /* @__PURE__ */ new Map();
@@ -5939,12 +5992,13 @@ function createNodeOps(h) {
5939
5992
  const { Fs, bridgeOf, call: call2, metadataCall, makeNode, statOf, childPath, flushNode, truncate } = h;
5940
5993
  const { ensureLoaded } = h;
5941
5994
  const setTimes = (node, path, atime, mtime) => {
5995
+ const now = Fs.sliccTouch === true;
5942
5996
  if (Fs.isLink(node.mode)) {
5943
- metadataCall(() => bridgeOf(node).lutimes(path, atime, mtime));
5997
+ metadataCall(() => bridgeOf(node).lutimes(path, atime, mtime, now));
5944
5998
  return;
5945
5999
  }
5946
6000
  flushNode(node);
5947
- metadataCall(() => bridgeOf(node).utimes(path, atime, mtime));
6001
+ metadataCall(() => bridgeOf(node).utimes(path, atime, mtime, now));
5948
6002
  };
5949
6003
  const timesOf = (node, attr2) => {
5950
6004
  const mtime = toMs(attr2.mtime) ?? attr2.timestamp;
@@ -6034,6 +6088,7 @@ function createNodeOps(h) {
6034
6088
  mtimeMs: Date.now()
6035
6089
  });
6036
6090
  node.live.stat = void 0;
6091
+ if (Fs.isFile(mode)) node.live.created = true;
6037
6092
  return node;
6038
6093
  },
6039
6094
  rename(oldNode, newDir, newName) {
@@ -6110,21 +6165,34 @@ function createStreamOps(h) {
6110
6165
  }
6111
6166
  }
6112
6167
  };
6113
- const opened = (node, on) => {
6168
+ const opened = (node, on, want = 0) => {
6114
6169
  const s = node.live;
6115
6170
  try {
6116
- const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle);
6171
+ const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle, want);
6117
6172
  s.handle = on ? handle : void 0;
6118
6173
  h.linked.opening(node, on);
6119
6174
  if (s.handle === void 0) h.handled.delete(node);
6120
6175
  else h.handled.add(node);
6121
- } catch {
6176
+ } catch (err) {
6177
+ if (refusal(err)) throw new Fs.ErrnoError(wasiErrno(err.code));
6122
6178
  }
6123
6179
  };
6180
+ const permitted = (stream, created) => {
6181
+ const s = stream.node.live;
6182
+ const bridge = bridgeOf(stream.node);
6183
+ if (!bridge.owners || s.orphan) return 0;
6184
+ const want = wantOf2(stream.flags) | (created ? HOLD_CREATED : 0);
6185
+ if (s.openCount > 0 && !created) {
6186
+ h.call(() => bridge.access?.(liveNodePath(stream.node), accessOf(want), "open"));
6187
+ }
6188
+ return want;
6189
+ };
6124
6190
  return {
6125
6191
  open(stream) {
6126
6192
  if (!Fs.isFile(stream.node.mode)) return;
6127
6193
  const s = stream.node.live;
6194
+ const created = s.created === true;
6195
+ s.created = void 0;
6128
6196
  if (s.openCount === 0 && !s.orphan) {
6129
6197
  const bridge = bridgeOf(stream.node);
6130
6198
  s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
@@ -6142,8 +6210,18 @@ function createStreamOps(h) {
6142
6210
  throw err;
6143
6211
  }
6144
6212
  }
6145
- stream.node.live.openCount++;
6146
- if (stream.node.live.openCount === 1) opened(stream.node, true);
6213
+ const live = stream.node.live;
6214
+ let counted = false;
6215
+ try {
6216
+ const want = permitted(stream, created);
6217
+ live.openCount++;
6218
+ counted = true;
6219
+ if (live.openCount === 1) opened(stream.node, true, want);
6220
+ } catch (err) {
6221
+ if (counted) live.openCount--;
6222
+ if (stream.fd !== void 0) Fs.closeStream?.(stream.fd);
6223
+ throw err;
6224
+ }
6147
6225
  held(stream, 1);
6148
6226
  },
6149
6227
  dup(stream) {
@@ -6452,13 +6530,14 @@ function useLiveChown(Fs) {
6452
6530
  Fs.chown(target, uid, gid);
6453
6531
  };
6454
6532
  }
6455
- var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, stale;
6533
+ var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, O_ACCMODE, O_TRUNC, stale;
6456
6534
  var init_live_vfs_fs = __esm({
6457
6535
  "src/realm/live-vfs-fs.ts"() {
6458
6536
  "use strict";
6459
6537
  init_ranged();
6460
6538
  init_types();
6461
6539
  init_wasi_errno();
6540
+ init_sync_fs_wire();
6462
6541
  S_IFDIR = 16384;
6463
6542
  S_IFREG = 32768;
6464
6543
  S_IFLNK = 40960;
@@ -6468,6 +6547,8 @@ var init_live_vfs_fs = __esm({
6468
6547
  SEEK_CUR = 1;
6469
6548
  SEEK_END = 2;
6470
6549
  EARLY_WHOLE_FILE = 64 * 1024;
6550
+ O_ACCMODE = 3;
6551
+ O_TRUNC = 512;
6471
6552
  stale = (s) => !!s.orphan && !s.kept;
6472
6553
  }
6473
6554
  });
@@ -6546,7 +6627,7 @@ function ptyStat(path) {
6546
6627
  function nonblocking(stream) {
6547
6628
  return (stream.flags & O_NONBLOCK2) !== 0 ? { nonblock: true } : void 0;
6548
6629
  }
6549
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
6630
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
6550
6631
  var init_kernel_streams = __esm({
6551
6632
  "src/process/kernel-streams.ts"() {
6552
6633
  "use strict";
@@ -6566,7 +6647,7 @@ var init_kernel_streams = __esm({
6566
6647
  O_CREAT = 64;
6567
6648
  O_EXCL = 128;
6568
6649
  O_NOCTTY = 256;
6569
- O_TRUNC = 512;
6650
+ O_TRUNC2 = 512;
6570
6651
  KILLED_BY_SIGPIPE = 128 + 13;
6571
6652
  ProcessExit = class extends Error {
6572
6653
  status;
@@ -6794,7 +6875,7 @@ var init_kernel_streams = __esm({
6794
6875
  );
6795
6876
  let stream;
6796
6877
  try {
6797
- stream = open("/dev/null", flags & ~(O_CREAT | O_EXCL | O_TRUNC), mode);
6878
+ stream = open("/dev/null", flags & ~(O_CREAT | O_EXCL | O_TRUNC2), mode);
6798
6879
  } catch (e) {
6799
6880
  this.sys.close(kfd);
6800
6881
  throw e;
@@ -7187,7 +7268,23 @@ function kernelUmask(imports, deps) {
7187
7268
  }
7188
7269
  }
7189
7270
  }
7190
- function noFollowUtimes(imports, fs, glue) {
7271
+ function touching(times, memory) {
7272
+ if (times === 0) return true;
7273
+ if (!memory) return false;
7274
+ const heap = new Int32Array(memory.buffer);
7275
+ const nsec = [heap[times + 8 >> 2], heap[times + 24 >> 2]];
7276
+ return nsec.every((n) => n === UTIME_NOW || n === UTIME_OMIT);
7277
+ }
7278
+ function touch(Fs, on, run) {
7279
+ if (!Fs || !on) return run();
7280
+ Fs.sliccTouch = true;
7281
+ try {
7282
+ return run();
7283
+ } finally {
7284
+ Fs.sliccTouch = void 0;
7285
+ }
7286
+ }
7287
+ function noFollowUtimes(imports, fs, glue, memory = () => void 0) {
7191
7288
  for (const namespace of namespaces(imports)) {
7192
7289
  const key = Object.keys(namespace).find(
7193
7290
  (name2) => glue !== void 0 && namespace[name2] === glue || name2 === "__syscall_utimensat"
@@ -7196,9 +7293,10 @@ function noFollowUtimes(imports, fs, glue) {
7196
7293
  if (key === void 0 || typeof utimensat !== "function") continue;
7197
7294
  namespace[key] = (dirfd, path, times, flags) => {
7198
7295
  const Fs = fs();
7296
+ const on = touching(times, memory());
7199
7297
  const { utime, lookupPath, ErrnoError } = Fs ?? {};
7200
7298
  if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW2) || !utime || !lookupPath || !ErrnoError) {
7201
- return utimensat(dirfd, path, times, flags);
7299
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
7202
7300
  }
7203
7301
  Fs.utime = (at, atime, mtime) => {
7204
7302
  const { node } = lookupPath.call(Fs, at, { follow: false });
@@ -7206,7 +7304,7 @@ function noFollowUtimes(imports, fs, glue) {
7206
7304
  node.node_ops.setattr(node, { atime, mtime });
7207
7305
  };
7208
7306
  try {
7209
- return utimensat(dirfd, path, times, flags);
7307
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
7210
7308
  } finally {
7211
7309
  Fs.utime = utime;
7212
7310
  }
@@ -7325,7 +7423,7 @@ function useFileMmap(Fs, deps) {
7325
7423
  const shared = (flags & MAP_TYPE) !== MAP_PRIVATE && (prot & PROT_WRITE) !== 0;
7326
7424
  const kfd = stream.sliccKernelFile ? stream.sliccKernelFd : void 0;
7327
7425
  if (shared && kfd !== void 0) throw new Fs.ErrnoError(wasiErrno("ENODEV"));
7328
- if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE) === O_WRONLY4 || !Fs.isFile(stream.node.mode)) {
7426
+ if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE2) === O_WRONLY4 || !Fs.isFile(stream.node.mode)) {
7329
7427
  return mmap.call(fs, stream, length, position, prot, flags);
7330
7428
  }
7331
7429
  const data = staging(Fs, length);
@@ -7536,7 +7634,7 @@ function useMounts(Fs, env = {}, live = false) {
7536
7634
  const open = Fs.open.bind(Fs);
7537
7635
  Fs.open = (path, flags, mode) => {
7538
7636
  const instead = backing[path];
7539
- if (!instead || (flags & (O_ACCMODE | O_CREAT2)) !== 0) return open(path, flags, mode);
7637
+ if (!instead || (flags & (O_ACCMODE2 | O_CREAT2)) !== 0) return open(path, flags, mode);
7540
7638
  try {
7541
7639
  return open(path, flags, mode);
7542
7640
  } catch (e) {
@@ -7545,11 +7643,57 @@ function useMounts(Fs, env = {}, live = false) {
7545
7643
  }
7546
7644
  };
7547
7645
  }
7548
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW2, EMSCRIPTEN_EPERM, O_PATH, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY4, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE, O_CREAT2, field, NAME;
7646
+ function cString(memory, at) {
7647
+ const bytes = new Uint8Array(memory.buffer, at);
7648
+ return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
7649
+ }
7650
+ function baseOf(Fs, dirfd) {
7651
+ return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
7652
+ }
7653
+ function kernelChecks(Fs, memory, call2) {
7654
+ const name2 = cString(memory, call2.path);
7655
+ const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
7656
+ const lookupPath = Fs.lookupPath;
7657
+ const { node } = lookupPath.call(Fs, abs, { follow: (call2.flags & AT_SYMLINK_NOFOLLOW2) === 0 });
7658
+ const bridge = node.live ? node.mount.opts.bridge : void 0;
7659
+ if (!bridge?.owners || !bridge.access) return 0;
7660
+ const kind = call2.flags & AT_EACCESS2 ? "eaccess" : "access";
7661
+ bridge.access(liveNodePath(node), call2.amode, kind, (call2.flags & AT_SYMLINK_NOFOLLOW2) !== 0);
7662
+ return 0;
7663
+ }
7664
+ function kernelAccess(imports, fs, memory) {
7665
+ for (const ns of namespaces(imports)) {
7666
+ const own = ns.__syscall_faccessat;
7667
+ if (typeof own !== "function") continue;
7668
+ ns.__syscall_faccessat = (dirfd, path, amode, flags) => {
7669
+ const rc = own(dirfd, path, amode, flags);
7670
+ const Fs = fs();
7671
+ const heap = memory();
7672
+ if (rc !== 0 || !Fs?.lookupPath || !heap) return rc;
7673
+ try {
7674
+ return kernelChecks(Fs, heap, { dirfd, path, amode: amode & 7, flags });
7675
+ } catch (err) {
7676
+ return -errnoOf(err);
7677
+ }
7678
+ };
7679
+ }
7680
+ }
7681
+ function linuxDevices(Fs) {
7682
+ const { chmod } = Fs;
7683
+ if (!chmod) return;
7684
+ for (const [path, mode] of DEVICE_MODES) {
7685
+ try {
7686
+ chmod.call(Fs, path, mode);
7687
+ } catch {
7688
+ }
7689
+ }
7690
+ }
7691
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW2, EMSCRIPTEN_EPERM, O_PATH, UTIME_NOW, UTIME_OMIT, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY4, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE2, O_CREAT2, field, NAME, AT_FDCWD, AT_EACCESS2, DEVICE_MODES;
7549
7692
  var init_process_fds = __esm({
7550
7693
  "src/process/process-fds.ts"() {
7551
7694
  "use strict";
7552
7695
  init_loopback_names();
7696
+ init_live_vfs_fs();
7553
7697
  init_process_pty();
7554
7698
  init_wasi_errno();
7555
7699
  O_CLOEXEC = 524288;
@@ -7573,6 +7717,8 @@ var init_process_fds = __esm({
7573
7717
  AT_SYMLINK_NOFOLLOW2 = 256;
7574
7718
  EMSCRIPTEN_EPERM = 63;
7575
7719
  O_PATH = 2097152;
7720
+ UTIME_NOW = 1073741823;
7721
+ UTIME_OMIT = 1073741822;
7576
7722
  PROT_WRITE = 2;
7577
7723
  MAP_PRIVATE = 2;
7578
7724
  MAP_TYPE = 15;
@@ -7581,10 +7727,22 @@ var init_process_fds = __esm({
7581
7727
  DIR_MODE = 16749;
7582
7728
  LINK_MODE = 41408;
7583
7729
  CHAR_DEVICE = 8630;
7584
- O_ACCMODE = 3;
7730
+ O_ACCMODE2 = 3;
7585
7731
  O_CREAT2 = 64;
7586
7732
  field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
7587
7733
  NAME = /^[a-z_][a-z0-9_-]*$/i;
7734
+ AT_FDCWD = -100;
7735
+ AT_EACCESS2 = 512;
7736
+ DEVICE_MODES = [
7737
+ ["/dev", 493],
7738
+ ["/dev/null", 438],
7739
+ ["/dev/zero", 438],
7740
+ ["/dev/full", 438],
7741
+ ["/dev/random", 438],
7742
+ ["/dev/urandom", 438],
7743
+ ["/dev/tty", 438],
7744
+ ["/dev/shm", 1023]
7745
+ ];
7588
7746
  }
7589
7747
  });
7590
7748
 
@@ -7672,7 +7830,7 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
7672
7830
  function deviceOfStream(stream) {
7673
7831
  const device2 = stream.path === void 0 ? void 0 : DEVICES2[stream.path];
7674
7832
  if (!device2 || stream.sliccKernelFd !== void 0) return void 0;
7675
- const access = ACCESS[stream.flags & O_ACCMODE2];
7833
+ const access = ACCESS[stream.flags & O_ACCMODE3];
7676
7834
  return { device: device2, ...access ? { access } : {} };
7677
7835
  }
7678
7836
  function inheritedSlot(fd, stream) {
@@ -7732,7 +7890,7 @@ function restoreForkedStreams(Fs, streams, table) {
7732
7890
  } else {
7733
7891
  const placed = place(
7734
7892
  Fs,
7735
- Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC2)),
7893
+ Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC3)),
7736
7894
  entry.fd
7737
7895
  );
7738
7896
  setCloseOnExec(placed, (entry.flags & O_CLOEXEC) !== 0);
@@ -7741,16 +7899,16 @@ function restoreForkedStreams(Fs, streams, table) {
7741
7899
  }
7742
7900
  }
7743
7901
  }
7744
- var O_RDWR4, O_ACCMODE2, O_CREAT3, O_EXCL2, O_TRUNC2, PLACEHOLDER_DIR, ACCESS, DEVICES2, FIFO_MODE, nextStreamIno, streamInos;
7902
+ var O_RDWR4, O_ACCMODE3, O_CREAT3, O_EXCL2, O_TRUNC3, PLACEHOLDER_DIR, ACCESS, DEVICES2, FIFO_MODE, nextStreamIno, streamInos;
7745
7903
  var init_process_fork = __esm({
7746
7904
  "src/process/process-fork.ts"() {
7747
7905
  "use strict";
7748
7906
  init_process_fds();
7749
7907
  O_RDWR4 = 2;
7750
- O_ACCMODE2 = 3;
7908
+ O_ACCMODE3 = 3;
7751
7909
  O_CREAT3 = 64;
7752
7910
  O_EXCL2 = 128;
7753
- O_TRUNC2 = 512;
7911
+ O_TRUNC3 = 512;
7754
7912
  PLACEHOLDER_DIR = "/dev/slicc-fd";
7755
7913
  ACCESS = { 0: "read", 1: "write" };
7756
7914
  DEVICES2 = {
@@ -8777,6 +8935,7 @@ function kernelSys(transport) {
8777
8935
  ...opts?.orphan ? { orphan: true } : {},
8778
8936
  ...opts?.truncate ? { truncate: true } : {},
8779
8937
  ...opts?.create ? { create: true } : {},
8938
+ ...opts?.created ? { created: true } : {},
8780
8939
  ...opts?.pin ? { pin: opts.pin } : {},
8781
8940
  ...opts?.handle !== void 0 ? { handle: opts.handle } : {}
8782
8941
  },
@@ -8900,7 +9059,7 @@ function wireKernelStdio(Fs, streams, sys) {
8900
9059
  const meta = kind === "device" || kind === "held" ? sys?.heldMeta?.(fd) : void 0;
8901
9060
  if (meta && openHeld(Fs, fd, meta)) continue;
8902
9061
  if (kind && PLACED.has(kind)) {
8903
- const flags = sys?.access ? stream.flags & ~O_ACCMODE3 | accessMode(sys.access(fd)) : stream.flags;
9062
+ const flags = sys?.access ? stream.flags & ~O_ACCMODE4 | accessMode(sys.access(fd)) : stream.flags;
8904
9063
  Fs.closeStream(fd);
8905
9064
  const kernel = { fd, kernel: fd, kind, flags };
8906
9065
  placeKernelStream(Fs, streams, kernel).flags = flags;
@@ -8945,6 +9104,9 @@ function reportGrowth(imports, publish) {
8945
9104
  function callerOwner(Fs, init) {
8946
9105
  return init.owners ? {} : { owner: ownByCaller(Fs, init.cred, credAbi(init.program.glue)) };
8947
9106
  }
9107
+ function utimensatOf(module) {
9108
+ return ownValue(module, "sliccSyscalls")?.utimensat;
9109
+ }
8948
9110
  async function runWasmProcess(init, port3, deps = {}) {
8949
9111
  const signals = new SignalGate(
8950
9112
  createSyncSabTransport(init.sab, port3, {
@@ -9012,11 +9174,9 @@ async function runWasmProcess(init, port3, deps = {}) {
9012
9174
  memory: () => memory,
9013
9175
  set: (mask) => void transport.call({ op: "proc-umask", mask }, Number.POSITIVE_INFINITY, "umask")
9014
9176
  });
9015
- noFollowUtimes(
9016
- imports,
9017
- () => ownValue(module, "FS"),
9018
- ownValue(module, "sliccSyscalls")?.utimensat
9019
- );
9177
+ const fsOf = () => ownValue(module, "FS");
9178
+ noFollowUtimes(imports, fsOf, utimensatOf(module), () => memory);
9179
+ kernelAccess(imports, fsOf, () => memory);
9020
9180
  const glue = ownValue(module, "sliccFdImports");
9021
9181
  syncFsync(imports, () => ownValue(module, "FS"), glue);
9022
9182
  positionalIo(imports, {
@@ -9054,6 +9214,7 @@ async function runWasmProcess(init, port3, deps = {}) {
9054
9214
  await initialized;
9055
9215
  const running = module;
9056
9216
  if (!hasStreams(running)) return runStdioOnly(running, init);
9217
+ if (init.owners) linuxDevices(running.FS);
9057
9218
  const vfs = mountVfsIntoEmscripten(running.FS, {
9058
9219
  bridge: createSyncFsSabBridge(transport, init.owners ? { owners: true } : {}),
9059
9220
  cwd: init.cwd,
@@ -9155,7 +9316,7 @@ function runMain(running, init) {
9155
9316
  return status2;
9156
9317
  }
9157
9318
  }
9158
- var FS_OPS, O_RDONLY, O_WRONLY6, O_RDWR6, O_ACCMODE3, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
9319
+ var FS_OPS, O_RDONLY, O_WRONLY6, O_RDWR6, O_ACCMODE4, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
9159
9320
  var init_process_runtime = __esm({
9160
9321
  "src/process/process-runtime.ts"() {
9161
9322
  "use strict";
@@ -9180,7 +9341,7 @@ var init_process_runtime = __esm({
9180
9341
  O_RDONLY = 0;
9181
9342
  O_WRONLY6 = 1;
9182
9343
  O_RDWR6 = 2;
9183
- O_ACCMODE3 = 3;
9344
+ O_ACCMODE4 = 3;
9184
9345
  O_DIRECTORY = 65536;
9185
9346
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY6 : O_RDWR6;
9186
9347
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket"]);
@@ -9516,10 +9677,10 @@ function procfsBridge(fs, tree) {
9516
9677
  ],
9517
9678
  () => fs.link(from, to, follow2)
9518
9679
  ),
9519
- hold: (p, held, open, handle) => {
9680
+ hold: (p, held, open, handle, want) => {
9520
9681
  if (handle !== void 0 && snapshots.delete(handle)) return void 0;
9521
9682
  if (!held) return fs.hold?.(p, held, open, handle);
9522
- return via(p, snapshot, () => fs.hold?.(p, held, open) ?? late(p));
9683
+ return via(p, snapshot, () => fs.hold?.(p, held, open, void 0, want) ?? late(p));
9523
9684
  },
9524
9685
  kept: (handle) => snapshots.has(handle) || fs.kept?.(handle) === true,
9525
9686
  pinned: (handle) => {