@ai-ecoverse/slicc-kernel 1.62.4 → 1.64.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,23 @@ 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
+ ["/", 493],
2969
+ ["/dev", 493],
2970
+ ["/dev/null", 438],
2971
+ ["/dev/zero", 438],
2972
+ ["/dev/full", 438],
2973
+ ["/dev/random", 438],
2974
+ ["/dev/urandom", 438],
2975
+ ["/dev/tty", 438],
2976
+ ["/dev/shm", 1023]
2977
+ ];
2852
2978
  }
2853
2979
  });
2854
2980
 
@@ -2936,7 +3062,7 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
2936
3062
  function deviceOfStream(stream) {
2937
3063
  const device2 = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2938
3064
  if (!device2 || stream.sliccKernelFd !== void 0) return void 0;
2939
- const access = ACCESS[stream.flags & O_ACCMODE2];
3065
+ const access = ACCESS[stream.flags & O_ACCMODE3];
2940
3066
  return { device: device2, ...access ? { access } : {} };
2941
3067
  }
2942
3068
  function inheritedSlot(fd, stream) {
@@ -2996,7 +3122,7 @@ function restoreForkedStreams(Fs, streams, table) {
2996
3122
  } else {
2997
3123
  const placed = place(
2998
3124
  Fs,
2999
- Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC2)),
3125
+ Fs.open(entry.path, entry.flags & ~(O_CREAT3 | O_EXCL2 | O_TRUNC3)),
3000
3126
  entry.fd
3001
3127
  );
3002
3128
  setCloseOnExec(placed, (entry.flags & O_CLOEXEC) !== 0);
@@ -3005,16 +3131,16 @@ function restoreForkedStreams(Fs, streams, table) {
3005
3131
  }
3006
3132
  }
3007
3133
  }
3008
- var O_RDWR, O_ACCMODE2, O_CREAT3, O_EXCL2, O_TRUNC2, PLACEHOLDER_DIR, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3134
+ var O_RDWR, O_ACCMODE3, O_CREAT3, O_EXCL2, O_TRUNC3, PLACEHOLDER_DIR, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3009
3135
  var init_process_fork = __esm({
3010
3136
  "src/process/process-fork.ts"() {
3011
3137
  "use strict";
3012
3138
  init_process_fds();
3013
3139
  O_RDWR = 2;
3014
- O_ACCMODE2 = 3;
3140
+ O_ACCMODE3 = 3;
3015
3141
  O_CREAT3 = 64;
3016
3142
  O_EXCL2 = 128;
3017
- O_TRUNC2 = 512;
3143
+ O_TRUNC3 = 512;
3018
3144
  PLACEHOLDER_DIR = "/dev/slicc-fd";
3019
3145
  ACCESS = { 0: "read", 1: "write" };
3020
3146
  DEVICES = {
@@ -4060,6 +4186,7 @@ function kernelSys(transport) {
4060
4186
  ...opts?.orphan ? { orphan: true } : {},
4061
4187
  ...opts?.truncate ? { truncate: true } : {},
4062
4188
  ...opts?.create ? { create: true } : {},
4189
+ ...opts?.created ? { created: true } : {},
4063
4190
  ...opts?.pin ? { pin: opts.pin } : {},
4064
4191
  ...opts?.handle !== void 0 ? { handle: opts.handle } : {}
4065
4192
  },
@@ -4183,7 +4310,7 @@ function wireKernelStdio(Fs, streams, sys) {
4183
4310
  const meta = kind === "device" || kind === "held" ? sys?.heldMeta?.(fd) : void 0;
4184
4311
  if (meta && openHeld(Fs, fd, meta)) continue;
4185
4312
  if (kind && PLACED.has(kind)) {
4186
- const flags = sys?.access ? stream.flags & ~O_ACCMODE3 | accessMode(sys.access(fd)) : stream.flags;
4313
+ const flags = sys?.access ? stream.flags & ~O_ACCMODE4 | accessMode(sys.access(fd)) : stream.flags;
4187
4314
  Fs.closeStream(fd);
4188
4315
  const kernel = { fd, kernel: fd, kind, flags };
4189
4316
  placeKernelStream(Fs, streams, kernel).flags = flags;
@@ -4228,6 +4355,9 @@ function reportGrowth(imports, publish) {
4228
4355
  function callerOwner(Fs, init) {
4229
4356
  return init.owners ? {} : { owner: ownByCaller(Fs, init.cred, credAbi(init.program.glue)) };
4230
4357
  }
4358
+ function utimensatOf(module) {
4359
+ return ownValue(module, "sliccSyscalls")?.utimensat;
4360
+ }
4231
4361
  async function runWasmProcess(init, port2, deps = {}) {
4232
4362
  const signals = new SignalGate(
4233
4363
  createSyncSabTransport(init.sab, port2, {
@@ -4295,11 +4425,9 @@ async function runWasmProcess(init, port2, deps = {}) {
4295
4425
  memory: () => memory,
4296
4426
  set: (mask) => void transport.call({ op: "proc-umask", mask }, Number.POSITIVE_INFINITY, "umask")
4297
4427
  });
4298
- noFollowUtimes(
4299
- imports,
4300
- () => ownValue(module, "FS"),
4301
- ownValue(module, "sliccSyscalls")?.utimensat
4302
- );
4428
+ const fsOf = () => ownValue(module, "FS");
4429
+ noFollowUtimes(imports, fsOf, utimensatOf(module), () => memory);
4430
+ kernelAccess(imports, fsOf, () => memory);
4303
4431
  const glue = ownValue(module, "sliccFdImports");
4304
4432
  syncFsync(imports, () => ownValue(module, "FS"), glue);
4305
4433
  positionalIo(imports, {
@@ -4337,6 +4465,7 @@ async function runWasmProcess(init, port2, deps = {}) {
4337
4465
  await initialized;
4338
4466
  const running = module;
4339
4467
  if (!hasStreams(running)) return runStdioOnly(running, init);
4468
+ if (init.owners) linuxDevices(running.FS);
4340
4469
  const vfs = mountVfsIntoEmscripten(running.FS, {
4341
4470
  bridge: createSyncFsSabBridge(transport, init.owners ? { owners: true } : {}),
4342
4471
  cwd: init.cwd,
@@ -4438,7 +4567,7 @@ function runMain(running, init) {
4438
4567
  return status2;
4439
4568
  }
4440
4569
  }
4441
- var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE3, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
4570
+ var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE4, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
4442
4571
  var init_process_runtime = __esm({
4443
4572
  "src/process/process-runtime.ts"() {
4444
4573
  "use strict";
@@ -4463,7 +4592,7 @@ var init_process_runtime = __esm({
4463
4592
  O_RDONLY = 0;
4464
4593
  O_WRONLY3 = 1;
4465
4594
  O_RDWR3 = 2;
4466
- O_ACCMODE3 = 3;
4595
+ O_ACCMODE4 = 3;
4467
4596
  O_DIRECTORY = 65536;
4468
4597
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY3 : O_RDWR3;
4469
4598
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket"]);
@@ -4791,9 +4920,10 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
4791
4920
  rmdir: (p) => mutating(() => bridge.rmdir(p)),
4792
4921
  symlink: (target, link) => mutating(() => bridge.symlink(target, link), ...entry(link)),
4793
4922
  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),
4923
+ utimes: (p, a, m, now2) => rewriting(p, () => bridge.utimes(p, a, m, now2)),
4924
+ lutimes: (p, a, m, now2) => mutating(() => bridge.lutimes(p, a, m, now2), p),
4796
4925
  ...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
4926
+ ...bridge.access ? { access: bridge.access.bind(bridge) } : {},
4797
4927
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
4798
4928
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
4799
4929
  ...bridge.pinned ? { pinned: (handle) => pinnedIo2(bridge, handle, rewriting) } : {},
@@ -5166,6 +5296,11 @@ function entryOf(info) {
5166
5296
  append: ((info.flags ?? 0) & O_APPEND) !== 0
5167
5297
  };
5168
5298
  }
5299
+ function wantOf2(oflags, rights) {
5300
+ const write2 = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
5301
+ const read2 = (rights & RIGHTS.FD_READ) !== 0n || !write2;
5302
+ return (read2 ? 4 : 0) | (write2 ? 2 : 0);
5303
+ }
5169
5304
  function openAccess(existing, oflags, rights) {
5170
5305
  const readonly = existing?.readonly === true;
5171
5306
  const mutating = readonly ? OFLAGS.TRUNC : OFLAGS.CREAT | OFLAGS.TRUNC;
@@ -5194,6 +5329,7 @@ var SYNTHETIC_DIRS2, O_NONBLOCK2, O_WRONLY4, O_RDWR4, O_APPEND, DEVICES2, WasiFd
5194
5329
  var init_wasi_fds = __esm({
5195
5330
  "src/process/wasi/wasi-fds.ts"() {
5196
5331
  "use strict";
5332
+ init_sync_fs_wire();
5197
5333
  init_wasi_abi();
5198
5334
  init_wasi_files();
5199
5335
  SYNTHETIC_DIRS2 = ["usr", "bin"];
@@ -5734,32 +5870,42 @@ var init_wasi_fds = __esm({
5734
5870
  buffer = void 0;
5735
5871
  }
5736
5872
  buffer ??= this.sharing(path, existing);
5873
+ const want = wantOf2(oflags, rights);
5737
5874
  if (buffer) {
5875
+ if (this.fs.owners) this.fs.access?.(path, want, "open");
5738
5876
  if (oflags & OFLAGS.TRUNC) buffer.truncate(0);
5739
5877
  } 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);
5878
+ buffer = this.freshBuffer(path, existing, oflags, want);
5752
5879
  }
5753
5880
  buffer.opens++;
5754
5881
  return new LocalFile(buffer, readable2, writable2, (fdflags & FDFLAGS.APPEND) !== 0);
5755
5882
  }
5883
+ freshBuffer(path, existing, oflags, want) {
5884
+ const made = !existing && this.createNew(path, oflags);
5885
+ const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
5886
+ if (existing?.ranged) this.fs.invalidate?.();
5887
+ const st = existing?.ranged || !existing ? this.fs.stat(path) : existing;
5888
+ const ranged = st.ranged ? st.size : void 0;
5889
+ const asked = (want & 4 ? HOLD_READ : 0) | (want & 2 ? HOLD_WRITE : 0) | (made ? HOLD_CREATED : 0);
5890
+ const handle = this.fs.hold?.(path, true, true, void 0, this.fs.owners ? asked : 0);
5891
+ const io = handle !== void 0 && this.fs.pinned ? this.fs.pinned(handle) : this.fs;
5892
+ const buffer = new FileBuffer(io, path, empty, st.maxFile, ranged, st.version);
5893
+ buffer.handle = handle;
5894
+ this.buffers.set(path, buffer);
5895
+ const id = this.identity(st);
5896
+ if (id !== void 0) this.know(buffer, id);
5897
+ return buffer;
5898
+ }
5756
5899
  kernelFile(path, existing, oflags, rights, fdflags) {
5757
5900
  const { readable: readable2, writable: writable2 } = openAccess(existing, oflags, rights);
5758
5901
  const append = (fdflags & FDFLAGS.APPEND) !== 0;
5759
5902
  const flags = (writable2 ? readable2 ? O_RDWR4 : O_WRONLY4 : 0) | (append ? O_APPEND : 0);
5760
5903
  const made = !existing && this.createNew(path, oflags);
5761
5904
  const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
5762
- const fd = this.kernel.sys.openVfs(path, flags, 0, truncate ? { truncate } : {});
5905
+ const fd = this.kernel.sys.openVfs(path, flags, 0, {
5906
+ ...truncate ? { truncate } : {},
5907
+ ...made ? { created: true } : {}
5908
+ });
5763
5909
  const ino = writable2 ? this.openedIno(fd) ?? this.inoOf(path) : void 0;
5764
5910
  if (truncate) this.fs.touched?.(path, ino);
5765
5911
  this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append, path, ino });
@@ -6152,7 +6298,7 @@ function wrap(table) {
6152
6298
  }
6153
6299
  return out;
6154
6300
  }
6155
- var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
6301
+ 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
6302
  var init_wasi_host = __esm({
6157
6303
  "src/process/wasi/wasi-host.ts"() {
6158
6304
  "use strict";
@@ -6174,6 +6320,7 @@ var init_wasi_host = __esm({
6174
6320
  IDS = ["ruid", "euid", "suid", "rgid", "egid", "sgid"];
6175
6321
  NS_PER_MS = 1000000n;
6176
6322
  AT_SYMLINK_NOFOLLOW2 = 1;
6323
+ AT_EACCESS2 = 2;
6177
6324
  ROOT_IDS = Object.freeze({ uid: 0, gid: 0 });
6178
6325
  GONE = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
6179
6326
  S_IFIFO = 4096;
@@ -6301,6 +6448,18 @@ var init_wasi_host = __esm({
6301
6448
  const path = at(dirfd, p, l);
6302
6449
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW2) === 0), out);
6303
6450
  },
6451
+ path_access: (dirfd, p, l, amode, flags) => {
6452
+ const path = at(dirfd, p, l);
6453
+ const nofollow = (flags & AT_SYMLINK_NOFOLLOW2) !== 0;
6454
+ if (deviceOf(path)) {
6455
+ if (this.o.fs.owners && amode & 1) throw new WasiError("EACCES");
6456
+ return;
6457
+ }
6458
+ pathOwned(path, !nofollow);
6459
+ if (!this.o.fs.owners) return;
6460
+ const kind = flags & AT_EACCESS2 ? "eaccess" : "access";
6461
+ this.o.fs.access?.(path, amode & 7, kind, nofollow);
6462
+ },
6304
6463
  fd_chmod: (fd, mode) => void this.o.fs.chmod(pathOf(fd), mode & 4095),
6305
6464
  path_chmod: (dirfd, p, l, mode, flags) => void this.o.fs.chmod(target(at(dirfd, p, l), flags), mode & 4095),
6306
6465
  umask: (mask, out) => {
@@ -6825,6 +6984,8 @@ var init_wasi_host = __esm({
6825
6984
  return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
6826
6985
  }
6827
6986
  setTimes(path, atim, mtim, flags, follow2 = true) {
6987
+ const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
6988
+ if (this.o.fs.owners && (flags & asked) === 0) return;
6828
6989
  const now = Date.now();
6829
6990
  let current;
6830
6991
  const statOf = follow2 ? this.o.fs.stat.bind(this.o.fs) : this.o.fs.lstat.bind(this.o.fs);
@@ -6837,7 +6998,8 @@ var init_wasi_host = __esm({
6837
6998
  this.o.fs,
6838
6999
  path,
6839
7000
  pick(FSTFLAGS.ATIM, FSTFLAGS.ATIM_NOW, atim, "atimeMs"),
6840
- pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs")
7001
+ pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs"),
7002
+ (flags & (FSTFLAGS.ATIM | FSTFLAGS.MTIM)) === 0
6841
7003
  );
6842
7004
  }
6843
7005
  readdir(fd, buf, len, cookie, usedPtr) {
@@ -7601,10 +7763,10 @@ function procfsBridge(fs, tree) {
7601
7763
  ],
7602
7764
  () => fs.link(from, to, follow2)
7603
7765
  ),
7604
- hold: (p, held, open, handle) => {
7766
+ hold: (p, held, open, handle, want) => {
7605
7767
  if (handle !== void 0 && snapshots.delete(handle)) return void 0;
7606
7768
  if (!held) return fs.hold?.(p, held, open, handle);
7607
- return via(p, snapshot, () => fs.hold?.(p, held, open) ?? late(p));
7769
+ return via(p, snapshot, () => fs.hold?.(p, held, open, void 0, want) ?? late(p));
7608
7770
  },
7609
7771
  kept: (handle) => snapshots.has(handle) || fs.kept?.(handle) === true,
7610
7772
  pinned: (handle) => {