@ai-ecoverse/slicc-kernel 1.62.3 → 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.
@@ -572,6 +572,82 @@ var init_wasi_errno = __esm({
572
572
  }
573
573
  });
574
574
 
575
+ // src/realm/sync-fs-wire.ts
576
+ function parseSyncFsUsage(json) {
577
+ const u = json;
578
+ if (!u || typeof u.quota !== "number" || typeof u.usage !== "number") return null;
579
+ return { quota: u.quota, usage: u.usage };
580
+ }
581
+ function syncError(code2, label) {
582
+ return Object.assign(new Error(`${code2}: ${label}`), { code: code2 });
583
+ }
584
+ function parseSyncFsStat(json) {
585
+ const s = json;
586
+ if (!s || typeof s.isFile !== "boolean" || typeof s.isDirectory !== "boolean" || typeof s.size !== "number") {
587
+ return null;
588
+ }
589
+ return {
590
+ isFile: s.isFile,
591
+ isDirectory: s.isDirectory,
592
+ isSymbolicLink: s.isSymbolicLink,
593
+ size: s.size,
594
+ ...typeof s.mode === "number" ? { mode: s.mode } : {},
595
+ ...typeof s.mtimeMs === "number" ? { mtimeMs: s.mtimeMs } : {},
596
+ ...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
597
+ ...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
598
+ ...typeof s.ino === "number" ? { ino: s.ino } : {},
599
+ ...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
600
+ ...typeof s.dev === "number" ? { dev: s.dev } : {},
601
+ ...s.readonly === true ? { readonly: true } : {},
602
+ ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
603
+ ...s.ranged === true ? { ranged: true } : {},
604
+ ...s.linkable === true ? { linkable: true } : {},
605
+ ...typeof s.version === "string" ? { version: s.version } : {},
606
+ ...typeof s.uid === "number" ? { uid: s.uid } : {},
607
+ ...typeof s.gid === "number" ? { gid: s.gid } : {}
608
+ };
609
+ }
610
+ var SYNC_FS_OPS, HOLD_READ, HOLD_WRITE, HOLD_CREATED, SYNC_FS_REQUEST_TIMEOUT_MS;
611
+ var init_sync_fs_wire = __esm({
612
+ "src/realm/sync-fs-wire.ts"() {
613
+ "use strict";
614
+ SYNC_FS_OPS = [
615
+ "read",
616
+ "write",
617
+ "exists",
618
+ "stat",
619
+ "lstat",
620
+ "readdir",
621
+ "readdir-stat",
622
+ "mkdir",
623
+ "rm",
624
+ "rename",
625
+ "link",
626
+ "unlink",
627
+ "rmdir",
628
+ "symlink",
629
+ "readlink",
630
+ "chmod",
631
+ "utimes",
632
+ "lutimes",
633
+ "statfs",
634
+ "hold",
635
+ "create",
636
+ "kept",
637
+ "pread",
638
+ "pwrite",
639
+ "truncate",
640
+ "chown",
641
+ "lchown",
642
+ "access"
643
+ ];
644
+ HOLD_READ = 4;
645
+ HOLD_WRITE = 8;
646
+ HOLD_CREATED = 16;
647
+ SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
648
+ }
649
+ });
650
+
575
651
  // src/realm/live-vfs-fs.ts
576
652
  function toErrno(Fs, err) {
577
653
  if (err?.errno !== void 0 && err instanceof Fs.ErrnoError) {
@@ -600,6 +676,19 @@ function toMs(v) {
600
676
  if (v === void 0 || v === null) return void 0;
601
677
  return v instanceof Date ? v.getTime() : v;
602
678
  }
679
+ function wantOf(flags) {
680
+ const mode = flags & O_ACCMODE;
681
+ const read2 = mode === 1 ? 0 : HOLD_READ;
682
+ const write2 = mode !== 0 || (flags & O_TRUNC) !== 0 ? HOLD_WRITE : 0;
683
+ return read2 | write2;
684
+ }
685
+ function accessOf(want) {
686
+ return (want & HOLD_READ ? 4 : 0) | (want & HOLD_WRITE ? 2 : 0);
687
+ }
688
+ function refusal(err) {
689
+ const code2 = err?.code;
690
+ return code2 === "EACCES" || code2 === "EPERM";
691
+ }
603
692
  function linkedStates(bridgeOf) {
604
693
  const opens = /* @__PURE__ */ new Map();
605
694
  const byId = /* @__PURE__ */ new Map();
@@ -839,12 +928,13 @@ function createNodeOps(h) {
839
928
  const { Fs, bridgeOf, call: call2, metadataCall, makeNode, statOf, childPath, flushNode, truncate } = h;
840
929
  const { ensureLoaded } = h;
841
930
  const setTimes = (node, path, atime, mtime) => {
931
+ const now = Fs.sliccTouch === true;
842
932
  if (Fs.isLink(node.mode)) {
843
- metadataCall(() => bridgeOf(node).lutimes(path, atime, mtime));
933
+ metadataCall(() => bridgeOf(node).lutimes(path, atime, mtime, now));
844
934
  return;
845
935
  }
846
936
  flushNode(node);
847
- metadataCall(() => bridgeOf(node).utimes(path, atime, mtime));
937
+ metadataCall(() => bridgeOf(node).utimes(path, atime, mtime, now));
848
938
  };
849
939
  const timesOf = (node, attr2) => {
850
940
  const mtime = toMs(attr2.mtime) ?? attr2.timestamp;
@@ -934,6 +1024,7 @@ function createNodeOps(h) {
934
1024
  mtimeMs: Date.now()
935
1025
  });
936
1026
  node.live.stat = void 0;
1027
+ if (Fs.isFile(mode)) node.live.created = true;
937
1028
  return node;
938
1029
  },
939
1030
  rename(oldNode, newDir, newName) {
@@ -1010,21 +1101,34 @@ function createStreamOps(h) {
1010
1101
  }
1011
1102
  }
1012
1103
  };
1013
- const opened = (node, on) => {
1104
+ const opened = (node, on, want = 0) => {
1014
1105
  const s = node.live;
1015
1106
  try {
1016
- const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle);
1107
+ const handle = bridgeOf(node).hold?.(liveNodePath(node), on, true, s.handle, want);
1017
1108
  s.handle = on ? handle : void 0;
1018
1109
  h.linked.opening(node, on);
1019
1110
  if (s.handle === void 0) h.handled.delete(node);
1020
1111
  else h.handled.add(node);
1021
- } catch {
1112
+ } catch (err) {
1113
+ if (refusal(err)) throw new Fs.ErrnoError(wasiErrno(err.code));
1022
1114
  }
1023
1115
  };
1116
+ const permitted = (stream, created) => {
1117
+ const s = stream.node.live;
1118
+ const bridge = bridgeOf(stream.node);
1119
+ if (!bridge.owners || s.orphan) return 0;
1120
+ const want = wantOf(stream.flags) | (created ? HOLD_CREATED : 0);
1121
+ if (s.openCount > 0 && !created) {
1122
+ h.call(() => bridge.access?.(liveNodePath(stream.node), accessOf(want), "open"));
1123
+ }
1124
+ return want;
1125
+ };
1024
1126
  return {
1025
1127
  open(stream) {
1026
1128
  if (!Fs.isFile(stream.node.mode)) return;
1027
1129
  const s = stream.node.live;
1130
+ const created = s.created === true;
1131
+ s.created = void 0;
1028
1132
  if (s.openCount === 0 && !s.orphan) {
1029
1133
  const bridge = bridgeOf(stream.node);
1030
1134
  s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
@@ -1042,8 +1146,18 @@ function createStreamOps(h) {
1042
1146
  throw err;
1043
1147
  }
1044
1148
  }
1045
- stream.node.live.openCount++;
1046
- if (stream.node.live.openCount === 1) opened(stream.node, true);
1149
+ const live = stream.node.live;
1150
+ let counted = false;
1151
+ try {
1152
+ const want = permitted(stream, created);
1153
+ live.openCount++;
1154
+ counted = true;
1155
+ if (live.openCount === 1) opened(stream.node, true, want);
1156
+ } catch (err) {
1157
+ if (counted) live.openCount--;
1158
+ if (stream.fd !== void 0) Fs.closeStream?.(stream.fd);
1159
+ throw err;
1160
+ }
1047
1161
  held(stream, 1);
1048
1162
  },
1049
1163
  dup(stream) {
@@ -1352,13 +1466,14 @@ function useLiveChown(Fs) {
1352
1466
  Fs.chown(target, uid, gid);
1353
1467
  };
1354
1468
  }
1355
- var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, stale;
1469
+ 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;
1356
1470
  var init_live_vfs_fs = __esm({
1357
1471
  "src/realm/live-vfs-fs.ts"() {
1358
1472
  "use strict";
1359
1473
  init_ranged();
1360
1474
  init_types();
1361
1475
  init_wasi_errno();
1476
+ init_sync_fs_wire();
1362
1477
  S_IFDIR = 16384;
1363
1478
  S_IFREG = 32768;
1364
1479
  S_IFLNK = 40960;
@@ -1368,6 +1483,8 @@ var init_live_vfs_fs = __esm({
1368
1483
  SEEK_CUR = 1;
1369
1484
  SEEK_END = 2;
1370
1485
  EARLY_WHOLE_FILE = 64 * 1024;
1486
+ O_ACCMODE = 3;
1487
+ O_TRUNC = 512;
1371
1488
  stale = (s) => !!s.orphan && !s.kept;
1372
1489
  }
1373
1490
  });
@@ -1420,78 +1537,6 @@ var init_emscripten_vfs_hook = __esm({
1420
1537
  }
1421
1538
  });
1422
1539
 
1423
- // src/realm/sync-fs-wire.ts
1424
- function parseSyncFsUsage(json) {
1425
- const u = json;
1426
- if (!u || typeof u.quota !== "number" || typeof u.usage !== "number") return null;
1427
- return { quota: u.quota, usage: u.usage };
1428
- }
1429
- function syncError(code2, label) {
1430
- return Object.assign(new Error(`${code2}: ${label}`), { code: code2 });
1431
- }
1432
- function parseSyncFsStat(json) {
1433
- const s = json;
1434
- if (!s || typeof s.isFile !== "boolean" || typeof s.isDirectory !== "boolean" || typeof s.size !== "number") {
1435
- return null;
1436
- }
1437
- return {
1438
- isFile: s.isFile,
1439
- isDirectory: s.isDirectory,
1440
- isSymbolicLink: s.isSymbolicLink,
1441
- size: s.size,
1442
- ...typeof s.mode === "number" ? { mode: s.mode } : {},
1443
- ...typeof s.mtimeMs === "number" ? { mtimeMs: s.mtimeMs } : {},
1444
- ...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
1445
- ...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
1446
- ...typeof s.ino === "number" ? { ino: s.ino } : {},
1447
- ...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
1448
- ...typeof s.dev === "number" ? { dev: s.dev } : {},
1449
- ...s.readonly === true ? { readonly: true } : {},
1450
- ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
1451
- ...s.ranged === true ? { ranged: true } : {},
1452
- ...s.linkable === true ? { linkable: true } : {},
1453
- ...typeof s.version === "string" ? { version: s.version } : {},
1454
- ...typeof s.uid === "number" ? { uid: s.uid } : {},
1455
- ...typeof s.gid === "number" ? { gid: s.gid } : {}
1456
- };
1457
- }
1458
- var SYNC_FS_OPS, SYNC_FS_REQUEST_TIMEOUT_MS;
1459
- var init_sync_fs_wire = __esm({
1460
- "src/realm/sync-fs-wire.ts"() {
1461
- "use strict";
1462
- SYNC_FS_OPS = [
1463
- "read",
1464
- "write",
1465
- "exists",
1466
- "stat",
1467
- "lstat",
1468
- "readdir",
1469
- "readdir-stat",
1470
- "mkdir",
1471
- "rm",
1472
- "rename",
1473
- "link",
1474
- "unlink",
1475
- "rmdir",
1476
- "symlink",
1477
- "readlink",
1478
- "chmod",
1479
- "utimes",
1480
- "lutimes",
1481
- "statfs",
1482
- "hold",
1483
- "create",
1484
- "kept",
1485
- "pread",
1486
- "pwrite",
1487
- "truncate",
1488
- "chown",
1489
- "lchown"
1490
- ];
1491
- SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
1492
- }
1493
- });
1494
-
1495
1540
  // src/realm/sync-sab-wire.ts
1496
1541
  function loadU53(header, lo, hi) {
1497
1542
  return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
@@ -1749,15 +1794,15 @@ function createSyncFsSabBridge(transport, opts = {}) {
1749
1794
  chmod: (path, mode) => {
1750
1795
  changing({ op: "chmod", path, mode }, path);
1751
1796
  },
1752
- utimes: (path, atimeMs, mtimeMs) => {
1753
- changing({ op: "utimes", path, atimeMs, mtimeMs }, path);
1797
+ utimes: (path, atimeMs, mtimeMs, now) => {
1798
+ changing({ op: "utimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
1754
1799
  },
1755
1800
  identify: () => {
1756
1801
  identity = { identity: true };
1757
1802
  },
1758
1803
  identified: () => last,
1759
- lutimes: (path, atimeMs, mtimeMs) => {
1760
- run({ op: "lutimes", path, atimeMs, mtimeMs }, path);
1804
+ lutimes: (path, atimeMs, mtimeMs, now) => {
1805
+ run({ op: "lutimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
1761
1806
  },
1762
1807
  create: (path, mode) => {
1763
1808
  run({ op: "create", path, ...mode !== void 0 ? { mode } : {} }, path);
@@ -1767,9 +1812,12 @@ function createSyncFsSabBridge(transport, opts = {}) {
1767
1812
  changing({ op: follow2 ? "chown" : "lchown", path, ...ids }, path);
1768
1813
  },
1769
1814
  ...opts.owners ? { owners: true } : {},
1770
- hold: (path, held, open, handle) => {
1815
+ access: (path, mode, kind = "access", nofollow) => {
1816
+ run({ op: "access", path, mode, arg2: kind, ...nofollow ? { nofollow } : {} }, path);
1817
+ },
1818
+ hold: (path, held, open, handle, want = 0) => {
1771
1819
  const mode = (held ? 1 : 0) | (open ? 2 : 0);
1772
- if (mode === 3) return json({ op: "hold", path, mode }, path);
1820
+ if (mode === 3) return json({ op: "hold", path, mode: mode | want }, path);
1773
1821
  run({ op: "hold", path, mode, ...handle !== void 0 ? { handle } : {} }, path);
1774
1822
  return void 0;
1775
1823
  },
@@ -1810,7 +1858,7 @@ function ptyStat(path) {
1810
1858
  function nonblocking(stream) {
1811
1859
  return (stream.flags & O_NONBLOCK) !== 0 ? { nonblock: true } : void 0;
1812
1860
  }
1813
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
1861
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
1814
1862
  var init_kernel_streams = __esm({
1815
1863
  "src/process/kernel-streams.ts"() {
1816
1864
  "use strict";
@@ -1830,7 +1878,7 @@ var init_kernel_streams = __esm({
1830
1878
  O_CREAT = 64;
1831
1879
  O_EXCL = 128;
1832
1880
  O_NOCTTY = 256;
1833
- O_TRUNC = 512;
1881
+ O_TRUNC2 = 512;
1834
1882
  KILLED_BY_SIGPIPE = 128 + 13;
1835
1883
  ProcessExit = class extends Error {
1836
1884
  status;
@@ -2058,7 +2106,7 @@ var init_kernel_streams = __esm({
2058
2106
  );
2059
2107
  let stream;
2060
2108
  try {
2061
- stream = open("/dev/null", flags & ~(O_CREAT | O_EXCL | O_TRUNC), mode);
2109
+ stream = open("/dev/null", flags & ~(O_CREAT | O_EXCL | O_TRUNC2), mode);
2062
2110
  } catch (e) {
2063
2111
  this.sys.close(kfd);
2064
2112
  throw e;
@@ -2451,7 +2499,23 @@ function kernelUmask(imports, deps) {
2451
2499
  }
2452
2500
  }
2453
2501
  }
2454
- function noFollowUtimes(imports, fs, glue) {
2502
+ function touching(times, memory) {
2503
+ if (times === 0) return true;
2504
+ if (!memory) return false;
2505
+ const heap = new Int32Array(memory.buffer);
2506
+ const nsec = [heap[times + 8 >> 2], heap[times + 24 >> 2]];
2507
+ return nsec.every((n) => n === UTIME_NOW || n === UTIME_OMIT);
2508
+ }
2509
+ function touch(Fs, on, run) {
2510
+ if (!Fs || !on) return run();
2511
+ Fs.sliccTouch = true;
2512
+ try {
2513
+ return run();
2514
+ } finally {
2515
+ Fs.sliccTouch = void 0;
2516
+ }
2517
+ }
2518
+ function noFollowUtimes(imports, fs, glue, memory = () => void 0) {
2455
2519
  for (const namespace of namespaces(imports)) {
2456
2520
  const key = Object.keys(namespace).find(
2457
2521
  (name2) => glue !== void 0 && namespace[name2] === glue || name2 === "__syscall_utimensat"
@@ -2460,9 +2524,10 @@ function noFollowUtimes(imports, fs, glue) {
2460
2524
  if (key === void 0 || typeof utimensat !== "function") continue;
2461
2525
  namespace[key] = (dirfd, path, times, flags) => {
2462
2526
  const Fs = fs();
2527
+ const on = touching(times, memory());
2463
2528
  const { utime, lookupPath, ErrnoError } = Fs ?? {};
2464
2529
  if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW) || !utime || !lookupPath || !ErrnoError) {
2465
- return utimensat(dirfd, path, times, flags);
2530
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2466
2531
  }
2467
2532
  Fs.utime = (at, atime, mtime) => {
2468
2533
  const { node } = lookupPath.call(Fs, at, { follow: false });
@@ -2470,7 +2535,7 @@ function noFollowUtimes(imports, fs, glue) {
2470
2535
  node.node_ops.setattr(node, { atime, mtime });
2471
2536
  };
2472
2537
  try {
2473
- return utimensat(dirfd, path, times, flags);
2538
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2474
2539
  } finally {
2475
2540
  Fs.utime = utime;
2476
2541
  }
@@ -2589,7 +2654,7 @@ function useFileMmap(Fs, deps) {
2589
2654
  const shared = (flags & MAP_TYPE) !== MAP_PRIVATE && (prot & PROT_WRITE) !== 0;
2590
2655
  const kfd = stream.sliccKernelFile ? stream.sliccKernelFd : void 0;
2591
2656
  if (shared && kfd !== void 0) throw new Fs.ErrnoError(wasiErrno("ENODEV"));
2592
- if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE) === O_WRONLY || !Fs.isFile(stream.node.mode)) {
2657
+ if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE2) === O_WRONLY || !Fs.isFile(stream.node.mode)) {
2593
2658
  return mmap.call(fs, stream, length, position, prot, flags);
2594
2659
  }
2595
2660
  const data = staging(Fs, length);
@@ -2800,7 +2865,7 @@ function useMounts(Fs, env = {}, live = false) {
2800
2865
  const open = Fs.open.bind(Fs);
2801
2866
  Fs.open = (path, flags, mode) => {
2802
2867
  const instead = backing[path];
2803
- if (!instead || (flags & (O_ACCMODE | O_CREAT2)) !== 0) return open(path, flags, mode);
2868
+ if (!instead || (flags & (O_ACCMODE2 | O_CREAT2)) !== 0) return open(path, flags, mode);
2804
2869
  try {
2805
2870
  return open(path, flags, mode);
2806
2871
  } catch (e) {
@@ -2809,11 +2874,57 @@ function useMounts(Fs, env = {}, live = false) {
2809
2874
  }
2810
2875
  };
2811
2876
  }
2812
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, O_PATH, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE, O_CREAT2, field, NAME;
2877
+ function cString(memory, at) {
2878
+ const bytes = new Uint8Array(memory.buffer, at);
2879
+ return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
2880
+ }
2881
+ function baseOf(Fs, dirfd) {
2882
+ return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
2883
+ }
2884
+ function kernelChecks(Fs, memory, call2) {
2885
+ const name2 = cString(memory, call2.path);
2886
+ const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
2887
+ const lookupPath = Fs.lookupPath;
2888
+ const { node } = lookupPath.call(Fs, abs, { follow: (call2.flags & AT_SYMLINK_NOFOLLOW) === 0 });
2889
+ const bridge = node.live ? node.mount.opts.bridge : void 0;
2890
+ if (!bridge?.owners || !bridge.access) return 0;
2891
+ const kind = call2.flags & AT_EACCESS ? "eaccess" : "access";
2892
+ bridge.access(liveNodePath(node), call2.amode, kind, (call2.flags & AT_SYMLINK_NOFOLLOW) !== 0);
2893
+ return 0;
2894
+ }
2895
+ function kernelAccess(imports, fs, memory) {
2896
+ for (const ns of namespaces(imports)) {
2897
+ const own = ns.__syscall_faccessat;
2898
+ if (typeof own !== "function") continue;
2899
+ ns.__syscall_faccessat = (dirfd, path, amode, flags) => {
2900
+ const rc = own(dirfd, path, amode, flags);
2901
+ const Fs = fs();
2902
+ const heap = memory();
2903
+ if (rc !== 0 || !Fs?.lookupPath || !heap) return rc;
2904
+ try {
2905
+ return kernelChecks(Fs, heap, { dirfd, path, amode: amode & 7, flags });
2906
+ } catch (err) {
2907
+ return -errnoOf(err);
2908
+ }
2909
+ };
2910
+ }
2911
+ }
2912
+ function linuxDevices(Fs) {
2913
+ const { chmod } = Fs;
2914
+ if (!chmod) return;
2915
+ for (const [path, mode] of DEVICE_MODES) {
2916
+ try {
2917
+ chmod.call(Fs, path, mode);
2918
+ } catch {
2919
+ }
2920
+ }
2921
+ }
2922
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, O_PATH, UTIME_NOW, UTIME_OMIT, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE2, O_CREAT2, field, NAME, AT_FDCWD, AT_EACCESS, DEVICE_MODES;
2813
2923
  var init_process_fds = __esm({
2814
2924
  "src/process/process-fds.ts"() {
2815
2925
  "use strict";
2816
2926
  init_loopback_names();
2927
+ init_live_vfs_fs();
2817
2928
  init_process_pty();
2818
2929
  init_wasi_errno();
2819
2930
  O_CLOEXEC = 524288;
@@ -2837,6 +2948,8 @@ var init_process_fds = __esm({
2837
2948
  AT_SYMLINK_NOFOLLOW = 256;
2838
2949
  EMSCRIPTEN_EPERM = 63;
2839
2950
  O_PATH = 2097152;
2951
+ UTIME_NOW = 1073741823;
2952
+ UTIME_OMIT = 1073741822;
2840
2953
  PROT_WRITE = 2;
2841
2954
  MAP_PRIVATE = 2;
2842
2955
  MAP_TYPE = 15;
@@ -2845,10 +2958,22 @@ var init_process_fds = __esm({
2845
2958
  DIR_MODE = 16749;
2846
2959
  LINK_MODE = 41408;
2847
2960
  CHAR_DEVICE = 8630;
2848
- O_ACCMODE = 3;
2961
+ O_ACCMODE2 = 3;
2849
2962
  O_CREAT2 = 64;
2850
2963
  field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
2851
2964
  NAME = /^[a-z_][a-z0-9_-]*$/i;
2965
+ AT_FDCWD = -100;
2966
+ AT_EACCESS = 512;
2967
+ DEVICE_MODES = [
2968
+ ["/dev", 493],
2969
+ ["/dev/null", 438],
2970
+ ["/dev/zero", 438],
2971
+ ["/dev/full", 438],
2972
+ ["/dev/random", 438],
2973
+ ["/dev/urandom", 438],
2974
+ ["/dev/tty", 438],
2975
+ ["/dev/shm", 1023]
2976
+ ];
2852
2977
  }
2853
2978
  });
2854
2979
 
@@ -2936,7 +3061,7 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
2936
3061
  function deviceOfStream(stream) {
2937
3062
  const device2 = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2938
3063
  if (!device2 || stream.sliccKernelFd !== void 0) return void 0;
2939
- const access = ACCESS[stream.flags & O_ACCMODE2];
3064
+ const access = ACCESS[stream.flags & O_ACCMODE3];
2940
3065
  return { device: device2, ...access ? { access } : {} };
2941
3066
  }
2942
3067
  function inheritedSlot(fd, stream) {
@@ -2996,7 +3121,7 @@ function restoreForkedStreams(Fs, streams, table) {
2996
3121
  } else {
2997
3122
  const placed = place(
2998
3123
  Fs,
2999
- Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC2)),
3124
+ Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC3)),
3000
3125
  entry.fd
3001
3126
  );
3002
3127
  setCloseOnExec(placed, (entry.flags & O_CLOEXEC) !== 0);
@@ -3005,16 +3130,16 @@ function restoreForkedStreams(Fs, streams, table) {
3005
3130
  }
3006
3131
  }
3007
3132
  }
3008
- var O_RDWR, O_ACCMODE2, O_CREAT3, O_EXCL2, O_TRUNC2, PLACEHOLDER_DIR, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3133
+ var O_RDWR, O_ACCMODE3, O_CREAT3, O_EXCL2, O_TRUNC3, PLACEHOLDER_DIR, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3009
3134
  var init_process_fork = __esm({
3010
3135
  "src/process/process-fork.ts"() {
3011
3136
  "use strict";
3012
3137
  init_process_fds();
3013
3138
  O_RDWR = 2;
3014
- O_ACCMODE2 = 3;
3139
+ O_ACCMODE3 = 3;
3015
3140
  O_CREAT3 = 64;
3016
3141
  O_EXCL2 = 128;
3017
- O_TRUNC2 = 512;
3142
+ O_TRUNC3 = 512;
3018
3143
  PLACEHOLDER_DIR = "/dev/slicc-fd";
3019
3144
  ACCESS = { 0: "read", 1: "write" };
3020
3145
  DEVICES = {
@@ -4060,6 +4185,7 @@ function kernelSys(transport) {
4060
4185
  ...opts?.orphan ? { orphan: true } : {},
4061
4186
  ...opts?.truncate ? { truncate: true } : {},
4062
4187
  ...opts?.create ? { create: true } : {},
4188
+ ...opts?.created ? { created: true } : {},
4063
4189
  ...opts?.pin ? { pin: opts.pin } : {},
4064
4190
  ...opts?.handle !== void 0 ? { handle: opts.handle } : {}
4065
4191
  },
@@ -4183,7 +4309,7 @@ function wireKernelStdio(Fs, streams, sys) {
4183
4309
  const meta = kind === "device" || kind === "held" ? sys?.heldMeta?.(fd) : void 0;
4184
4310
  if (meta && openHeld(Fs, fd, meta)) continue;
4185
4311
  if (kind && PLACED.has(kind)) {
4186
- const flags = sys?.access ? stream.flags & ~O_ACCMODE3 | accessMode(sys.access(fd)) : stream.flags;
4312
+ const flags = sys?.access ? stream.flags & ~O_ACCMODE4 | accessMode(sys.access(fd)) : stream.flags;
4187
4313
  Fs.closeStream(fd);
4188
4314
  const kernel = { fd, kernel: fd, kind, flags };
4189
4315
  placeKernelStream(Fs, streams, kernel).flags = flags;
@@ -4228,6 +4354,9 @@ function reportGrowth(imports, publish) {
4228
4354
  function callerOwner(Fs, init) {
4229
4355
  return init.owners ? {} : { owner: ownByCaller(Fs, init.cred, credAbi(init.program.glue)) };
4230
4356
  }
4357
+ function utimensatOf(module) {
4358
+ return ownValue(module, "sliccSyscalls")?.utimensat;
4359
+ }
4231
4360
  async function runWasmProcess(init, port2, deps = {}) {
4232
4361
  const signals = new SignalGate(
4233
4362
  createSyncSabTransport(init.sab, port2, {
@@ -4295,11 +4424,9 @@ async function runWasmProcess(init, port2, deps = {}) {
4295
4424
  memory: () => memory,
4296
4425
  set: (mask) => void transport.call({ op: "proc-umask", mask }, Number.POSITIVE_INFINITY, "umask")
4297
4426
  });
4298
- noFollowUtimes(
4299
- imports,
4300
- () => ownValue(module, "FS"),
4301
- ownValue(module, "sliccSyscalls")?.utimensat
4302
- );
4427
+ const fsOf = () => ownValue(module, "FS");
4428
+ noFollowUtimes(imports, fsOf, utimensatOf(module), () => memory);
4429
+ kernelAccess(imports, fsOf, () => memory);
4303
4430
  const glue = ownValue(module, "sliccFdImports");
4304
4431
  syncFsync(imports, () => ownValue(module, "FS"), glue);
4305
4432
  positionalIo(imports, {
@@ -4337,6 +4464,7 @@ async function runWasmProcess(init, port2, deps = {}) {
4337
4464
  await initialized;
4338
4465
  const running = module;
4339
4466
  if (!hasStreams(running)) return runStdioOnly(running, init);
4467
+ if (init.owners) linuxDevices(running.FS);
4340
4468
  const vfs = mountVfsIntoEmscripten(running.FS, {
4341
4469
  bridge: createSyncFsSabBridge(transport, init.owners ? { owners: true } : {}),
4342
4470
  cwd: init.cwd,
@@ -4438,7 +4566,7 @@ function runMain(running, init) {
4438
4566
  return status2;
4439
4567
  }
4440
4568
  }
4441
- var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE3, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
4569
+ var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE4, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
4442
4570
  var init_process_runtime = __esm({
4443
4571
  "src/process/process-runtime.ts"() {
4444
4572
  "use strict";
@@ -4463,7 +4591,7 @@ var init_process_runtime = __esm({
4463
4591
  O_RDONLY = 0;
4464
4592
  O_WRONLY3 = 1;
4465
4593
  O_RDWR3 = 2;
4466
- O_ACCMODE3 = 3;
4594
+ O_ACCMODE4 = 3;
4467
4595
  O_DIRECTORY = 65536;
4468
4596
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY3 : O_RDWR3;
4469
4597
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket"]);
@@ -4791,9 +4919,10 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
4791
4919
  rmdir: (p) => mutating(() => bridge.rmdir(p)),
4792
4920
  symlink: (target, link) => mutating(() => bridge.symlink(target, link), ...entry(link)),
4793
4921
  chmod: (p, mode) => rewriting(p, () => bridge.chmod(p, mode)),
4794
- utimes: (p, a, m) => rewriting(p, () => bridge.utimes(p, a, m)),
4795
- lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m), p),
4922
+ utimes: (p, a, m, now2) => rewriting(p, () => bridge.utimes(p, a, m, now2)),
4923
+ lutimes: (p, a, m, now2) => mutating(() => bridge.lutimes(p, a, m, now2), p),
4796
4924
  ...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
4925
+ ...bridge.access ? { access: bridge.access.bind(bridge) } : {},
4797
4926
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
4798
4927
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
4799
4928
  ...bridge.pinned ? { pinned: (handle) => pinnedIo2(bridge, handle, rewriting) } : {},
@@ -5166,6 +5295,11 @@ function entryOf(info) {
5166
5295
  append: ((info.flags ?? 0) & O_APPEND) !== 0
5167
5296
  };
5168
5297
  }
5298
+ function wantOf2(oflags, rights) {
5299
+ const write2 = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
5300
+ const read2 = (rights & RIGHTS.FD_READ) !== 0n || !write2;
5301
+ return (read2 ? 4 : 0) | (write2 ? 2 : 0);
5302
+ }
5169
5303
  function openAccess(existing, oflags, rights) {
5170
5304
  const readonly = existing?.readonly === true;
5171
5305
  const mutating = readonly ? OFLAGS.TRUNC : OFLAGS.CREAT | OFLAGS.TRUNC;
@@ -5194,6 +5328,7 @@ var SYNTHETIC_DIRS2, O_NONBLOCK2, O_WRONLY4, O_RDWR4, O_APPEND, DEVICES2, WasiFd
5194
5328
  var init_wasi_fds = __esm({
5195
5329
  "src/process/wasi/wasi-fds.ts"() {
5196
5330
  "use strict";
5331
+ init_sync_fs_wire();
5197
5332
  init_wasi_abi();
5198
5333
  init_wasi_files();
5199
5334
  SYNTHETIC_DIRS2 = ["usr", "bin"];
@@ -5734,32 +5869,42 @@ var init_wasi_fds = __esm({
5734
5869
  buffer = void 0;
5735
5870
  }
5736
5871
  buffer ??= this.sharing(path, existing);
5872
+ const want = wantOf2(oflags, rights);
5737
5873
  if (buffer) {
5874
+ if (this.fs.owners) this.fs.access?.(path, want, "open");
5738
5875
  if (oflags & OFLAGS.TRUNC) buffer.truncate(0);
5739
5876
  } else {
5740
- const made = !existing && this.createNew(path, oflags);
5741
- const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
5742
- if (existing?.ranged) this.fs.invalidate?.();
5743
- const st = existing?.ranged || !existing ? this.fs.stat(path) : existing;
5744
- const ranged = st.ranged ? st.size : void 0;
5745
- const handle = this.fs.hold?.(path, true, true);
5746
- const io = handle !== void 0 && this.fs.pinned ? this.fs.pinned(handle) : this.fs;
5747
- buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
5748
- buffer.handle = handle;
5749
- this.buffers.set(path, buffer);
5750
- const id = this.identity(st);
5751
- if (id !== void 0) this.know(buffer, id);
5877
+ buffer = this.freshBuffer(path, existing, oflags, want);
5752
5878
  }
5753
5879
  buffer.opens++;
5754
5880
  return new LocalFile(buffer, readable2, writable2, (fdflags & FDFLAGS.APPEND) !== 0);
5755
5881
  }
5882
+ freshBuffer(path, existing, oflags, want) {
5883
+ const made = !existing && this.createNew(path, oflags);
5884
+ const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
5885
+ if (existing?.ranged) this.fs.invalidate?.();
5886
+ const st = existing?.ranged || !existing ? this.fs.stat(path) : existing;
5887
+ const ranged = st.ranged ? st.size : void 0;
5888
+ const asked = (want & 4 ? HOLD_READ : 0) | (want & 2 ? HOLD_WRITE : 0) | (made ? HOLD_CREATED : 0);
5889
+ const handle = this.fs.hold?.(path, true, true, void 0, this.fs.owners ? asked : 0);
5890
+ const io = handle !== void 0 && this.fs.pinned ? this.fs.pinned(handle) : this.fs;
5891
+ const buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
5892
+ buffer.handle = handle;
5893
+ this.buffers.set(path, buffer);
5894
+ const id = this.identity(st);
5895
+ if (id !== void 0) this.know(buffer, id);
5896
+ return buffer;
5897
+ }
5756
5898
  kernelFile(path, existing, oflags, rights, fdflags) {
5757
5899
  const { readable: readable2, writable: writable2 } = openAccess(existing, oflags, rights);
5758
5900
  const append = (fdflags & FDFLAGS.APPEND) !== 0;
5759
5901
  const flags = (writable2 ? readable2 ? O_RDWR4 : O_WRONLY4 : 0) | (append ? O_APPEND : 0);
5760
5902
  const made = !existing && this.createNew(path, oflags);
5761
5903
  const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
5762
- const fd = this.kernel.sys.openVfs(path, flags, 0, truncate ? { truncate } : {});
5904
+ const fd = this.kernel.sys.openVfs(path, flags, 0, {
5905
+ ...truncate ? { truncate } : {},
5906
+ ...made ? { created: true } : {}
5907
+ });
5763
5908
  const ino = writable2 ? this.openedIno(fd) ?? this.inoOf(path) : void 0;
5764
5909
  if (truncate) this.fs.touched?.(path, ino);
5765
5910
  this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append, path, ino });
@@ -6152,7 +6297,7 @@ function wrap(table) {
6152
6297
  }
6153
6298
  return out;
6154
6299
  }
6155
- var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
6300
+ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, AT_EACCESS2, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
6156
6301
  var init_wasi_host = __esm({
6157
6302
  "src/process/wasi/wasi-host.ts"() {
6158
6303
  "use strict";
@@ -6174,6 +6319,7 @@ var init_wasi_host = __esm({
6174
6319
  IDS = ["ruid", "euid", "suid", "rgid", "egid", "sgid"];
6175
6320
  NS_PER_MS = 1000000n;
6176
6321
  AT_SYMLINK_NOFOLLOW2 = 1;
6322
+ AT_EACCESS2 = 2;
6177
6323
  ROOT_IDS = Object.freeze({ uid: 0, gid: 0 });
6178
6324
  GONE = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
6179
6325
  S_IFIFO = 4096;
@@ -6301,6 +6447,18 @@ var init_wasi_host = __esm({
6301
6447
  const path = at(dirfd, p, l);
6302
6448
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW2) === 0), out);
6303
6449
  },
6450
+ path_access: (dirfd, p, l, amode, flags) => {
6451
+ const path = at(dirfd, p, l);
6452
+ const nofollow = (flags & AT_SYMLINK_NOFOLLOW2) !== 0;
6453
+ if (deviceOf(path)) {
6454
+ if (this.o.fs.owners && amode & 1) throw new WasiError("EACCES");
6455
+ return;
6456
+ }
6457
+ pathOwned(path, !nofollow);
6458
+ if (!this.o.fs.owners) return;
6459
+ const kind = flags & AT_EACCESS2 ? "eaccess" : "access";
6460
+ this.o.fs.access?.(path, amode & 7, kind, nofollow);
6461
+ },
6304
6462
  fd_chmod: (fd, mode) => void this.o.fs.chmod(pathOf(fd), mode & 4095),
6305
6463
  path_chmod: (dirfd, p, l, mode, flags) => void this.o.fs.chmod(target(at(dirfd, p, l), flags), mode & 4095),
6306
6464
  umask: (mask, out) => {
@@ -6825,6 +6983,8 @@ var init_wasi_host = __esm({
6825
6983
  return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
6826
6984
  }
6827
6985
  setTimes(path, atim, mtim, flags, follow2 = true) {
6986
+ const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
6987
+ if (this.o.fs.owners && (flags & asked) === 0) return;
6828
6988
  const now = Date.now();
6829
6989
  let current;
6830
6990
  const statOf = follow2 ? this.o.fs.stat.bind(this.o.fs) : this.o.fs.lstat.bind(this.o.fs);
@@ -6837,7 +6997,8 @@ var init_wasi_host = __esm({
6837
6997
  this.o.fs,
6838
6998
  path,
6839
6999
  pick(FSTFLAGS.ATIM, FSTFLAGS.ATIM_NOW, atim, "atimeMs"),
6840
- pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs")
7000
+ pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs"),
7001
+ (flags & (FSTFLAGS.ATIM | FSTFLAGS.MTIM)) === 0
6841
7002
  );
6842
7003
  }
6843
7004
  readdir(fd, buf, len, cookie, usedPtr) {
@@ -7601,10 +7762,10 @@ function procfsBridge(fs, tree) {
7601
7762
  ],
7602
7763
  () => fs.link(from, to, follow2)
7603
7764
  ),
7604
- hold: (p, held, open, handle) => {
7765
+ hold: (p, held, open, handle, want) => {
7605
7766
  if (handle !== void 0 && snapshots.delete(handle)) return void 0;
7606
7767
  if (!held) return fs.hold?.(p, held, open, handle);
7607
- return via(p, snapshot, () => fs.hold?.(p, held, open) ?? late(p));
7768
+ return via(p, snapshot, () => fs.hold?.(p, held, open, void 0, want) ?? late(p));
7608
7769
  },
7609
7770
  kept: (handle) => snapshots.has(handle) || fs.kept?.(handle) === true,
7610
7771
  pinned: (handle) => {