@ai-ecoverse/slicc-kernel 1.92.0 → 1.93.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.
@@ -104,6 +104,13 @@ var init_lockdown = __esm({
104
104
  });
105
105
 
106
106
  // src/realm/sync-sab-wire.ts
107
+ function loadBlocked(header) {
108
+ return [Atomics.load(header, SAB_I_BLOCKED), Atomics.load(header, SAB_I_BLOCKED_HI)];
109
+ }
110
+ function storeBlocked(header, [low, high]) {
111
+ Atomics.store(header, SAB_I_BLOCKED_HI, high);
112
+ Atomics.store(header, SAB_I_BLOCKED, low);
113
+ }
107
114
  function loadU53(header, lo, hi) {
108
115
  return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
109
116
  }
@@ -146,7 +153,7 @@ function sabViews(sab) {
146
153
  window: new Uint8Array(sab, SAB_HEADER_BYTES)
147
154
  };
148
155
  }
149
- var SAB_HEADER_I32, SAB_CLOCK_OFFSET, SAB_CLOCK_I64, SAB_HEADER_BYTES, SAB_I_STATE, SAB_I_SEQ, SAB_I_STATUS, SAB_I_TOTAL, SAB_I_CHUNK, SAB_I_OFFSET, SAB_I_REQ, SAB_I_PUB, SAB_I_SIGNALS, SAB_I_TIMERS, SAB_I_MEMORY, SAB_I_TOTAL_HI, SAB_I_OFFSET_HI, SAB_I_KILLED, SAB_I_ASYNC, SAB_I_STOP, SAB_I_BLOCKED, U32, SAB_STATE_IDLE, SAB_STATE_PENDING, SAB_STATE_READY, SAB_STATUS_BYTES, SAB_STATUS_JSON, SAB_STATUS_VOID, SAB_STATUS_ERRNO, SAB_DEFAULT_WINDOW_BYTES, SAB_MIN_BYTES, SYNC_SAB_REQ_MSG, SYNC_SAB_NEXT_MSG, encoder, decoder;
156
+ var SAB_HEADER_I32, SAB_CLOCK_OFFSET, SAB_CLOCK_I64, SAB_HEADER_BYTES, SAB_I_STATE, SAB_I_SEQ, SAB_I_STATUS, SAB_I_TOTAL, SAB_I_CHUNK, SAB_I_OFFSET, SAB_I_REQ, SAB_I_PUB, SAB_I_SIGNALS, SAB_I_TIMERS, SAB_I_MEMORY, SAB_I_TOTAL_HI, SAB_I_OFFSET_HI, SAB_I_KILLED, SAB_I_ASYNC, SAB_I_STOP, SAB_I_BLOCKED, SAB_I_BLOCKED_HI, anyBlocked, U32, SAB_STATE_IDLE, SAB_STATE_PENDING, SAB_STATE_READY, SAB_STATUS_BYTES, SAB_STATUS_JSON, SAB_STATUS_VOID, SAB_STATUS_ERRNO, SAB_DEFAULT_WINDOW_BYTES, SAB_MIN_BYTES, SYNC_SAB_REQ_MSG, SYNC_SAB_NEXT_MSG, encoder, decoder;
150
157
  var init_sync_sab_wire = __esm({
151
158
  "src/realm/sync-sab-wire.ts"() {
152
159
  "use strict";
@@ -171,6 +178,8 @@ var init_sync_sab_wire = __esm({
171
178
  SAB_I_ASYNC = 14;
172
179
  SAB_I_STOP = 15;
173
180
  SAB_I_BLOCKED = 16;
181
+ SAB_I_BLOCKED_HI = 17;
182
+ anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
174
183
  U32 = 2 ** 32;
175
184
  SAB_STATE_IDLE = 0;
176
185
  SAB_STATE_PENDING = 1;
@@ -365,6 +374,73 @@ var init_signals = __esm({
365
374
  }
366
375
  });
367
376
 
377
+ // src/fs/types.ts
378
+ function normalizePath(path) {
379
+ const parts = [];
380
+ for (const part of path.split("/")) {
381
+ if (part === "" || part === ".") continue;
382
+ if (part === "..") parts.pop();
383
+ else parts.push(part);
384
+ }
385
+ return `/${parts.join("/")}`;
386
+ }
387
+ function inodeOf(path) {
388
+ let h1 = 3735928559;
389
+ let h2 = 1103547991;
390
+ for (let i = 0; i < path.length; i++) {
391
+ const c = path.charCodeAt(i);
392
+ h1 = Math.imul(h1 ^ c, 2654435761);
393
+ h2 = Math.imul(h2 ^ c, 1597334677);
394
+ }
395
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
396
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
397
+ return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
398
+ }
399
+ var init_types = __esm({
400
+ "src/fs/types.ts"() {
401
+ "use strict";
402
+ }
403
+ });
404
+
405
+ // src/fs/owners.ts
406
+ function inGroup(cred, gid) {
407
+ return cred.egid === gid || cred.groups.includes(gid);
408
+ }
409
+ var ROOT_OWNER;
410
+ var init_owners = __esm({
411
+ "src/fs/owners.ts"() {
412
+ "use strict";
413
+ init_types();
414
+ ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
415
+ }
416
+ });
417
+
418
+ // src/fs/walk.ts
419
+ var init_walk = __esm({
420
+ "src/fs/walk.ts"() {
421
+ "use strict";
422
+ init_types();
423
+ }
424
+ });
425
+
426
+ // src/fs/access.ts
427
+ function permits(cred, perm, want, directory = true) {
428
+ const mode = perm.mode ?? (directory ? 493 : 420);
429
+ if (cred.euid === 0) return (want & X_OK) === 0 || directory || (mode & 73) !== 0;
430
+ const shift = cred.euid === perm.uid ? 6 : inGroup(cred, perm.gid) ? 3 : 0;
431
+ return (mode >> shift & want) === want;
432
+ }
433
+ var X_OK;
434
+ var init_access = __esm({
435
+ "src/fs/access.ts"() {
436
+ "use strict";
437
+ init_owners();
438
+ init_types();
439
+ init_walk();
440
+ X_OK = 1;
441
+ }
442
+ });
443
+
368
444
  // src/fs/pages.ts
369
445
  var PAGE, READAHEAD, CLEAN_LIMIT, WRITEBACK, RUN, Pages;
370
446
  var init_pages = __esm({
@@ -619,34 +695,6 @@ var init_ranged = __esm({
619
695
  }
620
696
  });
621
697
 
622
- // src/fs/types.ts
623
- function normalizePath(path) {
624
- const parts = [];
625
- for (const part of path.split("/")) {
626
- if (part === "" || part === ".") continue;
627
- if (part === "..") parts.pop();
628
- else parts.push(part);
629
- }
630
- return `/${parts.join("/")}`;
631
- }
632
- function inodeOf(path) {
633
- let h1 = 3735928559;
634
- let h2 = 1103547991;
635
- for (let i = 0; i < path.length; i++) {
636
- const c = path.charCodeAt(i);
637
- h1 = Math.imul(h1 ^ c, 2654435761);
638
- h2 = Math.imul(h2 ^ c, 1597334677);
639
- }
640
- h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
641
- h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
642
- return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
643
- }
644
- var init_types = __esm({
645
- "src/fs/types.ts"() {
646
- "use strict";
647
- }
648
- });
649
-
650
698
  // src/process/wasi/wasi-abi.ts
651
699
  function wasiErrnoOf(code2) {
652
700
  if (!code2) return E.IO;
@@ -1071,12 +1119,21 @@ function createSyncFsSabBridge(transport, opts = {}) {
1071
1119
  lutimes: (path, atimeMs, mtimeMs, now) => {
1072
1120
  run({ op: "lutimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
1073
1121
  },
1074
- create: (path, mode) => {
1075
- run({ op: "create", path, ...mode !== void 0 ? { mode } : {} }, path);
1122
+ create: (path, mode, opening2) => {
1123
+ const flags = { ...mode !== void 0 ? { mode } : {}, ...opening2 ? { opening: opening2 } : {} };
1124
+ run({ op: "create", path, ...flags }, path);
1076
1125
  },
1077
- chown: (path, uid, gid, follow2) => {
1126
+ chown: (path, uid, gid, follow2, handle) => {
1078
1127
  const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
1079
- changing({ op: follow2 ? "chown" : "lchown", path, ...ids }, path);
1128
+ changing(
1129
+ {
1130
+ op: follow2 ? "chown" : "lchown",
1131
+ path,
1132
+ ...ids,
1133
+ ...handle !== void 0 ? { handle } : {}
1134
+ },
1135
+ path
1136
+ );
1080
1137
  },
1081
1138
  ...opts.owners ? { owners: true } : {},
1082
1139
  ...opts.links ? { links: true } : {},
@@ -1153,15 +1210,36 @@ function refusal(err) {
1153
1210
  function cachedStat(s, dir) {
1154
1211
  return s.stat !== void 0 && (!dir || s.statAt === syncCallCount());
1155
1212
  }
1213
+ function searchParents(Fs, node, bridge, call2) {
1214
+ const cred = Fs.sliccCred;
1215
+ if (!cred) return;
1216
+ let cur = node.parent;
1217
+ while (cur) {
1218
+ const st = cur.live.stat;
1219
+ if (st && st.uid !== void 0 && st.mode !== void 0) {
1220
+ const perm = { uid: st.uid, gid: st.gid ?? 0, mode: st.mode & 4095 };
1221
+ if (!permits(cred, perm, X_OK, true)) {
1222
+ call2(() => bridge.access?.(liveNodePath(cur), X_OK, "eaccess"));
1223
+ cur.live.stat = void 0;
1224
+ return;
1225
+ }
1226
+ } else {
1227
+ call2(() => bridge.access?.(liveNodePath(cur), X_OK, "eaccess"));
1228
+ return;
1229
+ }
1230
+ if (cur === cur.parent) break;
1231
+ cur = cur.parent;
1232
+ }
1233
+ }
1156
1234
  function linkedStates(bridgeOf) {
1157
1235
  const opens = /* @__PURE__ */ new Map();
1158
1236
  const byId = /* @__PURE__ */ new Map();
1159
- const idOf3 = (st) => st?.ino === void 0 || (st.nlink ?? 1) < 2 ? void 0 : `${st.dev}:${st.ino}`;
1237
+ const idOf4 = (st) => st?.ino === void 0 || (st.nlink ?? 1) < 2 ? void 0 : `${st.dev}:${st.ino}`;
1160
1238
  function know(s, id) {
1161
1239
  s.id = id;
1162
1240
  if (!byId.has(id)) byId.set(id, s);
1163
1241
  }
1164
- function opening(node, on) {
1242
+ function opening2(node, on) {
1165
1243
  const s = node.live;
1166
1244
  if (!on) {
1167
1245
  opens.delete(s);
@@ -1170,14 +1248,14 @@ function linkedStates(bridgeOf) {
1170
1248
  return;
1171
1249
  }
1172
1250
  opens.set(s, node);
1173
- const id = idOf3(s.stat);
1251
+ const id = idOf4(s.stat);
1174
1252
  if (id !== void 0) know(s, id);
1175
1253
  }
1176
1254
  function sharedWith(node) {
1177
1255
  const st = node.live.stat;
1178
1256
  if (st?.ino === void 0) return void 0;
1179
1257
  const id = `${st.dev}:${st.ino}`;
1180
- if (!byId.has(id) && idOf3(st) !== void 0) {
1258
+ if (!byId.has(id) && idOf4(st) !== void 0) {
1181
1259
  for (const [s2, other] of opens) {
1182
1260
  if (s2.id !== void 0 || s2.orphan) continue;
1183
1261
  let st2;
@@ -1185,7 +1263,7 @@ function linkedStates(bridgeOf) {
1185
1263
  st2 = bridgeOf(other).lstat(liveNodePath(other));
1186
1264
  } catch {
1187
1265
  }
1188
- const known = idOf3(st2);
1266
+ const known = idOf4(st2);
1189
1267
  if (known !== void 0) know(s2, known);
1190
1268
  }
1191
1269
  }
@@ -1193,7 +1271,7 @@ function linkedStates(bridgeOf) {
1193
1271
  return s && s !== node.live && !stale(s) ? s : void 0;
1194
1272
  }
1195
1273
  const holder = (node) => opens.get(node.live) ?? node;
1196
- return { opening, sharedWith, know, idOf: idOf3, holder };
1274
+ return { opening: opening2, sharedWith, know, idOf: idOf4, holder };
1197
1275
  }
1198
1276
  function createHelpers(Fs, ops) {
1199
1277
  const bridgeOf = (node) => node.mount.opts.bridge;
@@ -1415,7 +1493,9 @@ function createNodeOps(h) {
1415
1493
  const owned = bridgeOf(node).owners === true;
1416
1494
  if (owned && Fs.isLink(node.mode) && statOf(node).uid === void 0)
1417
1495
  node.live.stat = void 0;
1496
+ const cached = owned && cachedStat(node.live, Fs.isDir(node.mode));
1418
1497
  const st = statOf(node);
1498
+ if (cached) searchParents(Fs, node, bridgeOf(node), call2);
1419
1499
  const s = node.live;
1420
1500
  const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
1421
1501
  const mtime = new Date(st.mtimeMs ?? 0);
@@ -1478,7 +1558,7 @@ function createNodeOps(h) {
1478
1558
  if (masked !== DEFAULT_DIR_PERM) metadataCall(() => bridge.chmod(path, masked));
1479
1559
  } else if (Fs.isFile(mode)) {
1480
1560
  call2(
1481
- () => bridge.create ? bridge.create(path, perm) : bridge.writeFile(path, new Uint8Array(0))
1561
+ () => bridge.create ? bridge.create(path, perm, opening.get(h.Fs) > 0) : bridge.writeFile(path, new Uint8Array(0))
1482
1562
  );
1483
1563
  } else {
1484
1564
  throw new Fs.ErrnoError(wasiErrno("EPERM"));
@@ -1724,10 +1804,24 @@ function createStreamOps(h) {
1724
1804
  }
1725
1805
  };
1726
1806
  }
1807
+ function countOpens(Fs) {
1808
+ const { open } = Fs;
1809
+ if (typeof open !== "function" || opening.has(Fs)) return;
1810
+ opening.set(Fs, 0);
1811
+ Fs.open = function(...args) {
1812
+ opening.set(Fs, (opening.get(Fs) ?? 0) + 1);
1813
+ try {
1814
+ return open.apply(this, args);
1815
+ } finally {
1816
+ opening.set(Fs, (opening.get(Fs) ?? 1) - 1);
1817
+ }
1818
+ };
1819
+ }
1727
1820
  function createLiveVfsPlugin(Fs) {
1728
1821
  const mounts = /* @__PURE__ */ new Set();
1729
1822
  const ops = {};
1730
1823
  const h = createHelpers(Fs, ops);
1824
+ countOpens(Fs);
1731
1825
  const nodeOps = createNodeOps(h);
1732
1826
  const streamOps = createStreamOps(h);
1733
1827
  ops.node = nodeOps;
@@ -1860,12 +1954,12 @@ function liveRoot(Fs, bridge) {
1860
1954
  };
1861
1955
  }
1862
1956
  function crosses(Fs, from, to) {
1863
- const parentOf = (path) => Fs.lookupPath?.(path, { parent: true }).node;
1957
+ const parentOf2 = (path) => Fs.lookupPath?.(path, { parent: true }).node;
1864
1958
  const name2 = from.replace(/\/+$/, "").split("/").pop() ?? "";
1865
1959
  try {
1866
- const fromDir = parentOf(from);
1960
+ const fromDir = parentOf2(from);
1867
1961
  const node = fromDir && Fs.lookupNode?.(fromDir, name2);
1868
- const dir = parentOf(to);
1962
+ const dir = parentOf2(to);
1869
1963
  return !!node && !!dir && !!node.live !== !!dir.live;
1870
1964
  } catch {
1871
1965
  return false;
@@ -1929,6 +2023,25 @@ function guardRenames(Fs) {
1929
2023
  function idOf(value2) {
1930
2024
  return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
1931
2025
  }
2026
+ function chownHeld(Fs, node, s, uid, gid) {
2027
+ const bridge = node.mount.opts.bridge;
2028
+ const handle = s.handle;
2029
+ try {
2030
+ bridge.chown?.(liveNodePath(node), idOf(uid), idOf(gid), false, handle);
2031
+ } catch (err) {
2032
+ throw toErrno(Fs, err);
2033
+ }
2034
+ if (node.parent?.live) node.parent.live.listed = void 0;
2035
+ if (!s.orphan) {
2036
+ s.stat = void 0;
2037
+ return;
2038
+ }
2039
+ try {
2040
+ const st = bridge.keptStat?.(handle);
2041
+ if (st && s.stat) s.stat = { ...s.stat, uid: st.uid, gid: st.gid, mode: st.mode };
2042
+ } catch {
2043
+ }
2044
+ }
1932
2045
  function useLiveChown(Fs) {
1933
2046
  const chown = Fs.chown?.bind(Fs);
1934
2047
  if (!chown) return;
@@ -1947,8 +2060,10 @@ function useLiveChown(Fs) {
1947
2060
  if (!Fs.fchown || !getStreamChecked) return;
1948
2061
  Fs.fchown = (fd, uid, gid) => {
1949
2062
  const stream = getStreamChecked.call(Fs, fd);
1950
- const live = stream.node.live !== void 0;
1951
- const target = live || stream.path === void 0 ? stream.node : stream.path;
2063
+ const node = stream.node;
2064
+ const s = node.live;
2065
+ if (s?.handle !== void 0 && (!s.orphan || s.kept)) return chownHeld(Fs, node, s, uid, gid);
2066
+ const target = s !== void 0 || stream.path === void 0 ? stream.node : stream.path;
1952
2067
  Fs.chown(target, uid, gid);
1953
2068
  };
1954
2069
  }
@@ -2009,10 +2124,11 @@ function readingLinks(Fs) {
2009
2124
  }
2010
2125
  };
2011
2126
  }
2012
- var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, O_ACCMODE, O_TRUNC, O_PATH, stale;
2127
+ var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE, O_ACCMODE, O_TRUNC, O_PATH, stale, opening;
2013
2128
  var init_live_vfs_fs = __esm({
2014
2129
  "src/realm/live-vfs-fs.ts"() {
2015
2130
  "use strict";
2131
+ init_access();
2016
2132
  init_ranged();
2017
2133
  init_types();
2018
2134
  init_wasi_errno();
@@ -2031,6 +2147,7 @@ var init_live_vfs_fs = __esm({
2031
2147
  O_TRUNC = 512;
2032
2148
  O_PATH = 2097152;
2033
2149
  stale = (s) => !!s.orphan && !s.kept;
2150
+ opening = /* @__PURE__ */ new WeakMap();
2034
2151
  }
2035
2152
  });
2036
2153
 
@@ -2054,6 +2171,22 @@ function topLevelDirs(bridge, warn) {
2054
2171
  }
2055
2172
  return dirs;
2056
2173
  }
2174
+ function linuxRmdir(Fs) {
2175
+ const raw = Fs;
2176
+ const { mayDelete, lookupNode } = raw;
2177
+ if (!mayDelete || !lookupNode) return;
2178
+ raw.mayDelete = (dir, name2, isdir) => {
2179
+ const code2 = mayDelete.call(raw, dir, name2, isdir);
2180
+ if (code2 !== 10 || !isdir) return code2;
2181
+ try {
2182
+ const node = lookupNode.call(raw, dir, name2);
2183
+ if (node === node.parent) return 10;
2184
+ } catch {
2185
+ return code2;
2186
+ }
2187
+ return 0;
2188
+ };
2189
+ }
2057
2190
  function mountVfsIntoEmscripten(Fs, deps) {
2058
2191
  const { bridge, warn } = deps;
2059
2192
  const dirs = topLevelDirs(bridge, warn);
@@ -2061,6 +2194,8 @@ function mountVfsIntoEmscripten(Fs, deps) {
2061
2194
  if (dirs) liveRoot(Fs, bridge);
2062
2195
  if (bridge.owners && Fs.lookupPath) useLiveChown(Fs);
2063
2196
  if (bridge.links && Fs.lookupPath) readingLinks(Fs);
2197
+ linuxRmdir(Fs);
2198
+ if (deps.cred) Fs.sliccCred = deps.cred;
2064
2199
  try {
2065
2200
  Fs.chdir(deps.cwd);
2066
2201
  } catch (err) {
@@ -2083,309 +2218,1231 @@ var init_emscripten_vfs_hook = __esm({
2083
2218
  }
2084
2219
  });
2085
2220
 
2086
- // src/process/kernel-streams.ts
2087
- function isPtyPath(path) {
2088
- return PTY_PATH.test(path);
2221
+ // src/fs/dev-removal.ts
2222
+ function inDevTree(path) {
2223
+ return path === "/dev" || path.startsWith("/dev/");
2089
2224
  }
2090
- function ptyStat(path) {
2091
- const n = PTY_PATH.exec(path)?.[1];
2092
- const now = /* @__PURE__ */ new Date();
2093
- return {
2094
- dev: 22,
2095
- ino: n === void 0 ? 2 : 3 + Number(n),
2096
- mode: n === void 0 ? 8630 : 8592,
2097
- nlink: 1,
2098
- uid: 1e3,
2099
- gid: 1e3,
2100
- rdev: n === void 0 ? 5 << 8 | 2 : 136 << 8 | Number(n),
2101
- size: 0,
2102
- blksize: 4096,
2103
- blocks: 0,
2104
- atime: now,
2105
- mtime: now,
2106
- ctime: now
2107
- };
2225
+ function devRemoval(path, cred) {
2226
+ if (!inDevTree(path)) return void 0;
2227
+ if (cred && cred.euid !== 0) return "EACCES";
2228
+ return path === "/dev" ? "EBUSY" : "EPERM";
2108
2229
  }
2109
- function sealedStat(minor = 250) {
2110
- const now = /* @__PURE__ */ new Date();
2111
- return {
2112
- dev: 22,
2113
- ino: 1,
2114
- mode: 8630,
2115
- nlink: 1,
2116
- uid: 0,
2117
- gid: 0,
2118
- rdev: 10 << 8 | minor,
2119
- size: 0,
2120
- blksize: 4096,
2121
- blocks: 0,
2122
- atime: now,
2123
- mtime: now,
2124
- ctime: now
2230
+ var init_dev_removal = __esm({
2231
+ "src/fs/dev-removal.ts"() {
2232
+ "use strict";
2233
+ }
2234
+ });
2235
+
2236
+ // src/process/process-pty.ts
2237
+ function failed(e) {
2238
+ const code2 = e?.code;
2239
+ if (typeof code2 === "string") return -wasiErrno(code2);
2240
+ throw e;
2241
+ }
2242
+ function ptyIoctl(ioctl, deps) {
2243
+ return (fd, op, varargs) => {
2244
+ const request = op >>> 0;
2245
+ if (request !== TIOCGPTN && request !== TIOCSPTLCK && request !== TIOCSCTTY && request !== TIOCSWINSZ && request !== TIOCPKT) {
2246
+ return ioctl(fd, op, varargs);
2247
+ }
2248
+ const stream = deps.fs()?.getStream(fd);
2249
+ const kfd = stream?.sliccKernelFd;
2250
+ if (kfd === void 0) return ioctl(fd, op, varargs);
2251
+ const heap = deps.heap();
2252
+ if (!heap) return -wasiErrno("EFAULT");
2253
+ const argp = (heap[varargs >> 2] ?? 0) >>> 0;
2254
+ try {
2255
+ return answer(request, kfd, argp, heap, deps.kernel);
2256
+ } catch (e) {
2257
+ return failed(e);
2258
+ }
2125
2259
  };
2126
2260
  }
2127
- function nonblocking(stream) {
2128
- return (stream.flags & O_NONBLOCK) !== 0 ? { nonblock: true } : void 0;
2261
+ function answer(request, kfd, argp, heap, kernel) {
2262
+ switch (request) {
2263
+ case TIOCGPTN:
2264
+ heap[argp >> 2] = kernel.ptyNumber(kfd);
2265
+ return 0;
2266
+ case TIOCSPTLCK:
2267
+ kernel.ptyLock(kfd, (heap[argp >> 2] ?? 0) !== 0);
2268
+ return 0;
2269
+ case TIOCSCTTY:
2270
+ kernel.setControllingTerminal(kfd);
2271
+ return 0;
2272
+ case TIOCPKT:
2273
+ kernel.setPacketMode(kfd, (heap[argp >> 2] ?? 0) !== 0);
2274
+ return 0;
2275
+ default: {
2276
+ const word = heap[argp >> 2] ?? 0;
2277
+ kernel.setWinsize(kfd, word & 65535, word >>> 16 & 65535);
2278
+ return 0;
2279
+ }
2280
+ }
2129
2281
  }
2130
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH, STRERROR, CLIPBOARD_PATH, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
2131
- var init_kernel_streams = __esm({
2132
- "src/process/kernel-streams.ts"() {
2282
+ var TIOCGPTN, TIOCSPTLCK, TIOCSCTTY, TIOCSWINSZ, TIOCPKT;
2283
+ var init_process_pty = __esm({
2284
+ "src/process/process-pty.ts"() {
2133
2285
  "use strict";
2134
2286
  init_wasi_errno();
2135
- POLLIN = 1;
2136
- POLLOUT = 4;
2137
- POLLERR = 8;
2138
- POLLHUP = 16;
2139
- POLLRDNORM = 64;
2140
- POLLWRNORM = 256;
2141
- TCSETSF = 21508;
2142
- O_NONBLOCK = 2048;
2143
- SOCKET_MODE = 49663;
2144
- PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
2145
- TTY_PATH = /^\/dev\/tty\d+$/;
2146
- TTY_NAME = /^tty\d+$/;
2147
- SEALED_PATH = "/dev/sealed";
2148
- STRERROR = {
2149
- EACCES: "Permission denied",
2150
- EIO: "I/O error",
2151
- ENOTSUP: "Not supported",
2152
- EOPNOTSUPP: "Not supported",
2153
- EFBIG: "File too large",
2154
- EILSEQ: "Illegal byte sequence",
2155
- EINTR: "Interrupted system call"
2287
+ TIOCGPTN = 2147767344;
2288
+ TIOCSPTLCK = 1074025521;
2289
+ TIOCSCTTY = 21518;
2290
+ TIOCSWINSZ = 21524;
2291
+ TIOCPKT = 21536;
2292
+ }
2293
+ });
2294
+
2295
+ // src/process/process-fds.ts
2296
+ function closesOnExec(stream) {
2297
+ return stream.sliccCloexec === true;
2298
+ }
2299
+ function setCloseOnExec(stream, on) {
2300
+ if (on) stream.sliccCloexec = true;
2301
+ else delete stream.sliccCloexec;
2302
+ }
2303
+ function trackCloseOnExec(Fs) {
2304
+ if (tracked.has(Fs)) return;
2305
+ tracked.add(Fs);
2306
+ if (typeof Fs.dupStream === "function") {
2307
+ const dupStream = Fs.dupStream.bind(Fs);
2308
+ Fs.dupStream = (stream, fd) => {
2309
+ const copy2 = dupStream(stream, fd);
2310
+ setCloseOnExec(copy2, false);
2311
+ return copy2;
2156
2312
  };
2157
- CLIPBOARD_PATH = "/dev/clipboard";
2158
- O_CREAT = 64;
2159
- O_EXCL = 128;
2160
- O_NOCTTY = 256;
2161
- O_TRUNC2 = 512;
2162
- KILLED_BY_SIGPIPE = 128 + 13;
2163
- ProcessExit = class extends Error {
2164
- status;
2165
- constructor(status2) {
2166
- super(`exit ${status2}`);
2167
- this.status = status2;
2168
- }
2313
+ }
2314
+ if (typeof Fs.open === "function") {
2315
+ const open = Fs.open.bind(Fs);
2316
+ Fs.open = (path, flags, mode) => {
2317
+ const cloexec = typeof flags === "number" && (flags & O_CLOEXEC) !== 0;
2318
+ const stream = open(path, cloexec ? flags & ~O_CLOEXEC : flags, mode);
2319
+ setCloseOnExec(stream, cloexec);
2320
+ return stream;
2169
2321
  };
2170
- SyscallError = class extends Error {
2171
- code;
2172
- constructor(code2) {
2173
- super(code2);
2174
- this.code = code2;
2322
+ }
2323
+ }
2324
+ function marker(deps) {
2325
+ return (fd, on) => {
2326
+ const stream = deps.fs()?.getStream(fd);
2327
+ if (stream) setCloseOnExec(stream, on);
2328
+ };
2329
+ }
2330
+ function cloexecFcntl(fcntl, deps) {
2331
+ const mark = marker(deps);
2332
+ return (fd, cmd, varargs) => {
2333
+ if (cmd === F_DUPFD_CLOEXEC) {
2334
+ const copy2 = fcntl(fd, F_DUPFD, varargs);
2335
+ if (copy2 >= 0) mark(copy2, true);
2336
+ return copy2;
2337
+ }
2338
+ if (cmd === F_GETFL) {
2339
+ const flags = fcntl(fd, cmd, varargs);
2340
+ return flags < 0 ? flags : flags & ~O_CLOEXEC;
2341
+ }
2342
+ if (cmd !== F_GETFD && cmd !== F_SETFD) return fcntl(fd, cmd, varargs);
2343
+ const stream = deps.fs()?.getStream(fd);
2344
+ if (!stream) return -wasiErrno("EBADF");
2345
+ if (cmd === F_GETFD) return closesOnExec(stream) ? FD_CLOEXEC : 0;
2346
+ const arg = deps.heap()?.[varargs >> 2];
2347
+ if (arg === void 0) return -wasiErrno("EINVAL");
2348
+ setCloseOnExec(stream, (arg & FD_CLOEXEC) !== 0);
2349
+ return 0;
2350
+ };
2351
+ }
2352
+ function cloexecPipe2(pipe2, deps) {
2353
+ const mark = marker(deps);
2354
+ return (fdPtr, flags) => {
2355
+ const r = pipe2(fdPtr, flags & ~O_CLOEXEC);
2356
+ const heap = deps.heap();
2357
+ if (r === 0 && flags & O_CLOEXEC && heap) {
2358
+ mark(heap[fdPtr >> 2], true);
2359
+ mark(heap[(fdPtr >> 2) + 1], true);
2360
+ }
2361
+ return r;
2362
+ };
2363
+ }
2364
+ function quietTarget(dup3, deps) {
2365
+ return (fd = -1, newfd = -1, flags = 0, ...rest2) => {
2366
+ const Fs = deps.fs();
2367
+ const target = fd === newfd || flags !== 0 ? void 0 : Fs?.getStream(newfd);
2368
+ if (target && Fs?.getStream(fd)) {
2369
+ try {
2370
+ Fs.close?.(target);
2371
+ } catch {
2175
2372
  }
2373
+ }
2374
+ return dup3(fd, newfd, flags, ...rest2);
2375
+ };
2376
+ }
2377
+ function cloexecByFlag(syscall, flagArg, deps) {
2378
+ const mark = marker(deps);
2379
+ return (...args) => {
2380
+ const cloexec = ((args[flagArg] ?? 0) & O_CLOEXEC) !== 0;
2381
+ if (cloexec) args[flagArg] = args[flagArg] & ~O_CLOEXEC;
2382
+ const fd = syscall(...args);
2383
+ if (fd >= 0) mark(fd, cloexec);
2384
+ return fd;
2385
+ };
2386
+ }
2387
+ function wrapperFactories(deps) {
2388
+ const { pty, timer } = deps;
2389
+ return {
2390
+ ...timer ? { setitimer: (f) => kernelTimer(f, timer) } : {},
2391
+ fcntl: (f) => cloexecFcntl(f, deps),
2392
+ pipe2: (f) => cloexecPipe2(f, deps),
2393
+ dup3: (f) => cloexecByFlag(quietTarget(f, deps), 2, deps),
2394
+ socket: (f) => cloexecByFlag(f, 1, deps),
2395
+ accept4: (f) => cloexecByFlag(f, 3, deps),
2396
+ ...pty ? { ioctl: (f) => ptyIoctl(f, { fs: deps.fs, heap: deps.heap, kernel: pty }) } : {}
2397
+ };
2398
+ }
2399
+ function kernelTimer(setitimer, timer) {
2400
+ return (which, ms) => {
2401
+ if (which !== 0) return setitimer(which, ms);
2402
+ timer.arm(ms ?? 0);
2403
+ return 0;
2404
+ };
2405
+ }
2406
+ function syscallOf(glue, name2, value2) {
2407
+ const names = Object.keys(IMPORT_NAMES);
2408
+ const own = names.find((key) => glue[key] !== void 0 && glue[key] === value2);
2409
+ if (own) return own;
2410
+ return typeof value2 === "function" ? names.find((key) => glue[key] !== void 0 && IMPORT_NAMES[key] === name2) : void 0;
2411
+ }
2412
+ function wrapCloexecSyscalls(imports, glue, deps) {
2413
+ if (!glue) return;
2414
+ const factories = wrapperFactories(deps);
2415
+ const seen = /* @__PURE__ */ new Set();
2416
+ for (const namespace of Object.values(imports)) {
2417
+ if (!namespace || typeof namespace !== "object" || seen.has(namespace)) continue;
2418
+ seen.add(namespace);
2419
+ for (const [name2, value2] of Object.entries(namespace)) {
2420
+ const key = syscallOf(glue, name2, value2);
2421
+ const wrap2 = key && factories[key];
2422
+ if (wrap2) namespace[name2] = wrap2(value2);
2423
+ }
2424
+ }
2425
+ }
2426
+ function pathOpensLinks(Fs) {
2427
+ const fs = Fs;
2428
+ const { mayOpen, isLink } = fs;
2429
+ if (!mayOpen || !isLink) return;
2430
+ fs.mayOpen = (node, flags) => flags & O_PATH2 && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2431
+ }
2432
+ function importKey(namespace, name2, glue) {
2433
+ const own = glue?.[name2];
2434
+ if (typeof own === "function") {
2435
+ const found = Object.keys(namespace).find((k) => namespace[k] === own);
2436
+ if (found !== void 0) return found;
2437
+ }
2438
+ const literal = LITERALS[name2];
2439
+ return typeof namespace[literal] === "function" ? literal : void 0;
2440
+ }
2441
+ function wrapImport(imports, name2, glue, wrap2, optional = false) {
2442
+ let wrapped = false;
2443
+ for (const ns of namespaces(imports)) {
2444
+ const key = importKey(ns, name2, glue);
2445
+ if (key === void 0) continue;
2446
+ ns[key] = wrap2(ns[key]);
2447
+ wrapped = true;
2448
+ }
2449
+ if (!wrapped && !optional && typeof glue?.[name2] === "function") {
2450
+ throw new Error(`slicc-kernel cannot find the glue's ${LITERALS[name2]} among its imports`);
2451
+ }
2452
+ }
2453
+ function kernelUmask(imports, deps) {
2454
+ let umask = deps.initial & 511;
2455
+ const { glue } = deps;
2456
+ wrapImport(imports, "openat", glue, (openat) => (dirfd, path, flags, varargs) => {
2457
+ const memory = deps.memory();
2458
+ if (flags & O_CREAT && varargs && memory) new Int32Array(memory.buffer)[varargs >> 2] &= ~umask;
2459
+ return openat(dirfd, path, flags, varargs);
2460
+ });
2461
+ wrapImport(
2462
+ imports,
2463
+ "mkdirat",
2464
+ glue,
2465
+ (mkdirat) => (dirfd, path, mode) => mkdirat(dirfd, path, mode & ~umask)
2466
+ );
2467
+ wrapImport(
2468
+ imports,
2469
+ "mknodat",
2470
+ glue,
2471
+ (mknodat) => (dirfd, path, mode, dev) => mknodat(dirfd, path, mode & ~umask, dev)
2472
+ );
2473
+ wrapImport(imports, "umask", glue, (own) => {
2474
+ own(umask);
2475
+ return (mask) => {
2476
+ const old = umask;
2477
+ umask = mask & 511;
2478
+ own(umask);
2479
+ deps.set(umask);
2480
+ return old;
2176
2481
  };
2177
- KernelStreams = class {
2178
- refs = /* @__PURE__ */ new Map();
2179
- socketRoot;
2180
- sockets = 0;
2181
- descriptions = /* @__PURE__ */ new Map();
2182
- described = 0;
2183
- Fs;
2184
- sys;
2185
- options;
2186
- constructor(Fs, sys, options = {}) {
2187
- this.Fs = Fs;
2188
- this.sys = sys;
2189
- this.options = options;
2190
- }
2191
- attach(stream, kfd, terminal) {
2192
- this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
2193
- stream.sliccKernelFd = kfd;
2194
- stream.stream_ops = this.ops(kfd, stream.stream_ops);
2195
- if (terminal ?? this.sys.isatty?.(kfd) ?? false) stream.tty = this.ttyOps(kfd);
2196
- else delete stream.tty;
2197
- }
2198
- attachSocket(stream, kfd) {
2199
- this.attach(stream, kfd, false);
2200
- stream.sliccKernelSocket = true;
2201
- }
2202
- socketStream(flags) {
2203
- const fs = this.Fs;
2204
- if (!fs.mount || !fs.createNode || !fs.createStream) {
2205
- const stream = this.Fs.open("/dev/null", 2);
2206
- stream.flags = flags;
2207
- return stream;
2208
- }
2209
- const createNode = fs.createNode;
2210
- this.socketRoot ??= fs.mount({ mount: () => createNode(null, "/", 16895, 0) }, {}, null);
2211
- const ino = ++this.sockets;
2212
- const node = fs.createNode(this.socketRoot, `socket:${ino}`, SOCKET_MODE, 0);
2213
- const now = /* @__PURE__ */ new Date();
2214
- const stat = { dev: 0, ino, mode: SOCKET_MODE, nlink: 1, uid: 0, gid: 0, rdev: 0, size: 0 };
2215
- const times = { atime: now, mtime: now, ctime: now, blksize: 4096, blocks: 0 };
2216
- node.node_ops = { getattr: () => ({ ...stat, ...times }) };
2217
- return fs.createStream({ node, flags, seekable: false, position: 0, stream_ops: {} });
2482
+ });
2483
+ }
2484
+ function touching(times, memory) {
2485
+ if (times === 0) return true;
2486
+ if (!memory) return false;
2487
+ const heap = new Int32Array(memory.buffer);
2488
+ const nsec = [heap[times + 8 >> 2], heap[times + 24 >> 2]];
2489
+ return nsec.every((n) => n === UTIME_NOW || n === UTIME_OMIT);
2490
+ }
2491
+ function touch(Fs, on, run) {
2492
+ if (!Fs || !on) return run();
2493
+ Fs.sliccTouch = true;
2494
+ try {
2495
+ return run();
2496
+ } finally {
2497
+ Fs.sliccTouch = void 0;
2498
+ }
2499
+ }
2500
+ function noFollowUtimes(imports, fs, glue, memory = () => void 0) {
2501
+ wrapImport(
2502
+ imports,
2503
+ "utimensat",
2504
+ { utimensat: glue },
2505
+ (utimensat) => (dirfd, path, times, flags) => {
2506
+ const Fs = fs();
2507
+ const on = touching(times, memory());
2508
+ const { utime, lookupPath, ErrnoError } = Fs ?? {};
2509
+ if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW) || !utime || !lookupPath || !ErrnoError) {
2510
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2218
2511
  }
2219
- nameTerminal(stream) {
2220
- const kfd = stream.sliccKernelFd;
2221
- if (!stream.tty || kfd === void 0) return;
2222
- const name2 = this.sys.ttyName?.(kfd);
2223
- if (name2) this.nameStream(stream, name2);
2512
+ Fs.utime = (at, atime, mtime) => {
2513
+ const { node } = lookupPath.call(Fs, at, { follow: false });
2514
+ if (!node.node_ops.setattr) throw new ErrnoError(EMSCRIPTEN_EPERM);
2515
+ node.node_ops.setattr(node, { atime, mtime });
2516
+ };
2517
+ try {
2518
+ return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2519
+ } finally {
2520
+ Fs.utime = utime;
2224
2521
  }
2225
- nameStream(stream, name2) {
2226
- stream.path = name2;
2227
- this.ttyNode(name2);
2228
- if (typeof this.Fs.stat !== "function") return;
2229
- stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name2) ?? {} };
2522
+ }
2523
+ );
2524
+ }
2525
+ function errnoOf(err) {
2526
+ const { errno: errno2, code: code2 } = err ?? {};
2527
+ if (typeof errno2 === "number") return errno2;
2528
+ if (typeof code2 === "string") return wasiErrno(code2);
2529
+ throw err;
2530
+ }
2531
+ function persistsItself(stream) {
2532
+ const type = stream.node.mount?.type;
2533
+ return typeof type?.syncfs === "function";
2534
+ }
2535
+ function namespaces(imports) {
2536
+ const seen = /* @__PURE__ */ new Set();
2537
+ for (const namespace of Object.values(imports)) {
2538
+ if (namespace && typeof namespace === "object") seen.add(namespace);
2539
+ }
2540
+ return [...seen];
2541
+ }
2542
+ function keyOf(namespace, name2, glue) {
2543
+ const own = glue?.[name2];
2544
+ const found = typeof own === "function" ? Object.keys(namespace).find((k) => namespace[k] === own) : void 0;
2545
+ return found ?? (typeof namespace[name2] === "function" ? name2 : void 0);
2546
+ }
2547
+ function syncFsync(imports, fs, glue) {
2548
+ for (const namespace of namespaces(imports)) {
2549
+ const key = keyOf(namespace, "fd_sync", glue);
2550
+ const original = key === void 0 ? void 0 : namespace[key];
2551
+ if (key === void 0 || !original?.isAsync) continue;
2552
+ namespace[key] = (fd) => {
2553
+ const stream = fs()?.getStream(fd);
2554
+ if (!stream) return EBADF;
2555
+ if (persistsItself(stream)) return original(fd);
2556
+ try {
2557
+ const result = stream.stream_ops.fsync?.(stream);
2558
+ return typeof result === "number" ? result : 0;
2559
+ } catch (err) {
2560
+ return errnoOf(err);
2230
2561
  }
2231
- nameDevice(stream, kind) {
2232
- this.nameStream(stream, kind === "sealed" ? SEALED_PATH : CLIPBOARD_PATH);
2562
+ };
2563
+ }
2564
+ }
2565
+ function offsetOf(rest2) {
2566
+ const at = rest2.length >= 3 ? Number(rest2[1]) * 2 ** 32 + (Number(rest2[0]) >>> 0) : Number(BigInt.asIntN(64, BigInt(rest2[0])));
2567
+ return at >= 0 && Number.isSafeInteger(at) ? at : void 0;
2568
+ }
2569
+ function readInto(sys, kfd, target, at) {
2570
+ let done = 0;
2571
+ while (done < target.length) {
2572
+ const got = sys.pread?.(kfd, target.length - done, at + done) ?? new Uint8Array(0);
2573
+ if (got.length === 0) break;
2574
+ target.set(got, done);
2575
+ done += got.length;
2576
+ }
2577
+ return done;
2578
+ }
2579
+ function positioned(original, write2, deps) {
2580
+ return (fd, iov, iovcnt, ...rest2) => {
2581
+ const stream = deps.fs()?.getStream(Number(fd));
2582
+ const memory = deps.memory();
2583
+ const kfd = stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
2584
+ if (kfd === void 0 || !memory || !(write2 ? deps.sys.pwrite : deps.sys.pread)) {
2585
+ return original(fd, iov, iovcnt, ...rest2);
2586
+ }
2587
+ const at = offsetOf(rest2);
2588
+ if (at === void 0) return wasiErrno("EINVAL");
2589
+ const view = new DataView(memory.buffer);
2590
+ let done = 0;
2591
+ try {
2592
+ for (let i = 0; i < Number(iovcnt); i++) {
2593
+ const ptr = view.getUint32(Number(iov) + i * 8, true);
2594
+ const len = view.getUint32(Number(iov) + i * 8 + 4, true);
2595
+ const part = new Uint8Array(memory.buffer, ptr, len);
2596
+ const moved = write2 ? deps.sys.pwrite?.(kfd, part.slice(), at + done) ?? 0 : readInto(deps.sys, kfd, part, at + done);
2597
+ done += moved;
2598
+ if (moved < len) break;
2233
2599
  }
2234
- listSealed() {
2235
- const fs = this.Fs;
2236
- const { analyzePath, mkdev, makedev, registerDevice } = fs;
2237
- if (!analyzePath || !mkdev || !makedev) return;
2238
- const nodes = [
2239
- [SEALED_PATH, 250, this.sys.openSealed],
2240
- [CLIPBOARD_PATH, 251, this.sys.openClipboard]
2241
- ];
2242
- for (const [path, minor, opener] of nodes) {
2243
- if (!opener) continue;
2244
- const dev = makedev.call(fs, 10, minor);
2245
- registerDevice?.call(fs, dev, {
2246
- open: (stream) => this.openNode(stream, path, opener)
2247
- });
2248
- if (analyzePath.call(fs, path).exists) continue;
2249
- try {
2250
- const node = mkdev.call(fs, path, dev);
2251
- if (typeof node === "object" && node !== null) {
2252
- const made = node;
2253
- made.node_ops = { ...made.node_ops, getattr: () => sealedStat(minor) };
2254
- }
2255
- } catch {
2256
- }
2257
- }
2600
+ } catch (err) {
2601
+ return errnoOf(err);
2602
+ }
2603
+ view.setUint32(Number(rest2[rest2.length - 1]), done, true);
2604
+ return 0;
2605
+ };
2606
+ }
2607
+ function positionalIo(imports, deps) {
2608
+ for (const namespace of namespaces(imports)) {
2609
+ for (const [name2, write2] of [
2610
+ ["fd_pread", false],
2611
+ ["fd_pwrite", true]
2612
+ ]) {
2613
+ const key = keyOf(namespace, name2, deps.glue);
2614
+ if (key !== void 0) {
2615
+ namespace[key] = positioned(namespace[key], write2, deps);
2258
2616
  }
2259
- openNode(stream, path, opener) {
2260
- let kfd;
2261
- try {
2262
- kfd = this.call(() => opener.call(this.sys, stream.flags & 3));
2263
- } catch (e) {
2264
- this.Fs.closeStream(stream.fd);
2265
- throw e;
2617
+ }
2618
+ }
2619
+ }
2620
+ function staging(Fs, length) {
2621
+ try {
2622
+ return new Uint8Array(length);
2623
+ } catch {
2624
+ throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
2625
+ }
2626
+ }
2627
+ function useFileMmap(Fs, deps) {
2628
+ const fs = Fs;
2629
+ const mmap = fs.mmap;
2630
+ if (typeof mmap !== "function") return;
2631
+ fs.mmap = (stream, length, position, prot, flags) => {
2632
+ const memalign = deps.memalign();
2633
+ const memory = deps.memory();
2634
+ const shared = (flags & MAP_TYPE) !== MAP_PRIVATE && (prot & PROT_WRITE) !== 0;
2635
+ const kfd = stream.sliccKernelFile ? stream.sliccKernelFd : void 0;
2636
+ if (shared && kfd !== void 0) throw new Fs.ErrnoError(wasiErrno("ENODEV"));
2637
+ if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE2) === O_WRONLY || !Fs.isFile(stream.node.mode)) {
2638
+ return mmap.call(fs, stream, length, position, prot, flags);
2639
+ }
2640
+ const data = staging(Fs, length);
2641
+ let done = 0;
2642
+ try {
2643
+ if (kfd !== void 0) done = readInto(deps.sys, kfd, data, position);
2644
+ else {
2645
+ for (let got = 1; done < length && got > 0; done += got) {
2646
+ got = Fs.read(stream, data, done, length - done, position + done);
2266
2647
  }
2267
- this.attach(stream, kfd, false);
2268
- this.nameStream(stream, path);
2269
- if (path === CLIPBOARD_PATH) this.reportClose(kfd);
2270
2648
  }
2271
- reporting = /* @__PURE__ */ new Set();
2272
- reportClose(kfd) {
2273
- this.reporting.add(kfd);
2649
+ } catch (err) {
2650
+ throw new Fs.ErrnoError(errnoOf(err));
2651
+ }
2652
+ const size = Math.ceil(length / MAP_ALIGN) * MAP_ALIGN;
2653
+ const ptr = memalign(MAP_ALIGN, size);
2654
+ if (!ptr) throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
2655
+ const target = new Uint8Array(memory.buffer, ptr, size);
2656
+ target.fill(0);
2657
+ target.set(data.subarray(0, done));
2658
+ return { ptr, allocated: true };
2659
+ };
2660
+ }
2661
+ function wasmMemory(instance, imports) {
2662
+ const isMemory = (v) => v instanceof WebAssembly.Memory;
2663
+ const exported = Object.values(instance.exports).find(isMemory);
2664
+ if (exported) return exported;
2665
+ for (const namespace of Object.values(imports)) {
2666
+ const found = Object.values(namespace ?? {}).find(isMemory);
2667
+ if (found) return found;
2668
+ }
2669
+ return void 0;
2670
+ }
2671
+ function absoluteOf(path, cwd) {
2672
+ const parts = [];
2673
+ for (const part of `${path.startsWith("/") ? "" : cwd}/${path}`.split("/")) {
2674
+ if (part === "" || part === ".") continue;
2675
+ if (part === "..") parts.pop();
2676
+ else parts.push(part);
2677
+ }
2678
+ return `/${parts.join("/")}`;
2679
+ }
2680
+ function fdOfPath(path, cwd) {
2681
+ const abs = absoluteOf(path, cwd);
2682
+ const std = ["/dev/stdin", "/dev/stdout", "/dev/stderr"].indexOf(abs);
2683
+ if (std >= 0) return std;
2684
+ const m = /^\/(?:dev|proc\/self)\/fd\/(\d+)$/.exec(abs);
2685
+ return m ? Number(m[1]) : void 0;
2686
+ }
2687
+ function syntheticAttr(mode, ino) {
2688
+ const now = /* @__PURE__ */ new Date();
2689
+ return {
2690
+ dev: 1,
2691
+ ino,
2692
+ mode,
2693
+ nlink: 1,
2694
+ uid: 0,
2695
+ gid: 0,
2696
+ rdev: 0,
2697
+ size: 0,
2698
+ atime: now,
2699
+ mtime: now,
2700
+ ctime: now,
2701
+ blksize: 4096,
2702
+ blocks: 0
2703
+ };
2704
+ }
2705
+ function describeFdDir(Fs) {
2706
+ let dir;
2707
+ try {
2708
+ dir = Fs.lookupPath?.("/proc/self/fd", { follow: true })?.node;
2709
+ } catch {
2710
+ return;
2711
+ }
2712
+ const ops = dir?.node_ops;
2713
+ const lookup2 = ops?.lookup;
2714
+ if (!dir || !lookup2 || ops.getattr) return;
2715
+ dir.node_ops = {
2716
+ ...ops,
2717
+ getattr: () => syntheticAttr(DIR_MODE, 1),
2718
+ lookup: (parent, name2) => {
2719
+ const entry = lookup2(parent, name2);
2720
+ entry.node_ops = {
2721
+ ...entry.node_ops,
2722
+ getattr: () => syntheticAttr(LINK_MODE, entry.id ?? 0)
2723
+ };
2724
+ return entry;
2725
+ }
2726
+ };
2727
+ }
2728
+ function useZeroDevices(Fs) {
2729
+ const { analyzePath, registerDevice, mkdev, makedev } = Fs;
2730
+ if (!analyzePath || !registerDevice || !mkdev || !makedev) return;
2731
+ const zeros = (_s, buffer, offset, length) => {
2732
+ buffer.fill(0, offset, offset + length);
2733
+ return length;
2734
+ };
2735
+ const devices = [
2736
+ ["/dev/zero", 5, (_s, _b, _o, length) => length],
2737
+ [
2738
+ "/dev/full",
2739
+ 7,
2740
+ (_s, _b, _o, length) => {
2741
+ if (length > 0) throw new Fs.ErrnoError(wasiErrno("ENOSPC"));
2742
+ return 0;
2274
2743
  }
2275
- quitting = false;
2276
- atExit = false;
2277
- failedAtExit = false;
2278
- committed = /* @__PURE__ */ new Set();
2279
- exiting() {
2280
- this.atExit = true;
2281
- return () => {
2282
- this.atExit = false;
2283
- };
2284
- }
2285
- commitStdout() {
2286
- const kfd = this.Fs.getStream(1)?.sliccKernelFd;
2287
- if (kfd === void 0 || !this.reporting.delete(kfd)) return;
2288
- this.committed.add(kfd);
2289
- try {
2290
- this.sys.close(kfd);
2291
- } catch (e) {
2292
- if (e instanceof SyscallError) this.stdoutFailed(e.code);
2293
- }
2294
- }
2295
- exitStatus(status2) {
2296
- return this.failedAtExit && status2 === 0 ? 1 : status2;
2297
- }
2298
- reportedClose(stream, kfd) {
2299
- try {
2300
- this.sys.close(kfd);
2301
- } catch (e) {
2302
- if (this.quitting && stream.fd === 1 && e instanceof SyscallError) this.stdoutFailed(e.code);
2303
- this.call(() => {
2304
- throw e;
2305
- });
2306
- }
2307
- }
2308
- stdoutFailed(code2) {
2309
- this.failedAtExit = true;
2310
- const stderr = this.Fs.getStream(2)?.sliccKernelFd;
2311
- if (stderr === void 0) return;
2312
- const line = `${this.options.program ?? "program"}: write error: ${STRERROR[code2] ?? code2}
2744
+ ]
2745
+ ];
2746
+ for (const [path, minor, write2] of devices) {
2747
+ if (analyzePath.call(Fs, path).exists) continue;
2748
+ const dev = makedev.call(Fs, 1, minor);
2749
+ registerDevice.call(Fs, dev, { read: zeros, write: write2, llseek: () => 0 });
2750
+ mkdev.call(Fs, path, CHAR_DEVICE, dev);
2751
+ }
2752
+ }
2753
+ function useDevRemoval(Fs) {
2754
+ const fs = Fs;
2755
+ for (const name2 of ["unlink", "rmdir"]) {
2756
+ const remove = fs[name2];
2757
+ if (typeof remove !== "function") continue;
2758
+ fs[name2] = (path) => {
2759
+ const refused = devRemoval(absoluteOf(path, Fs.cwd()), fs.sliccCred);
2760
+ if (refused) throw new Fs.ErrnoError(wasiErrno(refused));
2761
+ remove.call(Fs, path);
2762
+ };
2763
+ }
2764
+ }
2765
+ function linkStdio(Fs) {
2766
+ const { unlink, symlink } = Fs;
2767
+ if (!unlink || !symlink) return;
2768
+ for (const [fd, name2] of ["stdin", "stdout", "stderr"].entries()) {
2769
+ try {
2770
+ unlink.call(Fs, `/dev/${name2}`);
2771
+ } catch {
2772
+ }
2773
+ try {
2774
+ symlink.call(Fs, `/proc/self/fd/${fd}`, `/dev/${name2}`);
2775
+ } catch {
2776
+ }
2777
+ }
2778
+ }
2779
+ function useDevFd(Fs) {
2780
+ if (typeof Fs.open !== "function") return;
2781
+ try {
2782
+ Fs.symlink?.("/proc/self/fd", "/dev/fd");
2783
+ } catch {
2784
+ }
2785
+ linkStdio(Fs);
2786
+ describeFdDir(Fs);
2787
+ const fdOf = (path) => typeof path === "string" ? fdOfPath(path, Fs.cwd()) : void 0;
2788
+ const target = (fd) => {
2789
+ const stream = Fs.getStream(fd);
2790
+ if (!stream) throw new Fs.ErrnoError(wasiErrno("EBADF"));
2791
+ return stream;
2792
+ };
2793
+ const open = Fs.open.bind(Fs);
2794
+ Fs.open = (path, flags, mode) => {
2795
+ const fd = fdOf(path);
2796
+ if (fd === void 0) return open(path, flags, mode);
2797
+ const copy2 = Fs.dupStream(target(fd), -1);
2798
+ setCloseOnExec(copy2, typeof flags === "number" && (flags & O_CLOEXEC) !== 0);
2799
+ return copy2;
2800
+ };
2801
+ const { stat, fstat } = Fs;
2802
+ if (typeof stat !== "function" || typeof fstat !== "function") return;
2803
+ Fs.stat = (path, dontFollow) => {
2804
+ const fd = dontFollow ? void 0 : fdOf(path);
2805
+ if (fd === void 0) return stat.call(Fs, path, dontFollow);
2806
+ target(fd);
2807
+ return fstat.call(Fs, fd);
2808
+ };
2809
+ }
2810
+ function pinRootKind() {
2811
+ pinnedRoot = rootKind();
2812
+ }
2813
+ function mountTable(mounts = []) {
2814
+ const root = pinnedRoot ?? rootKind();
2815
+ const lines = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
2816
+ for (const m of mounts) {
2817
+ const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
2818
+ if (m.state !== "ok") options.push(m.state);
2819
+ const access = options.includes("ro") ? [] : ["rw"];
2820
+ lines.push(
2821
+ `${field(m.source)} ${field(m.target)} ${m.type} ${[...access, ...options].join(",")} 0 0`
2822
+ );
2823
+ }
2824
+ return `${lines.join("\n")}
2313
2825
  `;
2314
- try {
2315
- this.sys.write(stderr, new TextEncoder().encode(line));
2316
- } catch {
2317
- }
2826
+ }
2827
+ function accounts(env = {}) {
2828
+ const user = env.USER ?? "web_user";
2829
+ const name2 = NAME.test(user) && user !== "root" ? user : "user";
2830
+ const home = env.HOME || "/home";
2831
+ return {
2832
+ passwd: `root:x:0:0:root:/root:/bin/sh
2833
+ ${name2}:x:1000:1000:${name2}:${home}:/bin/bash
2834
+ `,
2835
+ group: `root:x:0:
2836
+ ${name2}:x:1000:
2837
+ `
2838
+ };
2839
+ }
2840
+ function useMounts(Fs, env = {}, live = false) {
2841
+ const { writeFile, mkdirTree } = Fs;
2842
+ if (typeof Fs.open !== "function" || typeof writeFile !== "function") return;
2843
+ const { passwd, group } = accounts(env);
2844
+ const backing = { "/etc/mtab": "/proc/mounts" };
2845
+ try {
2846
+ if (!live) writeFile.call(Fs, "/proc/mounts", mountTable());
2847
+ } catch {
2848
+ return;
2849
+ }
2850
+ try {
2851
+ mkdirTree.call(Fs, "/dev/.etc");
2852
+ writeFile.call(Fs, "/dev/.etc/passwd", passwd);
2853
+ writeFile.call(Fs, "/dev/.etc/group", group);
2854
+ writeFile.call(Fs, "/dev/.etc/hosts", hostsFile(hostnameOf(env)));
2855
+ writeFile.call(Fs, "/dev/.etc/hostname", `${hostnameOf(env)}
2856
+ `);
2857
+ backing["/etc/passwd"] = "/dev/.etc/passwd";
2858
+ backing["/etc/group"] = "/dev/.etc/group";
2859
+ backing["/etc/hosts"] = "/dev/.etc/hosts";
2860
+ backing["/etc/hostname"] = "/dev/.etc/hostname";
2861
+ } catch {
2862
+ }
2863
+ const open = Fs.open.bind(Fs);
2864
+ Fs.open = (path, flags, mode) => {
2865
+ const instead = backing[path];
2866
+ if (!instead || (flags & (O_ACCMODE2 | O_CREAT)) !== 0) return open(path, flags, mode);
2867
+ try {
2868
+ return open(path, flags, mode);
2869
+ } catch (e) {
2870
+ if (e?.errno !== wasiErrno("ENOENT")) throw e;
2871
+ return open(instead, flags, mode);
2872
+ }
2873
+ };
2874
+ }
2875
+ function cString(memory, at) {
2876
+ const bytes = new Uint8Array(memory.buffer, at);
2877
+ return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
2878
+ }
2879
+ function baseOf(Fs, dirfd) {
2880
+ return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
2881
+ }
2882
+ function readonlyRefusal(Fs, memory, call2) {
2883
+ if (!(call2.amode & W_ACCESS)) return 0;
2884
+ try {
2885
+ const name2 = cString(memory, call2.path);
2886
+ const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
2887
+ const follow2 = (call2.flags & AT_SYMLINK_NOFOLLOW) === 0;
2888
+ const { node } = Fs.lookupPath.call(Fs, abs, {
2889
+ follow: follow2
2890
+ });
2891
+ const bridge = node.live ? node.mount.opts.bridge : void 0;
2892
+ const stats = bridge;
2893
+ const stat = follow2 ? stats?.stat : stats?.lstat;
2894
+ return stat?.call(stats, liveNodePath(node)).readonly ? -wasiErrno("EROFS") : 0;
2895
+ } catch {
2896
+ return 0;
2897
+ }
2898
+ }
2899
+ function kernelChecks(Fs, memory, call2) {
2900
+ const name2 = cString(memory, call2.path);
2901
+ const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
2902
+ const lookupPath = Fs.lookupPath;
2903
+ const { node } = lookupPath.call(Fs, abs, { follow: (call2.flags & AT_SYMLINK_NOFOLLOW) === 0 });
2904
+ const bridge = node.live ? node.mount.opts.bridge : void 0;
2905
+ if (!bridge?.owners || !bridge.access) return 0;
2906
+ const kind = call2.flags & AT_EACCESS ? "eaccess" : "access";
2907
+ bridge.access(liveNodePath(node), call2.amode, kind, (call2.flags & AT_SYMLINK_NOFOLLOW) !== 0);
2908
+ return 0;
2909
+ }
2910
+ function kernelAccess(imports, fs, memory, glue) {
2911
+ wrapImport(imports, "faccessat", glue, (own) => (dirfd, path, amode, flags) => {
2912
+ const Fs = fs();
2913
+ const heap = memory();
2914
+ const call2 = { dirfd, path, amode: amode & 7, flags };
2915
+ const refused = Fs?.lookupPath && heap ? readonlyRefusal(Fs, heap, call2) : 0;
2916
+ if (refused !== 0) return refused;
2917
+ const rc = own(dirfd, path, amode, flags);
2918
+ if (rc !== 0 || !Fs?.lookupPath || !heap) return rc;
2919
+ try {
2920
+ return kernelChecks(Fs, heap, { dirfd, path, amode: amode & 7, flags });
2921
+ } catch (err) {
2922
+ return -errnoOf(err);
2923
+ }
2924
+ });
2925
+ }
2926
+ function kernelLink(imports, fs, memory, glue) {
2927
+ wrapImport(
2928
+ imports,
2929
+ "linkat",
2930
+ glue,
2931
+ (own) => (olddirfd, oldpath, newdirfd, newpath, flags) => {
2932
+ const Fs = fs();
2933
+ const heap = memory();
2934
+ if (!Fs?.lookupPath || !heap) return own(olddirfd, oldpath, newdirfd, newpath, flags);
2935
+ const at = (dirfd, ptr) => {
2936
+ const name2 = cString(heap, ptr);
2937
+ return name2.startsWith("/") ? name2 : `${baseOf(Fs, dirfd)}/${name2}`;
2938
+ };
2939
+ try {
2940
+ const from = at(olddirfd, oldpath);
2941
+ const to = at(newdirfd, newpath);
2942
+ const follow2 = (flags & AT_SYMLINK_FOLLOW) !== 0;
2943
+ if (linkLive(Fs, from, to, follow2)) return 0;
2944
+ } catch (err) {
2945
+ return -errnoOf(err);
2318
2946
  }
2319
- creatingTerminal = false;
2320
- useTerminalNodes() {
2321
- const fs = this.Fs;
2322
- const { lookupNode, readdir, getPath, mkdev, makedev } = fs;
2323
- const ttyNames = this.sys.ttyNames?.bind(this.sys);
2324
- if (!lookupNode || !readdir || !getPath || !mkdev || !makedev || !ttyNames) return;
2325
- fs.lookupNode = (parent, name2) => {
2326
- try {
2327
- return lookupNode.call(fs, parent, name2);
2328
- } catch (e) {
2329
- const path = `/dev/${name2}`;
2330
- if (this.creatingTerminal || !TTY_NAME.test(name2) || getPath.call(fs, parent) !== "/dev")
2331
- throw e;
2332
- if (!ttyNames().includes(path)) throw e;
2333
- this.creatingTerminal = true;
2334
- try {
2335
- mkdev.call(fs, path, makedev.call(fs, 6, 0));
2336
- } finally {
2337
- this.creatingTerminal = false;
2338
- }
2339
- return lookupNode.call(fs, parent, name2);
2340
- }
2341
- };
2342
- fs.readdir = (path) => {
2343
- const names = readdir.call(fs, path);
2344
- if (path.replace(/\/+$/, "") !== "/dev") return names;
2345
- const missing2 = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name2) => TTY_NAME.test(name2) && !names.includes(name2));
2346
- return [...names, ...missing2];
2347
- };
2348
- }
2349
- ttyNode(name2) {
2350
- const { analyzePath, mkdev, makedev } = this.Fs;
2351
- if (!TTY_PATH.test(name2) || !analyzePath || !mkdev || !makedev) return;
2352
- if (!analyzePath.call(this.Fs, name2).exists)
2353
- mkdev.call(this.Fs, name2, makedev.call(this.Fs, 6, 0));
2947
+ return own(olddirfd, oldpath, newdirfd, newpath, flags);
2948
+ },
2949
+ true
2950
+ );
2951
+ }
2952
+ function kernelChdir(Fs) {
2953
+ const { chdir, lookupPath, ErrnoError } = Fs;
2954
+ if (!chdir || !lookupPath || !ErrnoError) return;
2955
+ Fs.chdir = (path) => {
2956
+ const { node } = lookupPath.call(Fs, path, { follow: true });
2957
+ const directory = Fs.isDir?.(node.mode) === true;
2958
+ const bridge = node.live && directory ? node.mount.opts.bridge : void 0;
2959
+ try {
2960
+ bridge?.access?.(liveNodePath(node), X_ACCESS, "eaccess", false);
2961
+ } catch (err) {
2962
+ throw new ErrnoError(errnoOf(err));
2963
+ }
2964
+ chdir.call(Fs, path);
2965
+ };
2966
+ }
2967
+ function linuxDevices(Fs) {
2968
+ Fs.ignorePermissions = true;
2969
+ kernelChdir(Fs);
2970
+ const { chmod } = Fs;
2971
+ if (!chmod) return;
2972
+ for (const [path, mode] of DEVICE_MODES) {
2973
+ try {
2974
+ chmod.call(Fs, path, mode);
2975
+ } catch {
2976
+ }
2977
+ }
2978
+ }
2979
+ 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_PATH2, LITERALS, UTIME_NOW, UTIME_OMIT, PROT_WRITE, MAP_PRIVATE, MAP_TYPE, O_WRONLY, MAP_ALIGN, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE2, O_CREAT, field, pinnedRoot, rootKind, NAME, AT_FDCWD, AT_EACCESS, W_ACCESS, X_ACCESS, AT_SYMLINK_FOLLOW, DEVICE_MODES;
2980
+ var init_process_fds = __esm({
2981
+ "src/process/process-fds.ts"() {
2982
+ "use strict";
2983
+ init_dev_removal();
2984
+ init_loopback_names();
2985
+ init_live_vfs_fs();
2986
+ init_process_pty();
2987
+ init_wasi_errno();
2988
+ O_CLOEXEC = 524288;
2989
+ FD_CLOEXEC = 1;
2990
+ F_DUPFD = 0;
2991
+ F_GETFD = 1;
2992
+ F_SETFD = 2;
2993
+ F_GETFL = 3;
2994
+ F_DUPFD_CLOEXEC = 1030;
2995
+ tracked = /* @__PURE__ */ new WeakSet();
2996
+ IMPORT_NAMES = {
2997
+ fcntl: "__syscall_fcntl64",
2998
+ pipe2: "__syscall_pipe2",
2999
+ dup3: "__syscall_dup3",
3000
+ socket: "__syscall_socket",
3001
+ accept4: "__syscall_accept4",
3002
+ ioctl: "__syscall_ioctl",
3003
+ setitimer: "_setitimer_js"
3004
+ };
3005
+ EBADF = 8;
3006
+ AT_SYMLINK_NOFOLLOW = 256;
3007
+ EMSCRIPTEN_EPERM = 63;
3008
+ O_PATH2 = 2097152;
3009
+ LITERALS = {
3010
+ openat: "__syscall_openat",
3011
+ mkdirat: "__syscall_mkdirat",
3012
+ mknodat: "__syscall_mknodat",
3013
+ umask: "__syscall_umask",
3014
+ faccessat: "__syscall_faccessat",
3015
+ linkat: "__syscall_linkat",
3016
+ utimensat: "__syscall_utimensat",
3017
+ getppid: "slicc_getppid_js",
3018
+ resizeHeap: "emscripten_resize_heap",
3019
+ fdWrite: "fd_write",
3020
+ fdRead: "fd_read",
3021
+ sleepMs: "slicc_sleep_ms"
3022
+ };
3023
+ UTIME_NOW = 1073741823;
3024
+ UTIME_OMIT = 1073741822;
3025
+ PROT_WRITE = 2;
3026
+ MAP_PRIVATE = 2;
3027
+ MAP_TYPE = 15;
3028
+ O_WRONLY = 1;
3029
+ MAP_ALIGN = 65536;
3030
+ DIR_MODE = 16749;
3031
+ LINK_MODE = 41408;
3032
+ CHAR_DEVICE = 8630;
3033
+ O_ACCMODE2 = 3;
3034
+ O_CREAT = 64;
3035
+ field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
3036
+ rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
3037
+ NAME = /^[a-z_][a-z0-9_-]*$/i;
3038
+ AT_FDCWD = -100;
3039
+ AT_EACCESS = 512;
3040
+ W_ACCESS = 2;
3041
+ X_ACCESS = 1;
3042
+ AT_SYMLINK_FOLLOW = 1024;
3043
+ DEVICE_MODES = [
3044
+ ["/", 493],
3045
+ ["/dev", 493],
3046
+ ["/dev/null", 438],
3047
+ ["/dev/zero", 438],
3048
+ ["/dev/full", 438],
3049
+ ["/dev/random", 438],
3050
+ ["/dev/urandom", 438],
3051
+ ["/dev/tty", 438],
3052
+ ["/dev/shm", 1023]
3053
+ ];
3054
+ }
3055
+ });
3056
+
3057
+ // src/process/fd-metadata.ts
3058
+ function idOf2(value2) {
3059
+ return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
3060
+ }
3061
+ function timeOf(value2) {
3062
+ return typeof value2 === "number" && Number.isFinite(value2) ? value2 : null;
3063
+ }
3064
+ function useKernelFdMetadata(Fs, sys, call2) {
3065
+ const { fdChown, fdChmod, fdUtimes } = sys;
3066
+ const meta = Fs;
3067
+ const kernelFd = (stream) => stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
3068
+ const find = (match) => {
3069
+ for (const s of Fs.streams) {
3070
+ const kfd = s && match(s) ? kernelFd(s) : void 0;
3071
+ if (kfd !== void 0) return kfd;
3072
+ }
3073
+ return void 0;
3074
+ };
3075
+ const ofPath = (path, follow2) => {
3076
+ if (typeof path !== "string") return find((s) => s.node === path);
3077
+ const fd = follow2 ? fdOfPath(path, Fs.cwd()) : void 0;
3078
+ if (fd !== void 0) return kernelFd(Fs.getStream(fd));
3079
+ return find((s) => s.path === path);
3080
+ };
3081
+ const ofFd = (fd) => kernelFd(Fs.getStream(fd));
3082
+ const chownBy = (kfd, uid, gid) => call2(() => fdChown?.call(sys, kfd, idOf2(uid), idOf2(gid)));
3083
+ if (fdChown && meta.chown) {
3084
+ const chown = meta.chown.bind(Fs);
3085
+ meta.chown = (path, uid, gid, dontFollow) => {
3086
+ const kfd = ofPath(path, !dontFollow);
3087
+ if (kfd === void 0) return chown(path, uid, gid, dontFollow);
3088
+ chownBy(kfd, uid, gid);
3089
+ };
3090
+ }
3091
+ if (fdChown && meta.fchown) {
3092
+ const fchown = meta.fchown.bind(Fs);
3093
+ meta.fchown = (fd, uid, gid) => {
3094
+ const kfd = ofFd(fd);
3095
+ if (kfd === void 0) return fchown(fd, uid, gid);
3096
+ chownBy(kfd, uid, gid);
3097
+ };
3098
+ }
3099
+ if (fdChmod && meta.chmod) {
3100
+ const chmod = meta.chmod.bind(Fs);
3101
+ meta.chmod = (path, mode, dontFollow) => {
3102
+ const kfd = ofPath(path, !dontFollow);
3103
+ if (kfd === void 0) return chmod(path, mode, dontFollow);
3104
+ call2(() => fdChmod.call(sys, kfd, mode & 4095));
3105
+ };
3106
+ }
3107
+ if (fdChmod && meta.fchmod) {
3108
+ const fchmod = meta.fchmod.bind(Fs);
3109
+ meta.fchmod = (fd, mode) => {
3110
+ const kfd = ofFd(fd);
3111
+ if (kfd === void 0) return fchmod(fd, mode);
3112
+ call2(() => fdChmod.call(sys, kfd, mode & 4095));
3113
+ };
3114
+ }
3115
+ if (fdUtimes && meta.utime) {
3116
+ const utime = meta.utime.bind(Fs);
3117
+ meta.utime = (path, atime, mtime) => {
3118
+ const kfd = ofPath(path, true);
3119
+ if (kfd === void 0) return utime(path, atime, mtime);
3120
+ const now = meta.sliccTouch === true;
3121
+ call2(() => fdUtimes.call(sys, kfd, timeOf(atime), timeOf(mtime), now));
3122
+ };
3123
+ }
3124
+ }
3125
+ var init_fd_metadata = __esm({
3126
+ "src/process/fd-metadata.ts"() {
3127
+ "use strict";
3128
+ init_process_fds();
3129
+ }
3130
+ });
3131
+
3132
+ // src/process/kernel-streams.ts
3133
+ function isPtyPath(path) {
3134
+ return PTY_PATH.test(path);
3135
+ }
3136
+ function ptyStat(path) {
3137
+ const n = PTY_PATH.exec(path)?.[1];
3138
+ const now = /* @__PURE__ */ new Date();
3139
+ return {
3140
+ dev: 22,
3141
+ ino: n === void 0 ? 2 : 3 + Number(n),
3142
+ mode: n === void 0 ? 8630 : 8592,
3143
+ nlink: 1,
3144
+ uid: 1e3,
3145
+ gid: 1e3,
3146
+ rdev: n === void 0 ? 5 << 8 | 2 : 136 << 8 | Number(n),
3147
+ size: 0,
3148
+ blksize: 4096,
3149
+ blocks: 0,
3150
+ atime: now,
3151
+ mtime: now,
3152
+ ctime: now
3153
+ };
3154
+ }
3155
+ function sealedStat(minor = 250) {
3156
+ const now = /* @__PURE__ */ new Date();
3157
+ return {
3158
+ dev: 22,
3159
+ ino: minor === 251 ? 2 : 1,
3160
+ mode: 8630,
3161
+ nlink: 1,
3162
+ uid: 0,
3163
+ gid: 0,
3164
+ rdev: 10 << 8 | minor,
3165
+ size: 0,
3166
+ blksize: 4096,
3167
+ blocks: 0,
3168
+ atime: now,
3169
+ mtime: now,
3170
+ ctime: now
3171
+ };
3172
+ }
3173
+ function nonblocking(stream) {
3174
+ return (stream.flags & O_NONBLOCK) !== 0 ? { nonblock: true } : void 0;
3175
+ }
3176
+ function datesOf(real) {
3177
+ const dates = {};
3178
+ for (const [key, value2] of Object.entries(real ?? {}))
3179
+ if (/^[amc]time$/.test(key) && (typeof value2 === "string" || typeof value2 === "number"))
3180
+ dates[key] = new Date(value2);
3181
+ return dates;
3182
+ }
3183
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH, STRERROR, CLIPBOARD_PATH, O_CREAT2, O_EXCL, O_NOCTTY, O_TRUNC2, O_DIRECTORY, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
3184
+ var init_kernel_streams = __esm({
3185
+ "src/process/kernel-streams.ts"() {
3186
+ "use strict";
3187
+ init_fd_metadata();
3188
+ init_wasi_errno();
3189
+ POLLIN = 1;
3190
+ POLLOUT = 4;
3191
+ POLLERR = 8;
3192
+ POLLHUP = 16;
3193
+ POLLRDNORM = 64;
3194
+ POLLWRNORM = 256;
3195
+ TCSETSF = 21508;
3196
+ O_NONBLOCK = 2048;
3197
+ SOCKET_MODE = 49663;
3198
+ PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
3199
+ TTY_PATH = /^\/dev\/tty\d+$/;
3200
+ TTY_NAME = /^tty\d+$/;
3201
+ SEALED_PATH = "/dev/sealed";
3202
+ STRERROR = {
3203
+ EACCES: "Permission denied",
3204
+ EIO: "I/O error",
3205
+ ENOTSUP: "Not supported",
3206
+ EOPNOTSUPP: "Not supported",
3207
+ EFBIG: "File too large",
3208
+ EILSEQ: "Illegal byte sequence",
3209
+ EINTR: "Interrupted system call"
3210
+ };
3211
+ CLIPBOARD_PATH = "/dev/clipboard";
3212
+ O_CREAT2 = 64;
3213
+ O_EXCL = 128;
3214
+ O_NOCTTY = 256;
3215
+ O_TRUNC2 = 512;
3216
+ O_DIRECTORY = 65536;
3217
+ KILLED_BY_SIGPIPE = 128 + 13;
3218
+ ProcessExit = class extends Error {
3219
+ status;
3220
+ constructor(status2) {
3221
+ super(`exit ${status2}`);
3222
+ this.status = status2;
2354
3223
  }
2355
- ttyOps(kfd) {
2356
- return {
2357
- ops: {
2358
- ioctl_tcgets: () => this.call(() => this.sys.tcgets?.(kfd)),
2359
- ioctl_tcsets: (_tty, op, termios) => this.call(() => {
2360
- this.sys.tcsets?.(kfd, termios, op === TCSETSF);
2361
- return 0;
2362
- }),
2363
- ioctl_tiocgwinsz: () => this.call(() => this.sys.winsize?.(kfd) ?? [24, 80]),
2364
- fsync: () => {
2365
- }
2366
- }
2367
- };
3224
+ };
3225
+ SyscallError = class extends Error {
3226
+ code;
3227
+ constructor(code2) {
3228
+ super(code2);
3229
+ this.code = code2;
2368
3230
  }
2369
- attachFile(stream, kfd) {
2370
- this.attach(stream, kfd, false);
2371
- stream.sliccKernelFile = true;
2372
- stream.stream_ops = {
2373
- ...stream.stream_ops,
2374
- llseek: (_s, offset, whence) => this.call(() => this.sys.seek(kfd, offset, whence)),
2375
- fsync: () => this.call(() => {
2376
- this.sys.flush(kfd);
2377
- return 0;
2378
- })
2379
- };
3231
+ };
3232
+ KernelStreams = class {
3233
+ refs = /* @__PURE__ */ new Map();
3234
+ socketRoot;
3235
+ sockets = 0;
3236
+ descriptions = /* @__PURE__ */ new Map();
3237
+ described = 0;
3238
+ Fs;
3239
+ sys;
3240
+ options;
3241
+ constructor(Fs, sys, options = {}) {
3242
+ this.Fs = Fs;
3243
+ this.sys = sys;
3244
+ this.options = options;
3245
+ }
3246
+ attach(stream, kfd, terminal) {
3247
+ this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
3248
+ stream.sliccKernelFd = kfd;
3249
+ stream.stream_ops = this.ops(kfd, stream.stream_ops);
3250
+ if (terminal ?? this.sys.isatty?.(kfd) ?? false) stream.tty = this.ttyOps(kfd);
3251
+ else delete stream.tty;
3252
+ }
3253
+ attachSocket(stream, kfd) {
3254
+ this.attach(stream, kfd, false);
3255
+ stream.sliccKernelSocket = true;
3256
+ }
3257
+ socketStream(flags) {
3258
+ const fs = this.Fs;
3259
+ if (!fs.mount || !fs.createNode || !fs.createStream) {
3260
+ const stream = this.Fs.open("/dev/null", 2);
3261
+ stream.flags = flags;
3262
+ return stream;
3263
+ }
3264
+ const createNode = fs.createNode;
3265
+ this.socketRoot ??= fs.mount({ mount: () => createNode(null, "/", 16895, 0) }, {}, null);
3266
+ const ino = ++this.sockets;
3267
+ const node = fs.createNode(this.socketRoot, `socket:${ino}`, SOCKET_MODE, 0);
3268
+ const now = /* @__PURE__ */ new Date();
3269
+ const stat = { dev: 0, ino, mode: SOCKET_MODE, nlink: 1, uid: 0, gid: 0, rdev: 0, size: 0 };
3270
+ const times = { atime: now, mtime: now, ctime: now, blksize: 4096, blocks: 0 };
3271
+ node.node_ops = { getattr: () => ({ ...stat, ...times }) };
3272
+ return fs.createStream({ node, flags, seekable: false, position: 0, stream_ops: {} });
3273
+ }
3274
+ nameTerminal(stream) {
3275
+ const kfd = stream.sliccKernelFd;
3276
+ if (!stream.tty || kfd === void 0) return;
3277
+ const name2 = this.sys.ttyName?.(kfd);
3278
+ if (name2) this.nameStream(stream, name2);
3279
+ }
3280
+ nameStream(stream, name2) {
3281
+ stream.path = name2;
3282
+ this.ttyNode(name2);
3283
+ if (typeof this.Fs.stat !== "function") return;
3284
+ stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name2) ?? {} };
3285
+ }
3286
+ nameDevice(stream, kind) {
3287
+ this.nameStream(stream, kind === "sealed" ? SEALED_PATH : CLIPBOARD_PATH);
3288
+ }
3289
+ listSealed() {
3290
+ const fs = this.Fs;
3291
+ const { analyzePath, mkdev, makedev, registerDevice } = fs;
3292
+ if (!analyzePath || !mkdev || !makedev) return;
3293
+ const nodes = [
3294
+ [SEALED_PATH, 250, this.sys.openSealed],
3295
+ [CLIPBOARD_PATH, 251, this.sys.openClipboard]
3296
+ ];
3297
+ for (const [path, minor, opener] of nodes) {
3298
+ if (!opener) continue;
3299
+ const dev = makedev.call(fs, 10, minor);
3300
+ registerDevice?.call(fs, dev, {
3301
+ open: (stream) => this.openNode(stream, path, opener)
3302
+ });
3303
+ if (analyzePath.call(fs, path).exists) continue;
3304
+ try {
3305
+ const node = mkdev.call(fs, path, dev);
3306
+ if (typeof node === "object" && node !== null) {
3307
+ const made = node;
3308
+ made.node_ops = { ...made.node_ops, getattr: () => sealedStat(minor) };
3309
+ }
3310
+ } catch {
3311
+ }
3312
+ }
3313
+ }
3314
+ openNode(stream, path, opener) {
3315
+ let kfd;
3316
+ try {
3317
+ kfd = this.call(() => opener.call(this.sys, stream.flags & 3));
3318
+ } catch (e) {
3319
+ this.Fs.closeStream(stream.fd);
3320
+ throw e;
3321
+ }
3322
+ this.attach(stream, kfd, false);
3323
+ this.nameStream(stream, path);
3324
+ if (path === CLIPBOARD_PATH) this.reportClose(kfd);
3325
+ }
3326
+ reporting = /* @__PURE__ */ new Set();
3327
+ reportClose(kfd) {
3328
+ this.reporting.add(kfd);
3329
+ }
3330
+ quitting = false;
3331
+ atExit = false;
3332
+ failedAtExit = false;
3333
+ committed = /* @__PURE__ */ new Set();
3334
+ exiting() {
3335
+ this.atExit = true;
3336
+ return () => {
3337
+ this.atExit = false;
3338
+ };
3339
+ }
3340
+ commitStdout() {
3341
+ const kfd = this.Fs.getStream(1)?.sliccKernelFd;
3342
+ if (kfd === void 0 || !this.reporting.delete(kfd)) return;
3343
+ this.committed.add(kfd);
3344
+ try {
3345
+ this.sys.close(kfd);
3346
+ } catch (e) {
3347
+ if (e instanceof SyscallError) this.stdoutFailed(e.code);
3348
+ }
3349
+ }
3350
+ exitStatus(status2) {
3351
+ return this.failedAtExit && status2 === 0 ? 1 : status2;
3352
+ }
3353
+ reportedClose(stream, kfd) {
3354
+ try {
3355
+ this.sys.close(kfd);
3356
+ } catch (e) {
3357
+ if (this.quitting && stream.fd === 1 && e instanceof SyscallError) this.stdoutFailed(e.code);
3358
+ this.call(() => {
3359
+ throw e;
3360
+ });
3361
+ }
3362
+ }
3363
+ stdoutFailed(code2) {
3364
+ this.failedAtExit = true;
3365
+ const stderr = this.Fs.getStream(2)?.sliccKernelFd;
3366
+ if (stderr === void 0) return;
3367
+ const line = `${this.options.program ?? "program"}: write error: ${STRERROR[code2] ?? code2}
3368
+ `;
3369
+ try {
3370
+ this.sys.write(stderr, new TextEncoder().encode(line));
3371
+ } catch {
3372
+ }
3373
+ }
3374
+ creatingTerminal = false;
3375
+ useTerminalNodes() {
3376
+ const fs = this.Fs;
3377
+ const { lookupNode, readdir, getPath, mkdev, makedev } = fs;
3378
+ const ttyNames = this.sys.ttyNames?.bind(this.sys);
3379
+ if (!lookupNode || !readdir || !getPath || !mkdev || !makedev || !ttyNames) return;
3380
+ fs.lookupNode = (parent, name2) => {
3381
+ try {
3382
+ return lookupNode.call(fs, parent, name2);
3383
+ } catch (e) {
3384
+ const path = `/dev/${name2}`;
3385
+ if (this.creatingTerminal || !TTY_NAME.test(name2) || getPath.call(fs, parent) !== "/dev")
3386
+ throw e;
3387
+ if (!ttyNames().includes(path)) throw e;
3388
+ this.creatingTerminal = true;
3389
+ try {
3390
+ mkdev.call(fs, path, makedev.call(fs, 6, 0));
3391
+ } finally {
3392
+ this.creatingTerminal = false;
3393
+ }
3394
+ return lookupNode.call(fs, parent, name2);
3395
+ }
3396
+ };
3397
+ fs.readdir = (path) => {
3398
+ const names = readdir.call(fs, path);
3399
+ if (path.replace(/\/+$/, "") !== "/dev") return names;
3400
+ const missing2 = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name2) => TTY_NAME.test(name2) && !names.includes(name2));
3401
+ return [...names, ...missing2];
3402
+ };
3403
+ }
3404
+ ttyNode(name2) {
3405
+ const { analyzePath, mkdev, makedev } = this.Fs;
3406
+ if (!TTY_PATH.test(name2) || !analyzePath || !mkdev || !makedev) return;
3407
+ if (!analyzePath.call(this.Fs, name2).exists)
3408
+ mkdev.call(this.Fs, name2, makedev.call(this.Fs, 6, 0));
3409
+ }
3410
+ ttyOps(kfd) {
3411
+ return {
3412
+ ops: {
3413
+ ioctl_tcgets: () => this.call(() => this.sys.tcgets?.(kfd)),
3414
+ ioctl_tcsets: (_tty, op, termios) => this.call(() => {
3415
+ this.sys.tcsets?.(kfd, termios, op === TCSETSF);
3416
+ return 0;
3417
+ }),
3418
+ ioctl_tiocgwinsz: () => this.call(() => this.sys.winsize?.(kfd) ?? [24, 80]),
3419
+ fsync: () => {
3420
+ }
3421
+ }
3422
+ };
3423
+ }
3424
+ attachFile(stream, kfd) {
3425
+ this.attach(stream, kfd, false);
3426
+ stream.sliccKernelFile = true;
3427
+ stream.stream_ops = {
3428
+ ...stream.stream_ops,
3429
+ llseek: (_s, offset, whence) => this.call(() => this.sys.seek(kfd, offset, whence)),
3430
+ fsync: () => this.call(() => {
3431
+ this.sys.flush(kfd);
3432
+ return 0;
3433
+ })
3434
+ };
2380
3435
  }
2381
3436
  sizeFromKernel(stream, kfd) {
2382
- const { size } = this.sys;
3437
+ const { size, fdStat: fdStat2 } = this.sys;
2383
3438
  if (!size) return;
2384
3439
  const node = stream.node;
2385
- this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => ({
2386
- ...node.node_ops?.getattr?.(node),
2387
- size: this.call(() => size.call(this.sys, kfd))
2388
- }));
3440
+ this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => {
3441
+ const base = node.node_ops?.getattr?.(node);
3442
+ const live = this.call(() => size.call(this.sys, kfd));
3443
+ const real = fdStat2 && this.call(() => fdStat2.call(this.sys, kfd));
3444
+ return { ...base, ...real, ...datesOf(real), size: live };
3445
+ });
2389
3446
  }
2390
3447
  describe(stream, name2, getattr) {
2391
3448
  if (this.descriptions.size === 0) this.useDescriptions();
@@ -2404,6 +3461,9 @@ var init_kernel_streams = __esm({
2404
3461
  };
2405
3462
  }
2406
3463
  }
3464
+ useKernelFdMetadata() {
3465
+ useKernelFdMetadata(this.Fs, this.sys, this.call.bind(this));
3466
+ }
2407
3467
  useControllingTerminal() {
2408
3468
  if (typeof this.Fs.open !== "function") return;
2409
3469
  this.usePtyPaths();
@@ -2457,7 +3517,7 @@ var init_kernel_streams = __esm({
2457
3517
  }
2458
3518
  }
2459
3519
  refuseExclusiveLink(path, flags) {
2460
- if ((flags & (O_CREAT | O_EXCL)) !== (O_CREAT | O_EXCL)) return;
3520
+ if ((flags & (O_CREAT2 | O_EXCL)) !== (O_CREAT2 | O_EXCL)) return;
2461
3521
  let mode = 0;
2462
3522
  try {
2463
3523
  mode = this.Fs.stat?.(path, true)?.mode ?? 0;
@@ -2484,15 +3544,22 @@ var init_kernel_streams = __esm({
2484
3544
  openClipboard(open, path, flags, mode) {
2485
3545
  const { openClipboard } = this.sys;
2486
3546
  if (path !== CLIPBOARD_PATH || !openClipboard) return void 0;
3547
+ if (flags & O_DIRECTORY) throw new this.Fs.ErrnoError(wasiErrno("ENOTDIR"));
2487
3548
  const kfd = this.call(() => openClipboard.call(this.sys, flags & 3));
2488
- const stream = this.vessel(open, kfd, { path, flags, mode }, false);
2489
- this.reportClose(kfd);
2490
- return stream;
3549
+ try {
3550
+ const stream = this.vessel(open, kfd, { path, flags, mode }, false);
3551
+ this.reportClose(kfd);
3552
+ return stream;
3553
+ } catch (e) {
3554
+ this.sys.clipboardAbort?.(kfd);
3555
+ this.sys.close(kfd);
3556
+ throw e;
3557
+ }
2491
3558
  }
2492
3559
  vessel(open, kfd, at, terminal) {
2493
3560
  let stream;
2494
3561
  try {
2495
- stream = open("/dev/null", at.flags & ~(O_CREAT | O_EXCL | O_TRUNC2), at.mode);
3562
+ stream = open("/dev/null", at.flags & ~(O_CREAT2 | O_EXCL | O_TRUNC2), at.mode);
2496
3563
  } catch (e) {
2497
3564
  this.sys.close(kfd);
2498
3565
  throw e;
@@ -2620,869 +3687,64 @@ var init_kernel_streams = __esm({
2620
3687
  return {
2621
3688
  ...base,
2622
3689
  llseek: () => this.call(() => {
2623
- throw new SyscallError("ESPIPE");
2624
- }),
2625
- read: (s, buffer, offset, length) => this.call(() => {
2626
- const bytes = this.restarting(() => this.sys.read(kfd, length, nonblocking(s)));
2627
- buffer.set(bytes, offset);
2628
- return bytes.length;
2629
- }),
2630
- write: (s, buffer, offset, length) => {
2631
- try {
2632
- const bytes = buffer.slice(offset, offset + length);
2633
- return this.restarting(() => this.sys.write(kfd, bytes, nonblocking(s)));
2634
- } catch (e) {
2635
- if (e instanceof SyscallError && e.code === "EPIPE" && !this.options.sigpipe?.()) {
2636
- throw new ProcessExit(KILLED_BY_SIGPIPE);
2637
- }
2638
- return this.call(() => {
2639
- throw e;
2640
- });
2641
- }
2642
- },
2643
- fsync: () => 0,
2644
- poll: () => {
2645
- const state = this.call(() => this.sys.poll(kfd));
2646
- let mask = 0;
2647
- if (state.readable) mask |= POLLIN | POLLRDNORM;
2648
- if (state.writable) mask |= POLLOUT | POLLWRNORM;
2649
- if (state.hangup) mask |= state.readable ? POLLHUP : POLLERR;
2650
- return mask;
2651
- },
2652
- dup: (stream) => {
2653
- base.dup?.(stream);
2654
- this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
2655
- },
2656
- close: (stream) => {
2657
- if (this.atExit && stream.fd === 2 && this.reporting.size > 0) this.commitStdout();
2658
- try {
2659
- base.close?.(stream);
2660
- } catch {
2661
- }
2662
- const left = (this.refs.get(kfd) ?? 1) - 1;
2663
- if (left > 0) {
2664
- this.refs.set(kfd, left);
2665
- return;
2666
- }
2667
- this.refs.delete(kfd);
2668
- if (this.committed.size > 0 && this.committed.delete(kfd)) return;
2669
- if (this.reporting.size > 0 && this.reporting.delete(kfd)) {
2670
- this.reportedClose(stream, kfd);
2671
- return;
2672
- }
2673
- try {
2674
- this.sys.close(kfd);
2675
- } catch {
2676
- }
2677
- }
2678
- };
2679
- }
2680
- };
2681
- }
2682
- });
2683
-
2684
- // src/process/process-pty.ts
2685
- function failed(e) {
2686
- const code2 = e?.code;
2687
- if (typeof code2 === "string") return -wasiErrno(code2);
2688
- throw e;
2689
- }
2690
- function ptyIoctl(ioctl, deps) {
2691
- return (fd, op, varargs) => {
2692
- const request = op >>> 0;
2693
- if (request !== TIOCGPTN && request !== TIOCSPTLCK && request !== TIOCSCTTY && request !== TIOCSWINSZ && request !== TIOCPKT) {
2694
- return ioctl(fd, op, varargs);
2695
- }
2696
- const stream = deps.fs()?.getStream(fd);
2697
- const kfd = stream?.sliccKernelFd;
2698
- if (kfd === void 0) return ioctl(fd, op, varargs);
2699
- const heap = deps.heap();
2700
- if (!heap) return -wasiErrno("EFAULT");
2701
- const argp = (heap[varargs >> 2] ?? 0) >>> 0;
2702
- try {
2703
- return answer(request, kfd, argp, heap, deps.kernel);
2704
- } catch (e) {
2705
- return failed(e);
2706
- }
2707
- };
2708
- }
2709
- function answer(request, kfd, argp, heap, kernel) {
2710
- switch (request) {
2711
- case TIOCGPTN:
2712
- heap[argp >> 2] = kernel.ptyNumber(kfd);
2713
- return 0;
2714
- case TIOCSPTLCK:
2715
- kernel.ptyLock(kfd, (heap[argp >> 2] ?? 0) !== 0);
2716
- return 0;
2717
- case TIOCSCTTY:
2718
- kernel.setControllingTerminal(kfd);
2719
- return 0;
2720
- case TIOCPKT:
2721
- kernel.setPacketMode(kfd, (heap[argp >> 2] ?? 0) !== 0);
2722
- return 0;
2723
- default: {
2724
- const word = heap[argp >> 2] ?? 0;
2725
- kernel.setWinsize(kfd, word & 65535, word >>> 16 & 65535);
2726
- return 0;
2727
- }
2728
- }
2729
- }
2730
- var TIOCGPTN, TIOCSPTLCK, TIOCSCTTY, TIOCSWINSZ, TIOCPKT;
2731
- var init_process_pty = __esm({
2732
- "src/process/process-pty.ts"() {
2733
- "use strict";
2734
- init_wasi_errno();
2735
- TIOCGPTN = 2147767344;
2736
- TIOCSPTLCK = 1074025521;
2737
- TIOCSCTTY = 21518;
2738
- TIOCSWINSZ = 21524;
2739
- TIOCPKT = 21536;
2740
- }
2741
- });
2742
-
2743
- // src/process/process-fds.ts
2744
- function closesOnExec(stream) {
2745
- return stream.sliccCloexec === true;
2746
- }
2747
- function setCloseOnExec(stream, on) {
2748
- if (on) stream.sliccCloexec = true;
2749
- else delete stream.sliccCloexec;
2750
- }
2751
- function trackCloseOnExec(Fs) {
2752
- if (tracked.has(Fs)) return;
2753
- tracked.add(Fs);
2754
- if (typeof Fs.dupStream === "function") {
2755
- const dupStream = Fs.dupStream.bind(Fs);
2756
- Fs.dupStream = (stream, fd) => {
2757
- const copy2 = dupStream(stream, fd);
2758
- setCloseOnExec(copy2, false);
2759
- return copy2;
2760
- };
2761
- }
2762
- if (typeof Fs.open === "function") {
2763
- const open = Fs.open.bind(Fs);
2764
- Fs.open = (path, flags, mode) => {
2765
- const cloexec = typeof flags === "number" && (flags & O_CLOEXEC) !== 0;
2766
- const stream = open(path, cloexec ? flags & ~O_CLOEXEC : flags, mode);
2767
- setCloseOnExec(stream, cloexec);
2768
- return stream;
2769
- };
2770
- }
2771
- }
2772
- function marker(deps) {
2773
- return (fd, on) => {
2774
- const stream = deps.fs()?.getStream(fd);
2775
- if (stream) setCloseOnExec(stream, on);
2776
- };
2777
- }
2778
- function cloexecFcntl(fcntl, deps) {
2779
- const mark = marker(deps);
2780
- return (fd, cmd, varargs) => {
2781
- if (cmd === F_DUPFD_CLOEXEC) {
2782
- const copy2 = fcntl(fd, F_DUPFD, varargs);
2783
- if (copy2 >= 0) mark(copy2, true);
2784
- return copy2;
2785
- }
2786
- if (cmd === F_GETFL) {
2787
- const flags = fcntl(fd, cmd, varargs);
2788
- return flags < 0 ? flags : flags & ~O_CLOEXEC;
2789
- }
2790
- if (cmd !== F_GETFD && cmd !== F_SETFD) return fcntl(fd, cmd, varargs);
2791
- const stream = deps.fs()?.getStream(fd);
2792
- if (!stream) return -wasiErrno("EBADF");
2793
- if (cmd === F_GETFD) return closesOnExec(stream) ? FD_CLOEXEC : 0;
2794
- const arg = deps.heap()?.[varargs >> 2];
2795
- if (arg === void 0) return -wasiErrno("EINVAL");
2796
- setCloseOnExec(stream, (arg & FD_CLOEXEC) !== 0);
2797
- return 0;
2798
- };
2799
- }
2800
- function cloexecPipe2(pipe2, deps) {
2801
- const mark = marker(deps);
2802
- return (fdPtr, flags) => {
2803
- const r = pipe2(fdPtr, flags & ~O_CLOEXEC);
2804
- const heap = deps.heap();
2805
- if (r === 0 && flags & O_CLOEXEC && heap) {
2806
- mark(heap[fdPtr >> 2], true);
2807
- mark(heap[(fdPtr >> 2) + 1], true);
2808
- }
2809
- return r;
2810
- };
2811
- }
2812
- function quietTarget(dup3, deps) {
2813
- return (fd = -1, newfd = -1, flags = 0, ...rest2) => {
2814
- const Fs = deps.fs();
2815
- const target = fd === newfd || flags !== 0 ? void 0 : Fs?.getStream(newfd);
2816
- if (target && Fs?.getStream(fd)) {
2817
- try {
2818
- Fs.close?.(target);
2819
- } catch {
2820
- }
2821
- }
2822
- return dup3(fd, newfd, flags, ...rest2);
2823
- };
2824
- }
2825
- function cloexecByFlag(syscall, flagArg, deps) {
2826
- const mark = marker(deps);
2827
- return (...args) => {
2828
- const cloexec = ((args[flagArg] ?? 0) & O_CLOEXEC) !== 0;
2829
- if (cloexec) args[flagArg] = args[flagArg] & ~O_CLOEXEC;
2830
- const fd = syscall(...args);
2831
- if (fd >= 0) mark(fd, cloexec);
2832
- return fd;
2833
- };
2834
- }
2835
- function wrapperFactories(deps) {
2836
- const { pty, timer } = deps;
2837
- return {
2838
- ...timer ? { setitimer: (f) => kernelTimer(f, timer) } : {},
2839
- fcntl: (f) => cloexecFcntl(f, deps),
2840
- pipe2: (f) => cloexecPipe2(f, deps),
2841
- dup3: (f) => cloexecByFlag(quietTarget(f, deps), 2, deps),
2842
- socket: (f) => cloexecByFlag(f, 1, deps),
2843
- accept4: (f) => cloexecByFlag(f, 3, deps),
2844
- ...pty ? { ioctl: (f) => ptyIoctl(f, { fs: deps.fs, heap: deps.heap, kernel: pty }) } : {}
2845
- };
2846
- }
2847
- function kernelTimer(setitimer, timer) {
2848
- return (which, ms) => {
2849
- if (which !== 0) return setitimer(which, ms);
2850
- timer.arm(ms ?? 0);
2851
- return 0;
2852
- };
2853
- }
2854
- function syscallOf(glue, name2, value2) {
2855
- const names = Object.keys(IMPORT_NAMES);
2856
- const own = names.find((key) => glue[key] !== void 0 && glue[key] === value2);
2857
- if (own) return own;
2858
- return typeof value2 === "function" ? names.find((key) => glue[key] !== void 0 && IMPORT_NAMES[key] === name2) : void 0;
2859
- }
2860
- function wrapCloexecSyscalls(imports, glue, deps) {
2861
- if (!glue) return;
2862
- const factories = wrapperFactories(deps);
2863
- const seen = /* @__PURE__ */ new Set();
2864
- for (const namespace of Object.values(imports)) {
2865
- if (!namespace || typeof namespace !== "object" || seen.has(namespace)) continue;
2866
- seen.add(namespace);
2867
- for (const [name2, value2] of Object.entries(namespace)) {
2868
- const key = syscallOf(glue, name2, value2);
2869
- const wrap2 = key && factories[key];
2870
- if (wrap2) namespace[name2] = wrap2(value2);
2871
- }
2872
- }
2873
- }
2874
- function pathOpensLinks(Fs) {
2875
- const fs = Fs;
2876
- const { mayOpen, isLink } = fs;
2877
- if (!mayOpen || !isLink) return;
2878
- fs.mayOpen = (node, flags) => flags & O_PATH2 && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2879
- }
2880
- function importKey(namespace, name2, glue) {
2881
- const own = glue?.[name2];
2882
- if (typeof own === "function") {
2883
- const found = Object.keys(namespace).find((k) => namespace[k] === own);
2884
- if (found !== void 0) return found;
2885
- }
2886
- const literal = LITERALS[name2];
2887
- return typeof namespace[literal] === "function" ? literal : void 0;
2888
- }
2889
- function wrapImport(imports, name2, glue, wrap2, optional = false) {
2890
- let wrapped = false;
2891
- for (const ns of namespaces(imports)) {
2892
- const key = importKey(ns, name2, glue);
2893
- if (key === void 0) continue;
2894
- ns[key] = wrap2(ns[key]);
2895
- wrapped = true;
2896
- }
2897
- if (!wrapped && !optional && typeof glue?.[name2] === "function") {
2898
- throw new Error(`slicc-kernel cannot find the glue's ${LITERALS[name2]} among its imports`);
2899
- }
2900
- }
2901
- function kernelUmask(imports, deps) {
2902
- let umask = deps.initial & 511;
2903
- const { glue } = deps;
2904
- wrapImport(imports, "openat", glue, (openat) => (dirfd, path, flags, varargs) => {
2905
- const memory = deps.memory();
2906
- if (flags & O_CREAT2 && varargs && memory) new Int32Array(memory.buffer)[varargs >> 2] &= ~umask;
2907
- return openat(dirfd, path, flags, varargs);
2908
- });
2909
- wrapImport(
2910
- imports,
2911
- "mkdirat",
2912
- glue,
2913
- (mkdirat) => (dirfd, path, mode) => mkdirat(dirfd, path, mode & ~umask)
2914
- );
2915
- wrapImport(
2916
- imports,
2917
- "mknodat",
2918
- glue,
2919
- (mknodat) => (dirfd, path, mode, dev) => mknodat(dirfd, path, mode & ~umask, dev)
2920
- );
2921
- wrapImport(imports, "umask", glue, (own) => {
2922
- own(umask);
2923
- return (mask) => {
2924
- const old = umask;
2925
- umask = mask & 511;
2926
- own(umask);
2927
- deps.set(umask);
2928
- return old;
2929
- };
2930
- });
2931
- }
2932
- function touching(times, memory) {
2933
- if (times === 0) return true;
2934
- if (!memory) return false;
2935
- const heap = new Int32Array(memory.buffer);
2936
- const nsec = [heap[times + 8 >> 2], heap[times + 24 >> 2]];
2937
- return nsec.every((n) => n === UTIME_NOW || n === UTIME_OMIT);
2938
- }
2939
- function touch(Fs, on, run) {
2940
- if (!Fs || !on) return run();
2941
- Fs.sliccTouch = true;
2942
- try {
2943
- return run();
2944
- } finally {
2945
- Fs.sliccTouch = void 0;
2946
- }
2947
- }
2948
- function noFollowUtimes(imports, fs, glue, memory = () => void 0) {
2949
- wrapImport(
2950
- imports,
2951
- "utimensat",
2952
- { utimensat: glue },
2953
- (utimensat) => (dirfd, path, times, flags) => {
2954
- const Fs = fs();
2955
- const on = touching(times, memory());
2956
- const { utime, lookupPath, ErrnoError } = Fs ?? {};
2957
- if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW) || !utime || !lookupPath || !ErrnoError) {
2958
- return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2959
- }
2960
- Fs.utime = (at, atime, mtime) => {
2961
- const { node } = lookupPath.call(Fs, at, { follow: false });
2962
- if (!node.node_ops.setattr) throw new ErrnoError(EMSCRIPTEN_EPERM);
2963
- node.node_ops.setattr(node, { atime, mtime });
2964
- };
2965
- try {
2966
- return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2967
- } finally {
2968
- Fs.utime = utime;
2969
- }
2970
- }
2971
- );
2972
- }
2973
- function errnoOf(err) {
2974
- const { errno: errno2, code: code2 } = err ?? {};
2975
- if (typeof errno2 === "number") return errno2;
2976
- if (typeof code2 === "string") return wasiErrno(code2);
2977
- throw err;
2978
- }
2979
- function persistsItself(stream) {
2980
- const type = stream.node.mount?.type;
2981
- return typeof type?.syncfs === "function";
2982
- }
2983
- function namespaces(imports) {
2984
- const seen = /* @__PURE__ */ new Set();
2985
- for (const namespace of Object.values(imports)) {
2986
- if (namespace && typeof namespace === "object") seen.add(namespace);
2987
- }
2988
- return [...seen];
2989
- }
2990
- function keyOf(namespace, name2, glue) {
2991
- const own = glue?.[name2];
2992
- const found = typeof own === "function" ? Object.keys(namespace).find((k) => namespace[k] === own) : void 0;
2993
- return found ?? (typeof namespace[name2] === "function" ? name2 : void 0);
2994
- }
2995
- function syncFsync(imports, fs, glue) {
2996
- for (const namespace of namespaces(imports)) {
2997
- const key = keyOf(namespace, "fd_sync", glue);
2998
- const original = key === void 0 ? void 0 : namespace[key];
2999
- if (key === void 0 || !original?.isAsync) continue;
3000
- namespace[key] = (fd) => {
3001
- const stream = fs()?.getStream(fd);
3002
- if (!stream) return EBADF;
3003
- if (persistsItself(stream)) return original(fd);
3004
- try {
3005
- const result = stream.stream_ops.fsync?.(stream);
3006
- return typeof result === "number" ? result : 0;
3007
- } catch (err) {
3008
- return errnoOf(err);
3009
- }
3010
- };
3011
- }
3012
- }
3013
- function offsetOf(rest2) {
3014
- const at = rest2.length >= 3 ? Number(rest2[1]) * 2 ** 32 + (Number(rest2[0]) >>> 0) : Number(BigInt.asIntN(64, BigInt(rest2[0])));
3015
- return at >= 0 && Number.isSafeInteger(at) ? at : void 0;
3016
- }
3017
- function readInto(sys, kfd, target, at) {
3018
- let done = 0;
3019
- while (done < target.length) {
3020
- const got = sys.pread?.(kfd, target.length - done, at + done) ?? new Uint8Array(0);
3021
- if (got.length === 0) break;
3022
- target.set(got, done);
3023
- done += got.length;
3024
- }
3025
- return done;
3026
- }
3027
- function positioned(original, write2, deps) {
3028
- return (fd, iov, iovcnt, ...rest2) => {
3029
- const stream = deps.fs()?.getStream(Number(fd));
3030
- const memory = deps.memory();
3031
- const kfd = stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
3032
- if (kfd === void 0 || !memory || !(write2 ? deps.sys.pwrite : deps.sys.pread)) {
3033
- return original(fd, iov, iovcnt, ...rest2);
3034
- }
3035
- const at = offsetOf(rest2);
3036
- if (at === void 0) return wasiErrno("EINVAL");
3037
- const view = new DataView(memory.buffer);
3038
- let done = 0;
3039
- try {
3040
- for (let i = 0; i < Number(iovcnt); i++) {
3041
- const ptr = view.getUint32(Number(iov) + i * 8, true);
3042
- const len = view.getUint32(Number(iov) + i * 8 + 4, true);
3043
- const part = new Uint8Array(memory.buffer, ptr, len);
3044
- const moved = write2 ? deps.sys.pwrite?.(kfd, part.slice(), at + done) ?? 0 : readInto(deps.sys, kfd, part, at + done);
3045
- done += moved;
3046
- if (moved < len) break;
3047
- }
3048
- } catch (err) {
3049
- return errnoOf(err);
3050
- }
3051
- view.setUint32(Number(rest2[rest2.length - 1]), done, true);
3052
- return 0;
3053
- };
3054
- }
3055
- function positionalIo(imports, deps) {
3056
- for (const namespace of namespaces(imports)) {
3057
- for (const [name2, write2] of [
3058
- ["fd_pread", false],
3059
- ["fd_pwrite", true]
3060
- ]) {
3061
- const key = keyOf(namespace, name2, deps.glue);
3062
- if (key !== void 0) {
3063
- namespace[key] = positioned(namespace[key], write2, deps);
3064
- }
3065
- }
3066
- }
3067
- }
3068
- function staging(Fs, length) {
3069
- try {
3070
- return new Uint8Array(length);
3071
- } catch {
3072
- throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
3073
- }
3074
- }
3075
- function useFileMmap(Fs, deps) {
3076
- const fs = Fs;
3077
- const mmap = fs.mmap;
3078
- if (typeof mmap !== "function") return;
3079
- fs.mmap = (stream, length, position, prot, flags) => {
3080
- const memalign = deps.memalign();
3081
- const memory = deps.memory();
3082
- const shared = (flags & MAP_TYPE) !== MAP_PRIVATE && (prot & PROT_WRITE) !== 0;
3083
- const kfd = stream.sliccKernelFile ? stream.sliccKernelFd : void 0;
3084
- if (shared && kfd !== void 0) throw new Fs.ErrnoError(wasiErrno("ENODEV"));
3085
- if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE2) === O_WRONLY || !Fs.isFile(stream.node.mode)) {
3086
- return mmap.call(fs, stream, length, position, prot, flags);
3087
- }
3088
- const data = staging(Fs, length);
3089
- let done = 0;
3090
- try {
3091
- if (kfd !== void 0) done = readInto(deps.sys, kfd, data, position);
3092
- else {
3093
- for (let got = 1; done < length && got > 0; done += got) {
3094
- got = Fs.read(stream, data, done, length - done, position + done);
3095
- }
3096
- }
3097
- } catch (err) {
3098
- throw new Fs.ErrnoError(errnoOf(err));
3099
- }
3100
- const size = Math.ceil(length / MAP_ALIGN) * MAP_ALIGN;
3101
- const ptr = memalign(MAP_ALIGN, size);
3102
- if (!ptr) throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
3103
- const target = new Uint8Array(memory.buffer, ptr, size);
3104
- target.fill(0);
3105
- target.set(data.subarray(0, done));
3106
- return { ptr, allocated: true };
3107
- };
3108
- }
3109
- function wasmMemory(instance, imports) {
3110
- const isMemory = (v) => v instanceof WebAssembly.Memory;
3111
- const exported = Object.values(instance.exports).find(isMemory);
3112
- if (exported) return exported;
3113
- for (const namespace of Object.values(imports)) {
3114
- const found = Object.values(namespace ?? {}).find(isMemory);
3115
- if (found) return found;
3116
- }
3117
- return void 0;
3118
- }
3119
- function fdOfPath(path, cwd) {
3120
- const parts = [];
3121
- for (const part of `${path.startsWith("/") ? "" : cwd}/${path}`.split("/")) {
3122
- if (part === "" || part === ".") continue;
3123
- if (part === "..") parts.pop();
3124
- else parts.push(part);
3125
- }
3126
- const abs = `/${parts.join("/")}`;
3127
- const std = ["/dev/stdin", "/dev/stdout", "/dev/stderr"].indexOf(abs);
3128
- if (std >= 0) return std;
3129
- const m = /^\/(?:dev|proc\/self)\/fd\/(\d+)$/.exec(abs);
3130
- return m ? Number(m[1]) : void 0;
3131
- }
3132
- function syntheticAttr(mode, ino) {
3133
- const now = /* @__PURE__ */ new Date();
3134
- return {
3135
- dev: 1,
3136
- ino,
3137
- mode,
3138
- nlink: 1,
3139
- uid: 0,
3140
- gid: 0,
3141
- rdev: 0,
3142
- size: 0,
3143
- atime: now,
3144
- mtime: now,
3145
- ctime: now,
3146
- blksize: 4096,
3147
- blocks: 0
3148
- };
3149
- }
3150
- function describeFdDir(Fs) {
3151
- let dir;
3152
- try {
3153
- dir = Fs.lookupPath?.("/proc/self/fd", { follow: true })?.node;
3154
- } catch {
3155
- return;
3156
- }
3157
- const ops = dir?.node_ops;
3158
- const lookup2 = ops?.lookup;
3159
- if (!dir || !lookup2 || ops.getattr) return;
3160
- dir.node_ops = {
3161
- ...ops,
3162
- getattr: () => syntheticAttr(DIR_MODE, 1),
3163
- lookup: (parent, name2) => {
3164
- const entry = lookup2(parent, name2);
3165
- entry.node_ops = {
3166
- ...entry.node_ops,
3167
- getattr: () => syntheticAttr(LINK_MODE, entry.id ?? 0)
3168
- };
3169
- return entry;
3170
- }
3171
- };
3172
- }
3173
- function useZeroDevices(Fs) {
3174
- const { analyzePath, registerDevice, mkdev, makedev } = Fs;
3175
- if (!analyzePath || !registerDevice || !mkdev || !makedev) return;
3176
- const zeros = (_s, buffer, offset, length) => {
3177
- buffer.fill(0, offset, offset + length);
3178
- return length;
3179
- };
3180
- const devices = [
3181
- ["/dev/zero", 5, (_s, _b, _o, length) => length],
3182
- [
3183
- "/dev/full",
3184
- 7,
3185
- (_s, _b, _o, length) => {
3186
- if (length > 0) throw new Fs.ErrnoError(wasiErrno("ENOSPC"));
3187
- return 0;
3188
- }
3189
- ]
3190
- ];
3191
- for (const [path, minor, write2] of devices) {
3192
- if (analyzePath.call(Fs, path).exists) continue;
3193
- const dev = makedev.call(Fs, 1, minor);
3194
- registerDevice.call(Fs, dev, { read: zeros, write: write2, llseek: () => 0 });
3195
- mkdev.call(Fs, path, CHAR_DEVICE, dev);
3196
- }
3197
- }
3198
- function linkStdio(Fs) {
3199
- const { unlink, symlink } = Fs;
3200
- if (!unlink || !symlink) return;
3201
- for (const [fd, name2] of ["stdin", "stdout", "stderr"].entries()) {
3202
- try {
3203
- unlink.call(Fs, `/dev/${name2}`);
3204
- } catch {
3205
- }
3206
- try {
3207
- symlink.call(Fs, `/proc/self/fd/${fd}`, `/dev/${name2}`);
3208
- } catch {
3209
- }
3210
- }
3211
- }
3212
- function useDevFd(Fs) {
3213
- if (typeof Fs.open !== "function") return;
3214
- try {
3215
- Fs.symlink?.("/proc/self/fd", "/dev/fd");
3216
- } catch {
3217
- }
3218
- linkStdio(Fs);
3219
- describeFdDir(Fs);
3220
- const fdOf = (path) => typeof path === "string" ? fdOfPath(path, Fs.cwd()) : void 0;
3221
- const target = (fd) => {
3222
- const stream = Fs.getStream(fd);
3223
- if (!stream) throw new Fs.ErrnoError(wasiErrno("EBADF"));
3224
- return stream;
3225
- };
3226
- const open = Fs.open.bind(Fs);
3227
- Fs.open = (path, flags, mode) => {
3228
- const fd = fdOf(path);
3229
- if (fd === void 0) return open(path, flags, mode);
3230
- const copy2 = Fs.dupStream(target(fd), -1);
3231
- setCloseOnExec(copy2, typeof flags === "number" && (flags & O_CLOEXEC) !== 0);
3232
- return copy2;
3233
- };
3234
- const { stat, fstat } = Fs;
3235
- if (typeof stat !== "function" || typeof fstat !== "function") return;
3236
- Fs.stat = (path, dontFollow) => {
3237
- const fd = dontFollow ? void 0 : fdOf(path);
3238
- if (fd === void 0) return stat.call(Fs, path, dontFollow);
3239
- target(fd);
3240
- return fstat.call(Fs, fd);
3241
- };
3242
- }
3243
- function pinRootKind() {
3244
- pinnedRoot = rootKind();
3245
- }
3246
- function mountTable(mounts = []) {
3247
- const root = pinnedRoot ?? rootKind();
3248
- const lines = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
3249
- for (const m of mounts) {
3250
- const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
3251
- if (m.state !== "ok") options.push(m.state);
3252
- const access = options.includes("ro") ? [] : ["rw"];
3253
- lines.push(
3254
- `${field(m.source)} ${field(m.target)} ${m.type} ${[...access, ...options].join(",")} 0 0`
3255
- );
3256
- }
3257
- return `${lines.join("\n")}
3258
- `;
3259
- }
3260
- function accounts(env = {}) {
3261
- const user = env.USER ?? "web_user";
3262
- const name2 = NAME.test(user) && user !== "root" ? user : "user";
3263
- const home = env.HOME || "/home";
3264
- return {
3265
- passwd: `root:x:0:0:root:/root:/bin/sh
3266
- ${name2}:x:1000:1000:${name2}:${home}:/bin/bash
3267
- `,
3268
- group: `root:x:0:
3269
- ${name2}:x:1000:
3270
- `
3271
- };
3272
- }
3273
- function useMounts(Fs, env = {}, live = false) {
3274
- const { writeFile, mkdirTree } = Fs;
3275
- if (typeof Fs.open !== "function" || typeof writeFile !== "function") return;
3276
- const { passwd, group } = accounts(env);
3277
- const backing = { "/etc/mtab": "/proc/mounts" };
3278
- try {
3279
- if (!live) writeFile.call(Fs, "/proc/mounts", mountTable());
3280
- } catch {
3281
- return;
3282
- }
3283
- try {
3284
- mkdirTree.call(Fs, "/dev/.etc");
3285
- writeFile.call(Fs, "/dev/.etc/passwd", passwd);
3286
- writeFile.call(Fs, "/dev/.etc/group", group);
3287
- writeFile.call(Fs, "/dev/.etc/hosts", hostsFile(hostnameOf(env)));
3288
- writeFile.call(Fs, "/dev/.etc/hostname", `${hostnameOf(env)}
3289
- `);
3290
- backing["/etc/passwd"] = "/dev/.etc/passwd";
3291
- backing["/etc/group"] = "/dev/.etc/group";
3292
- backing["/etc/hosts"] = "/dev/.etc/hosts";
3293
- backing["/etc/hostname"] = "/dev/.etc/hostname";
3294
- } catch {
3295
- }
3296
- const open = Fs.open.bind(Fs);
3297
- Fs.open = (path, flags, mode) => {
3298
- const instead = backing[path];
3299
- if (!instead || (flags & (O_ACCMODE2 | O_CREAT2)) !== 0) return open(path, flags, mode);
3300
- try {
3301
- return open(path, flags, mode);
3302
- } catch (e) {
3303
- if (e?.errno !== wasiErrno("ENOENT")) throw e;
3304
- return open(instead, flags, mode);
3305
- }
3306
- };
3307
- }
3308
- function cString(memory, at) {
3309
- const bytes = new Uint8Array(memory.buffer, at);
3310
- return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
3311
- }
3312
- function baseOf(Fs, dirfd) {
3313
- return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
3314
- }
3315
- function readonlyRefusal(Fs, memory, call2) {
3316
- if (!(call2.amode & W_ACCESS)) return 0;
3317
- try {
3318
- const name2 = cString(memory, call2.path);
3319
- const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
3320
- const follow2 = (call2.flags & AT_SYMLINK_NOFOLLOW) === 0;
3321
- const { node } = Fs.lookupPath.call(Fs, abs, {
3322
- follow: follow2
3323
- });
3324
- const bridge = node.live ? node.mount.opts.bridge : void 0;
3325
- const stats = bridge;
3326
- const stat = follow2 ? stats?.stat : stats?.lstat;
3327
- return stat?.call(stats, liveNodePath(node)).readonly ? -wasiErrno("EROFS") : 0;
3328
- } catch {
3329
- return 0;
3330
- }
3331
- }
3332
- function kernelChecks(Fs, memory, call2) {
3333
- const name2 = cString(memory, call2.path);
3334
- const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
3335
- const lookupPath = Fs.lookupPath;
3336
- const { node } = lookupPath.call(Fs, abs, { follow: (call2.flags & AT_SYMLINK_NOFOLLOW) === 0 });
3337
- const bridge = node.live ? node.mount.opts.bridge : void 0;
3338
- if (!bridge?.owners || !bridge.access) return 0;
3339
- const kind = call2.flags & AT_EACCESS ? "eaccess" : "access";
3340
- bridge.access(liveNodePath(node), call2.amode, kind, (call2.flags & AT_SYMLINK_NOFOLLOW) !== 0);
3341
- return 0;
3342
- }
3343
- function kernelAccess(imports, fs, memory, glue) {
3344
- wrapImport(imports, "faccessat", glue, (own) => (dirfd, path, amode, flags) => {
3345
- const Fs = fs();
3346
- const heap = memory();
3347
- const call2 = { dirfd, path, amode: amode & 7, flags };
3348
- const refused = Fs?.lookupPath && heap ? readonlyRefusal(Fs, heap, call2) : 0;
3349
- if (refused !== 0) return refused;
3350
- const rc = own(dirfd, path, amode, flags);
3351
- if (rc !== 0 || !Fs?.lookupPath || !heap) return rc;
3352
- try {
3353
- return kernelChecks(Fs, heap, { dirfd, path, amode: amode & 7, flags });
3354
- } catch (err) {
3355
- return -errnoOf(err);
3356
- }
3357
- });
3358
- }
3359
- function kernelLink(imports, fs, memory, glue) {
3360
- wrapImport(
3361
- imports,
3362
- "linkat",
3363
- glue,
3364
- (own) => (olddirfd, oldpath, newdirfd, newpath, flags) => {
3365
- const Fs = fs();
3366
- const heap = memory();
3367
- if (!Fs?.lookupPath || !heap) return own(olddirfd, oldpath, newdirfd, newpath, flags);
3368
- const at = (dirfd, ptr) => {
3369
- const name2 = cString(heap, ptr);
3370
- return name2.startsWith("/") ? name2 : `${baseOf(Fs, dirfd)}/${name2}`;
3371
- };
3372
- try {
3373
- const from = at(olddirfd, oldpath);
3374
- const to = at(newdirfd, newpath);
3375
- const follow2 = (flags & AT_SYMLINK_FOLLOW) !== 0;
3376
- if (linkLive(Fs, from, to, follow2)) return 0;
3377
- } catch (err) {
3378
- return -errnoOf(err);
3379
- }
3380
- return own(olddirfd, oldpath, newdirfd, newpath, flags);
3381
- },
3382
- true
3383
- );
3384
- }
3385
- function kernelChdir(Fs) {
3386
- const { chdir, lookupPath, ErrnoError } = Fs;
3387
- if (!chdir || !lookupPath || !ErrnoError) return;
3388
- Fs.chdir = (path) => {
3389
- const { node } = lookupPath.call(Fs, path, { follow: true });
3390
- const directory = Fs.isDir?.(node.mode) === true;
3391
- const bridge = node.live && directory ? node.mount.opts.bridge : void 0;
3392
- try {
3393
- bridge?.access?.(liveNodePath(node), X_ACCESS, "eaccess", false);
3394
- } catch (err) {
3395
- throw new ErrnoError(errnoOf(err));
3396
- }
3397
- chdir.call(Fs, path);
3398
- };
3399
- }
3400
- function linuxDevices(Fs) {
3401
- Fs.ignorePermissions = true;
3402
- kernelChdir(Fs);
3403
- const { chmod } = Fs;
3404
- if (!chmod) return;
3405
- for (const [path, mode] of DEVICE_MODES) {
3406
- try {
3407
- chmod.call(Fs, path, mode);
3408
- } catch {
3409
- }
3410
- }
3411
- }
3412
- 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_PATH2, LITERALS, 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, pinnedRoot, rootKind, NAME, AT_FDCWD, AT_EACCESS, W_ACCESS, X_ACCESS, AT_SYMLINK_FOLLOW, DEVICE_MODES;
3413
- var init_process_fds = __esm({
3414
- "src/process/process-fds.ts"() {
3415
- "use strict";
3416
- init_loopback_names();
3417
- init_live_vfs_fs();
3418
- init_process_pty();
3419
- init_wasi_errno();
3420
- O_CLOEXEC = 524288;
3421
- FD_CLOEXEC = 1;
3422
- F_DUPFD = 0;
3423
- F_GETFD = 1;
3424
- F_SETFD = 2;
3425
- F_GETFL = 3;
3426
- F_DUPFD_CLOEXEC = 1030;
3427
- tracked = /* @__PURE__ */ new WeakSet();
3428
- IMPORT_NAMES = {
3429
- fcntl: "__syscall_fcntl64",
3430
- pipe2: "__syscall_pipe2",
3431
- dup3: "__syscall_dup3",
3432
- socket: "__syscall_socket",
3433
- accept4: "__syscall_accept4",
3434
- ioctl: "__syscall_ioctl",
3435
- setitimer: "_setitimer_js"
3436
- };
3437
- EBADF = 8;
3438
- AT_SYMLINK_NOFOLLOW = 256;
3439
- EMSCRIPTEN_EPERM = 63;
3440
- O_PATH2 = 2097152;
3441
- LITERALS = {
3442
- openat: "__syscall_openat",
3443
- mkdirat: "__syscall_mkdirat",
3444
- mknodat: "__syscall_mknodat",
3445
- umask: "__syscall_umask",
3446
- faccessat: "__syscall_faccessat",
3447
- linkat: "__syscall_linkat",
3448
- utimensat: "__syscall_utimensat",
3449
- getppid: "slicc_getppid_js",
3450
- resizeHeap: "emscripten_resize_heap",
3451
- fdWrite: "fd_write",
3452
- fdRead: "fd_read",
3453
- sleepMs: "slicc_sleep_ms"
3690
+ throw new SyscallError("ESPIPE");
3691
+ }),
3692
+ read: (s, buffer, offset, length) => this.call(() => {
3693
+ const bytes = this.restarting(() => this.sys.read(kfd, length, nonblocking(s)));
3694
+ buffer.set(bytes, offset);
3695
+ return bytes.length;
3696
+ }),
3697
+ write: (s, buffer, offset, length) => {
3698
+ try {
3699
+ const bytes = buffer.slice(offset, offset + length);
3700
+ return this.restarting(() => this.sys.write(kfd, bytes, nonblocking(s)));
3701
+ } catch (e) {
3702
+ if (e instanceof SyscallError && e.code === "EPIPE" && !this.options.sigpipe?.()) {
3703
+ throw new ProcessExit(KILLED_BY_SIGPIPE);
3704
+ }
3705
+ return this.call(() => {
3706
+ throw e;
3707
+ });
3708
+ }
3709
+ },
3710
+ fsync: () => 0,
3711
+ poll: () => {
3712
+ const state = this.call(() => this.sys.poll(kfd));
3713
+ let mask = 0;
3714
+ if (state.readable) mask |= POLLIN | POLLRDNORM;
3715
+ if (state.writable) mask |= POLLOUT | POLLWRNORM;
3716
+ if (state.hangup) mask |= state.readable ? POLLHUP : POLLERR;
3717
+ return mask;
3718
+ },
3719
+ dup: (stream) => {
3720
+ base.dup?.(stream);
3721
+ this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
3722
+ },
3723
+ close: (stream) => {
3724
+ if (this.atExit && stream.fd === 2 && this.reporting.size > 0) this.commitStdout();
3725
+ try {
3726
+ base.close?.(stream);
3727
+ } catch {
3728
+ }
3729
+ const left = (this.refs.get(kfd) ?? 1) - 1;
3730
+ if (left > 0) {
3731
+ this.refs.set(kfd, left);
3732
+ return;
3733
+ }
3734
+ this.refs.delete(kfd);
3735
+ if (this.committed.size > 0 && this.committed.delete(kfd)) return;
3736
+ if (this.reporting.size > 0 && this.reporting.delete(kfd)) {
3737
+ this.reportedClose(stream, kfd);
3738
+ return;
3739
+ }
3740
+ try {
3741
+ this.sys.close(kfd);
3742
+ } catch {
3743
+ }
3744
+ }
3745
+ };
3746
+ }
3454
3747
  };
3455
- UTIME_NOW = 1073741823;
3456
- UTIME_OMIT = 1073741822;
3457
- PROT_WRITE = 2;
3458
- MAP_PRIVATE = 2;
3459
- MAP_TYPE = 15;
3460
- O_WRONLY = 1;
3461
- MAP_ALIGN = 65536;
3462
- DIR_MODE = 16749;
3463
- LINK_MODE = 41408;
3464
- CHAR_DEVICE = 8630;
3465
- O_ACCMODE2 = 3;
3466
- O_CREAT2 = 64;
3467
- field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
3468
- rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
3469
- NAME = /^[a-z_][a-z0-9_-]*$/i;
3470
- AT_FDCWD = -100;
3471
- AT_EACCESS = 512;
3472
- W_ACCESS = 2;
3473
- X_ACCESS = 1;
3474
- AT_SYMLINK_FOLLOW = 1024;
3475
- DEVICE_MODES = [
3476
- ["/", 493],
3477
- ["/dev", 493],
3478
- ["/dev/null", 438],
3479
- ["/dev/zero", 438],
3480
- ["/dev/full", 438],
3481
- ["/dev/random", 438],
3482
- ["/dev/urandom", 438],
3483
- ["/dev/tty", 438],
3484
- ["/dev/shm", 1023]
3485
- ];
3486
3748
  }
3487
3749
  });
3488
3750
 
@@ -3542,7 +3804,8 @@ function kernelEntry(stream, kernel) {
3542
3804
  }
3543
3805
  const device2 = stream.path === void 0 ? void 0 : NAMED_DEVICES[stream.path];
3544
3806
  const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : device2 ?? "stream";
3545
- return { fd: stream.fd, kernel, kind, ...cloexec };
3807
+ const access = kind === "tty" ? O_RDWR : (stream.flags ?? O_RDWR) & O_ACCMODE3;
3808
+ return { fd: stream.fd, kernel, kind, flags: access, ...cloexec };
3546
3809
  }
3547
3810
  function describeInherited(Fs, sys, streams, livePath, actions = []) {
3548
3811
  const table = /* @__PURE__ */ new Map();
@@ -3589,12 +3852,13 @@ function place(Fs, stream, fd) {
3589
3852
  return moved;
3590
3853
  }
3591
3854
  function placeholder(Fs, streams, entry) {
3592
- if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR);
3855
+ const access = entry.flags ?? O_RDWR;
3856
+ if (entry.kind === "socket") return streams.socketStream(access);
3593
3857
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
3594
3858
  if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
3595
- return Fs.open("/dev/null", O_RDWR);
3859
+ return Fs.open("/dev/null", access);
3596
3860
  Fs.mkdirTree(PLACEHOLDER_DIR);
3597
- return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, O_RDWR | O_CREAT3);
3861
+ return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, access | O_CREAT3);
3598
3862
  }
3599
3863
  function asFifo(stream, streams, identity) {
3600
3864
  const inos = streamInos.get(streams) ?? /* @__PURE__ */ new Map();
@@ -4295,7 +4559,7 @@ var KERNEL_VERSION, OS_RELEASE;
4295
4559
  var init_version = __esm({
4296
4560
  "src/version.ts"() {
4297
4561
  "use strict";
4298
- KERNEL_VERSION = true ? "1.92.0" : "0.0.0-dev";
4562
+ KERNEL_VERSION = true ? "1.93.0" : "0.0.0-dev";
4299
4563
  OS_RELEASE = "6.0.0-slicc";
4300
4564
  }
4301
4565
  });
@@ -4796,6 +5060,20 @@ function kernelSys(transport) {
4796
5060
  size(fd) {
4797
5061
  return json2(call2({ op: "fd-vfs-stat", fd }, `fd-vfs-stat ${fd}`)).size;
4798
5062
  },
5063
+ fdStat(fd) {
5064
+ const r = json2(call2({ op: "fd-vfs-stat", fd, full: true }, `fd-vfs-stat ${fd}`));
5065
+ return r?.stat;
5066
+ },
5067
+ fdChmod(fd, mode) {
5068
+ call2({ op: "fd-chmod", fd, mode }, `fd-chmod ${fd}`);
5069
+ },
5070
+ fdChown(fd, uid, gid) {
5071
+ const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
5072
+ call2({ op: "fd-chown", fd, ...ids }, `fd-chown ${fd}`);
5073
+ },
5074
+ fdUtimes(fd, atimeMs, mtimeMs, now) {
5075
+ call2({ op: "fd-utimes", fd, atimeMs, mtimeMs, now }, `fd-utimes ${fd}`);
5076
+ },
4799
5077
  ttyNames() {
4800
5078
  return json2(call2({ op: "fd-tty-names" }, "fd-tty-names"));
4801
5079
  },
@@ -4827,6 +5105,9 @@ function kernelSys(transport) {
4827
5105
  openClipboard(flags) {
4828
5106
  return json2(call2({ op: "fd-open-clipboard", flags }, "fd-open-clipboard"));
4829
5107
  },
5108
+ clipboardAbort(fd) {
5109
+ call2({ op: "fd-clipboard-abort", fd }, "fd-clipboard-abort");
5110
+ },
4830
5111
  ptyNumbers() {
4831
5112
  return json2(call2({ op: "pty-list" }, "pty-list"));
4832
5113
  },
@@ -4865,7 +5146,7 @@ function openDevice(Fs, fd, meta) {
4865
5146
  return openAt(Fs, fd, `/dev/${meta.device}`, accessMode(meta.access));
4866
5147
  }
4867
5148
  function openHeld(Fs, fd, meta) {
4868
- return "dir" in meta ? openAt(Fs, fd, meta.dir, O_RDONLY | O_DIRECTORY) : openDevice(Fs, fd, meta);
5149
+ return "dir" in meta ? openAt(Fs, fd, meta.dir, O_RDONLY | O_DIRECTORY2) : openDevice(Fs, fd, meta);
4869
5150
  }
4870
5151
  function openAt(Fs, fd, path, flags) {
4871
5152
  let stream;
@@ -4977,6 +5258,17 @@ function kernelWrappers(imports, module, deps) {
4977
5258
  function bridgeFlags(init) {
4978
5259
  return { ...init.owners ? { owners: true } : {}, ...init.links ? { links: true } : {} };
4979
5260
  }
5261
+ function credSyncTransport(gated, early, cred) {
5262
+ return {
5263
+ call: (req, timeoutMs, label) => {
5264
+ if (!FS_OPS.has(req.op)) early();
5265
+ const r = gated.call(req, timeoutMs, label);
5266
+ if (cred && req.op === "proc-setcred" && r.ok && r.kind === "json")
5267
+ Object.assign(cred, r.json);
5268
+ return r;
5269
+ }
5270
+ };
5271
+ }
4980
5272
  async function runWasmProcess(init, port2, deps = {}) {
4981
5273
  const signals = new SignalGate(
4982
5274
  createSyncSabTransport(init.sab, port2, {
@@ -4995,12 +5287,7 @@ async function runWasmProcess(init, port2, deps = {}) {
4995
5287
  const gated = signals.transport();
4996
5288
  let early = () => {
4997
5289
  };
4998
- const transport = {
4999
- call: (req, timeoutMs, label) => {
5000
- if (!FS_OPS.has(req.op)) early();
5001
- return gated.call(req, timeoutMs, label);
5002
- }
5003
- };
5290
+ const transport = credSyncTransport(gated, () => early(), init.cred);
5004
5291
  const sys = kernelSys(transport);
5005
5292
  const encoder5 = new TextEncoder();
5006
5293
  const say = (fd) => (text) => sys.write(fd, encoder5.encode(`${text}
@@ -5083,7 +5370,8 @@ async function runWasmProcess(init, port2, deps = {}) {
5083
5370
  const vfs = mountVfsIntoEmscripten(running.FS, {
5084
5371
  bridge: createSyncFsSabBridge(transport, bridgeFlags(init)),
5085
5372
  cwd: init.cwd,
5086
- warn: deps.warn ?? say(2)
5373
+ warn: deps.warn ?? say(2),
5374
+ cred: init.owners ? init.cred : void 0
5087
5375
  });
5088
5376
  early = () => signals.quiet(() => vfs.flushDirty());
5089
5377
  const sigpipe = () => running.sliccSigpipe?.() === 1;
@@ -5102,6 +5390,7 @@ async function runWasmProcess(init, port2, deps = {}) {
5102
5390
  atExit = () => streams.exiting();
5103
5391
  useMounts(running.FS, init.env, true);
5104
5392
  useZeroDevices(running.FS);
5393
+ useDevRemoval(running.FS);
5105
5394
  useProcfs(running.FS, sys, init.pid);
5106
5395
  if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
5107
5396
  else {
@@ -5111,6 +5400,7 @@ async function runWasmProcess(init, port2, deps = {}) {
5111
5400
  const pipefs = ownValue(running, "PIPEFS");
5112
5401
  if (pipefs) streams.usePipes(pipefs);
5113
5402
  streams.useControllingTerminal();
5403
+ streams.useKernelFdMetadata();
5114
5404
  useDevFd(running.FS);
5115
5405
  useFileMmap(running.FS, {
5116
5406
  sys,
@@ -5122,9 +5412,9 @@ async function runWasmProcess(init, port2, deps = {}) {
5122
5412
  transport,
5123
5413
  Fs: running.FS,
5124
5414
  env: init.env,
5415
+ pid: init.pid,
5125
5416
  beforeSpawn: () => vfs.flush(),
5126
5417
  afterChild: () => vfs.invalidate(),
5127
- pid: init.pid,
5128
5418
  raise: (sig) => running.sliccRaise?.(sig),
5129
5419
  restartable,
5130
5420
  memory: () => memory,
@@ -5144,6 +5434,9 @@ async function runWasmProcess(init, port2, deps = {}) {
5144
5434
  sigpipe,
5145
5435
  restartable
5146
5436
  });
5437
+ return runWithFlush(running, init, streams, vfs);
5438
+ }
5439
+ function runWithFlush(running, init, streams, vfs) {
5147
5440
  try {
5148
5441
  return streams.exitStatus(runMain(running, init));
5149
5442
  } finally {
@@ -5208,7 +5501,7 @@ function runMain(running, init) {
5208
5501
  return status2;
5209
5502
  }
5210
5503
  }
5211
- var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE4, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
5504
+ var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, O_ACCMODE4, O_DIRECTORY2, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
5212
5505
  var init_process_runtime = __esm({
5213
5506
  "src/process/process-runtime.ts"() {
5214
5507
  "use strict";
@@ -5234,7 +5527,7 @@ var init_process_runtime = __esm({
5234
5527
  O_WRONLY3 = 1;
5235
5528
  O_RDWR3 = 2;
5236
5529
  O_ACCMODE4 = 3;
5237
- O_DIRECTORY = 65536;
5530
+ O_DIRECTORY2 = 65536;
5238
5531
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY3 : O_RDWR3;
5239
5532
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard", "sealed"]);
5240
5533
  GLUE_TRAILER = [
@@ -5360,6 +5653,21 @@ function physicalPath(fs, path) {
5360
5653
  }
5361
5654
  return `/${walk.done.join("/")}`;
5362
5655
  }
5656
+ async function physicalPathAsync(fs, path) {
5657
+ const walk = start(path);
5658
+ for (let part = next(walk); part !== void 0; part = next(walk)) {
5659
+ const at = `/${[...walk.done, part].join("/")}`;
5660
+ let target;
5661
+ try {
5662
+ target = (await fs.lstat(at)).isSymbolicLink ? await fs.readlink(at) : void 0;
5663
+ } catch {
5664
+ return rest(walk, part);
5665
+ }
5666
+ if (target === void 0) walk.done.push(part);
5667
+ else if (!follow(walk, target)) return lexical(path);
5668
+ }
5669
+ return `/${walk.done.join("/")}`;
5670
+ }
5363
5671
  var MAX_HOPS;
5364
5672
  var init_physical_path = __esm({
5365
5673
  "src/fs/physical-path.ts"() {
@@ -5584,9 +5892,11 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
5584
5892
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
5585
5893
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
5586
5894
  ...bridge.pinned ? { pinned: (handle) => pinnedIo2(bridge, handle, rewriting) } : {},
5587
- ...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p), ...entry(p)) } : {},
5895
+ ...bridge.create ? {
5896
+ create: (p, mode, opening2) => mutating(() => bridge.create?.(p, mode, opening2), ...entry(p))
5897
+ } : {},
5588
5898
  ...chown ? {
5589
- chown: (p, uid, gid, follow2) => rewriting(p, () => chown.call(bridge, p, uid, gid, follow2))
5899
+ chown: (p, ...rest2) => rewriting(p, () => chown.call(bridge, p, ...rest2))
5590
5900
  } : {},
5591
5901
  ...bridge.pread && bridge.pwrite && bridge.truncate ? {
5592
5902
  pread: bridge.pread.bind(bridge),
@@ -6356,6 +6666,7 @@ var init_wasi_fds = __esm({
6356
6666
  const { buffer } = e.file;
6357
6667
  try {
6358
6668
  buffer.flush();
6669
+ this.reported.delete(buffer);
6359
6670
  } catch (err) {
6360
6671
  this.reported.add(buffer);
6361
6672
  this.drop(buffer);
@@ -6421,6 +6732,7 @@ var init_wasi_fds = __esm({
6421
6732
  for (const buffer of this.buffers.values()) {
6422
6733
  try {
6423
6734
  buffer.flush();
6735
+ this.reported.delete(buffer);
6424
6736
  } catch (err) {
6425
6737
  if (!this.reported.has(buffer)) throw err;
6426
6738
  }
@@ -6643,7 +6955,7 @@ var init_wasi_fds = __esm({
6643
6955
  return true;
6644
6956
  }
6645
6957
  try {
6646
- this.fs.create(path);
6958
+ this.fs.create(path, void 0, true);
6647
6959
  return true;
6648
6960
  } catch (err) {
6649
6961
  if (oflags & OFLAGS.EXCL || err.code !== "EEXIST") throw err;
@@ -6957,7 +7269,7 @@ var init_wasi_termios = __esm({
6957
7269
  });
6958
7270
 
6959
7271
  // src/process/wasi/wasi-host.ts
6960
- function idOf2(value2) {
7272
+ function idOf3(value2) {
6961
7273
  return value2 >>> 0 === 4294967295 ? void 0 : value2 >>> 0;
6962
7274
  }
6963
7275
  function linkedOf(st) {
@@ -7034,6 +7346,7 @@ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, AT_EACCESS2, ROOT_IDS, GONE,
7034
7346
  var init_wasi_host = __esm({
7035
7347
  "src/process/wasi/wasi-host.ts"() {
7036
7348
  "use strict";
7349
+ init_dev_removal();
7037
7350
  init_physical_path();
7038
7351
  init_cpu_clock();
7039
7352
  init_cred();
@@ -7131,10 +7444,10 @@ var init_wasi_host = __esm({
7131
7444
  return path;
7132
7445
  };
7133
7446
  const modeOf2 = (st) => (st.mode ?? 0) & 4095;
7134
- const chown = (path, uid, gid, follow2) => {
7447
+ const chown = (path, uid, gid, follow2, handle) => {
7135
7448
  const { chown: own } = this.o.fs;
7136
7449
  if (!own) throw new WasiError("ENOSYS");
7137
- own.call(this.o.fs, path, idOf2(uid), idOf2(gid), follow2);
7450
+ own.call(this.o.fs, path, idOf3(uid), idOf3(gid), follow2, handle);
7138
7451
  };
7139
7452
  const caller = () => {
7140
7453
  const cred = this.o.kernel.call({ op: "proc-cred" });
@@ -7165,7 +7478,11 @@ var init_wasi_host = __esm({
7165
7478
  return follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path);
7166
7479
  };
7167
7480
  return wrap({
7168
- fd_chown: (fd, uid, gid) => void chown(pathOf(fd), uid, gid, true),
7481
+ fd_chown: (fd, uid, gid) => {
7482
+ const e = fds.get(fd);
7483
+ const handle = e.type === "file" ? e.file.buffer.handle : void 0;
7484
+ void chown(pathOf(fd), uid, gid, true, handle);
7485
+ },
7169
7486
  path_chown: (dirfd, p, l, uid, gid, flags) => void chown(at(dirfd, p, l), uid, gid, (flags & AT_SYMLINK_NOFOLLOW2) === 0),
7170
7487
  fd_owner: (fd, out) => {
7171
7488
  if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
@@ -7177,14 +7494,14 @@ var init_wasi_host = __esm({
7177
7494
  owner(fdOwned(fd), out);
7178
7495
  },
7179
7496
  path_filestat_owner: (dirfd, lookup2, p, l, statOut, out) => {
7180
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7181
7497
  const path = at(dirfd, p, l);
7498
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7182
7499
  this.writeFilestat(statOut, this.pathFilestat(path, lookup2));
7183
7500
  owner(pathOwned(path, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0), out);
7184
7501
  },
7185
7502
  path_owner: (dirfd, p, l, flags, out) => {
7186
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7187
7503
  const path = at(dirfd, p, l);
7504
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7188
7505
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW2) === 0), out);
7189
7506
  },
7190
7507
  path_access: (dirfd, p, l, amode, flags) => {
@@ -7441,14 +7758,35 @@ var init_wasi_host = __esm({
7441
7758
  const { mem, fds, o } = this;
7442
7759
  const at = (dirfd, p, l) => fds.resolve(dirfd, mem.string(p, l));
7443
7760
  return {
7444
- path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
7445
- const path = at(dirfd, p, l);
7446
- if (deviceOf(path)) this.interrupted?.();
7447
- const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
7448
- mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
7449
- if (fresh) this.created(path, 438);
7761
+ path_open: (dirfd, lookup2, p, l, oflags, rights, _inheriting, fdflags, out) => {
7762
+ const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
7763
+ try {
7764
+ const path = at(dirfd, p, l);
7765
+ if (deviceOf(path)) this.interrupted?.();
7766
+ const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
7767
+ mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
7768
+ if (fresh) this.created(path, 438);
7769
+ } catch (err) {
7770
+ if (err.code !== "ENOENT") throw err;
7771
+ const raw = mem.string(p, l);
7772
+ const joined2 = raw.startsWith("/") ? raw : `${fds.dir(dirfd).path}/${raw}`;
7773
+ const resolved2 = this.resolveForDev(joined2, follow2);
7774
+ if (!resolved2) throw err;
7775
+ mem.view().setUint32(out, fds.open(resolved2, oflags, rights, fdflags), true);
7776
+ }
7777
+ },
7778
+ path_filestat_get: (dirfd, lookup2, p, l, out) => {
7779
+ try {
7780
+ this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2));
7781
+ } catch (err) {
7782
+ if (err.code !== "ENOENT") throw err;
7783
+ const raw = mem.string(p, l);
7784
+ const joined2 = raw.startsWith("/") ? raw : `${fds.dir(dirfd).path}/${raw}`;
7785
+ const resolved2 = this.resolveForDev(joined2, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0);
7786
+ if (!resolved2) throw err;
7787
+ this.writeFilestat(out, this.pathFilestat(resolved2, lookup2));
7788
+ }
7450
7789
  },
7451
- path_filestat_get: (dirfd, lookup2, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2)),
7452
7790
  path_filestat_set_times: (dirfd, lookup2, p, l, atim, mtim, flags) => {
7453
7791
  const path = at(dirfd, p, l);
7454
7792
  fds.flushPath(path);
@@ -7463,6 +7801,7 @@ var init_wasi_host = __esm({
7463
7801
  path_remove_directory: (dirfd, p, l) => void o.fs.rmdir(at(dirfd, p, l)),
7464
7802
  path_unlink_file: (dirfd, p, l) => {
7465
7803
  const path = at(dirfd, p, l);
7804
+ if (inDevTree(path)) return void o.fs.unlink(path);
7466
7805
  const st = o.fs.lstat(path);
7467
7806
  if (st.isDirectory) throw new WasiError("EISDIR");
7468
7807
  const linked = linkedOf(st);
@@ -7694,7 +8033,12 @@ var init_wasi_host = __esm({
7694
8033
  const v = this.mem.view();
7695
8034
  v.setUint8(out, filetype);
7696
8035
  v.setUint16(out + 2, flags, true);
7697
- const rights = seeks ? RIGHTS.ALL : RIGHTS.ALL & ~(RIGHTS.FD_SEEK | RIGHTS.FD_TELL);
8036
+ let rights = seeks ? RIGHTS.ALL : RIGHTS.ALL & ~(RIGHTS.FD_SEEK | RIGHTS.FD_TELL);
8037
+ if (e.type === "kernel") {
8038
+ const access = this.o.kernel.sys.access?.(fd);
8039
+ if (access === "read") rights &= ~RIGHTS.FD_WRITE;
8040
+ else if (access === "write") rights &= ~RIGHTS.FD_READ;
8041
+ }
7698
8042
  v.setBigUint64(out + 8, rights, true);
7699
8043
  v.setBigUint64(out + 16, RIGHTS.ALL, true);
7700
8044
  }
@@ -7760,6 +8104,21 @@ var init_wasi_host = __esm({
7760
8104
  synthetic(path) {
7761
8105
  return deviceOf(path) !== void 0 || path === SEALED_PATH2 && !!this.o.kernel.sys.openSealed || path === CLIPBOARD_PATH2 && !!this.o.kernel.sys.openClipboard;
7762
8106
  }
8107
+ resolveForDev(path, follow2 = true) {
8108
+ try {
8109
+ if (!follow2) {
8110
+ const slash = path.lastIndexOf("/");
8111
+ if (slash <= 0) return void 0;
8112
+ const parent = physicalPath(this.o.fs, path.slice(0, slash));
8113
+ const resolved3 = `${parent}/${path.slice(slash + 1)}`;
8114
+ return resolved3 !== path && this.synthetic(resolved3) ? resolved3 : void 0;
8115
+ }
8116
+ const resolved2 = physicalPath(this.o.fs, path);
8117
+ return resolved2 !== path && this.synthetic(resolved2) ? resolved2 : void 0;
8118
+ } catch {
8119
+ return void 0;
8120
+ }
8121
+ }
7763
8122
  pathFilestat(path, lookup2) {
7764
8123
  if (this.synthetic(path)) {
7765
8124
  return this.local({
@@ -7771,7 +8130,19 @@ var init_wasi_host = __esm({
7771
8130
  }
7772
8131
  this.fds.flushPath(path);
7773
8132
  const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
7774
- return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
8133
+ try {
8134
+ return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
8135
+ } catch (err) {
8136
+ if (err.code !== "ENOENT") throw err;
8137
+ const resolved2 = this.resolveForDev(path, follow2);
8138
+ if (!resolved2) throw err;
8139
+ return this.local({
8140
+ filetype: FILETYPE.CHARACTER_DEVICE,
8141
+ size: 0n,
8142
+ ino: pathInode(resolved2),
8143
+ mtimeNs: 0n
8144
+ });
8145
+ }
7775
8146
  }
7776
8147
  setTimes(path, atim, mtim, flags, follow2 = true) {
7777
8148
  const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
@@ -7843,6 +8214,7 @@ var init_wasi_threads = __esm({
7843
8214
  "src/process/wasi/wasi-threads.ts"() {
7844
8215
  "use strict";
7845
8216
  init_protocol();
8217
+ init_sync_sab_wire();
7846
8218
  init_wasi_files();
7847
8219
  LAST_TID = 0;
7848
8220
  RUNNING = 1;
@@ -7878,7 +8250,7 @@ var init_wasi_threads = __esm({
7878
8250
  this.beforeSpawn?.();
7879
8251
  const tid = Atomics.add(this.ids, LAST_TID, 1) + 1;
7880
8252
  const modules = this.modules?.();
7881
- const blocked = this.blocked?.() ?? 0;
8253
+ const blocked = this.blocked?.();
7882
8254
  this.port.postMessage({
7883
8255
  type: WASM_THREAD_SPAWN,
7884
8256
  thread: {
@@ -7887,7 +8259,7 @@ var init_wasi_threads = __esm({
7887
8259
  memory: this.memory,
7888
8260
  ids: this.ids.buffer,
7889
8261
  ...modules ? { modules } : {},
7890
- ...blocked ? { blocked } : {}
8262
+ ...anyBlocked(blocked) ? { blocked } : {}
7891
8263
  }
7892
8264
  });
7893
8265
  return tid;
@@ -8108,7 +8480,8 @@ var init_wasix_process = __esm({
8108
8480
  cwd: this.host.cwd,
8109
8481
  ...fds.isShared ? { shared: true } : {},
8110
8482
  setjmps: this.driver.setjmps(),
8111
- ...this.host.signals ? { signals: this.host.signals.snapshot() } : {}
8483
+ ...this.host.signals ? { signals: this.host.signals.snapshot() } : {},
8484
+ ...this.host.sigmask ? { blocked: this.host.sigmask.inherited() } : {}
8112
8485
  };
8113
8486
  return this.call({
8114
8487
  op: "proc-fork",
@@ -8614,7 +8987,7 @@ function procfsBridge(fs, tree) {
8614
8987
  }
8615
8988
  const { chown } = fs;
8616
8989
  if (chown) {
8617
- over.chown = (p, uid, gid, follow2) => readOnly2([[p, follow2 === true]], () => chown.call(fs, p, uid, gid, follow2));
8990
+ over.chown = (p, ...rest2) => readOnly2([[p, rest2[2] === true]], () => chown.call(fs, p, ...rest2));
8618
8991
  }
8619
8992
  return new Proxy(fs, {
8620
8993
  get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
@@ -8772,7 +9145,7 @@ var init_wasi_sigmask = __esm({
8772
9145
  };
8773
9146
  WasiSigmask = class {
8774
9147
  lo;
8775
- hi = 0;
9148
+ hi;
8776
9149
  header;
8777
9150
  deliver;
8778
9151
  process;
@@ -8781,9 +9154,10 @@ var init_wasi_sigmask = __esm({
8781
9154
  this.deliver = deliver;
8782
9155
  this.process = process;
8783
9156
  this.lo = libcBits(Atomics.load(header, SAB_I_BLOCKED));
9157
+ this.hi = Atomics.load(header, SAB_I_BLOCKED_HI);
8784
9158
  }
8785
9159
  static unsupported(header) {
8786
- Atomics.store(header, SAB_I_BLOCKED, 0);
9160
+ storeBlocked(header, [0, 0]);
8787
9161
  }
8788
9162
  set(how, setLo, setHi, old) {
8789
9163
  if (how !== SIG_BLOCK && how !== SIG_UNBLOCK && how !== SIG_SETMASK) return E.INVAL;
@@ -8791,7 +9165,7 @@ var init_wasi_sigmask = __esm({
8791
9165
  this.lo = apply(how, this.lo, setLo | 0) & ~LIBC_UNBLOCKABLE;
8792
9166
  this.hi = apply(how, this.hi, setHi | 0);
8793
9167
  const now = kernelBits(this.lo);
8794
- Atomics.store(this.header, SAB_I_BLOCKED, now);
9168
+ storeBlocked(this.header, [now, this.hi]);
8795
9169
  if ((Atomics.load(this.header, SAB_I_SIGNALS) & ~now) !== 0) this.deliver();
8796
9170
  return E.SUCCESS;
8797
9171
  }
@@ -8799,7 +9173,7 @@ var init_wasi_sigmask = __esm({
8799
9173
  const old = [this.lo, this.hi];
8800
9174
  this.lo = setLo & ~LIBC_UNBLOCKABLE;
8801
9175
  this.hi = setHi | 0;
8802
- Atomics.store(this.header, SAB_I_BLOCKED, kernelBits(this.lo));
9176
+ storeBlocked(this.header, [kernelBits(this.lo), this.hi]);
8803
9177
  return old;
8804
9178
  }
8805
9179
  deliverUnblocked() {
@@ -8812,6 +9186,9 @@ var init_wasi_sigmask = __esm({
8812
9186
  this.set(SIG_SETMASK, lo, hi, () => {
8813
9187
  });
8814
9188
  }
9189
+ inherited() {
9190
+ return [kernelBits(this.lo), this.hi];
9191
+ }
8815
9192
  discard(sig) {
8816
9193
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
8817
9194
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
@@ -10789,6 +11166,7 @@ __export(wasi_runtime_exports, {
10789
11166
  runWasiProcess: () => runWasiProcess,
10790
11167
  runWasiThread: () => runWasiThread,
10791
11168
  sigmaskOf: () => sigmaskOf,
11169
+ takeThreadDefault: () => takeThreadDefault,
10792
11170
  trapMessage: () => trapMessage,
10793
11171
  unsupportedImport: () => unsupportedImport,
10794
11172
  wireSignals: () => wireSignals
@@ -10832,7 +11210,7 @@ function sigmaskOf(module, sab, gate, threads, process) {
10832
11210
  WasiSigmask.unsupported(header);
10833
11211
  return void 0;
10834
11212
  }
10835
- if (threads) threads.blocked = () => Atomics.load(header, SAB_I_BLOCKED);
11213
+ if (threads) threads.blocked = () => loadBlocked(header);
10836
11214
  const shared = process && new Int32Array(process, 0, SAB_HEADER_I32);
10837
11215
  return new WasiSigmask(header, () => gate.deliver(), shared);
10838
11216
  }
@@ -11226,7 +11604,7 @@ async function runWasiThread(init, port2) {
11226
11604
  masks: () => null,
11227
11605
  raise: (sig) => signals.raise(sig)
11228
11606
  });
11229
- const signals = new WasiSignals(takeDefault(call2, init.pid));
11607
+ const signals = new WasiSignals(takeThreadDefault(call2, init.pid));
11230
11608
  const threads = new WasiThreads(port2, thread.memory, threadCap(init.env), thread.tid, thread.ids);
11231
11609
  threads.received = thread.modules;
11232
11610
  const id = identify(transport, init);
@@ -11280,7 +11658,7 @@ async function runWasiThread(init, port2) {
11280
11658
  throw e;
11281
11659
  }
11282
11660
  }
11283
- var TRAPPED, PREVIEW1, WASIX, SLICC, SIGNAL_CALLBACK, takeDefault, SLICC_FS, SLICC_TTY, RESERVED2, UNDELIVERED, DELIVERED, importsSlicc, importsSigactionHook, noErrno, FALLBACK_MAXIMUM_PAGES, LinkSync, DL_GEN, BACKTRACE_FRAMES;
11661
+ var TRAPPED, PREVIEW1, WASIX, SLICC, SIGNAL_CALLBACK, takeDefault, takeThreadDefault, SLICC_FS, SLICC_TTY, RESERVED2, UNDELIVERED, DELIVERED, importsSlicc, importsSigactionHook, noErrno, FALLBACK_MAXIMUM_PAGES, LinkSync, DL_GEN, BACKTRACE_FRAMES;
11284
11662
  var init_wasi_runtime = __esm({
11285
11663
  "src/process/wasi/wasi-runtime.ts"() {
11286
11664
  "use strict";
@@ -11315,6 +11693,17 @@ var init_wasi_runtime = __esm({
11315
11693
  call2({ op: "proc-kill", pid, sig });
11316
11694
  if (defaultAction(sig) === "terminate") throw new WasiExit(128 + sig);
11317
11695
  };
11696
+ takeThreadDefault = (call2, pid) => (sig) => {
11697
+ if (defaultAction(sig) !== "terminate") {
11698
+ call2({ op: "proc-kill", pid, sig });
11699
+ return;
11700
+ }
11701
+ try {
11702
+ call2({ op: "proc-kill-self", sig });
11703
+ } catch {
11704
+ }
11705
+ throw new WasiExit(128 + sig);
11706
+ };
11318
11707
  SLICC_FS = "slicc_fs";
11319
11708
  SLICC_TTY = "slicc_tty";
11320
11709
  RESERVED2 = RESERVED_NAMESPACES;
@@ -11715,6 +12104,8 @@ var init_js_kernel = __esm({
11715
12104
 
11716
12105
  // src/process/js/js-children.ts
11717
12106
  function exitedOf(status2) {
12107
+ if ((status2 & 255) === 127)
12108
+ return { status: 128 + (status2 >> 8 & 255), signal: status2 >> 8 & 255, stopped: true };
11718
12109
  const signal = status2 & 127;
11719
12110
  return signal ? { status: 128 + signal, signal } : { status: status2 >> 8 & 255 };
11720
12111
  }
@@ -11751,8 +12142,10 @@ function writable(io, fd) {
11751
12142
  });
11752
12143
  }
11753
12144
  function childOps(kernel, io, defaults, sync) {
11754
- const wait2 = async (pid) => {
11755
- const r = await kernel.blocking({ op: "proc-wait", pid, nohang: false });
12145
+ const wait2 = async (pid, options = {}) => {
12146
+ if (typeof options !== "object" || options === null) throw new JsCallError("EINVAL", "wait");
12147
+ const untraced = options.untraced === true ? { untraced: true } : {};
12148
+ const r = await kernel.blocking({ op: "proc-wait", pid, nohang: false, ...untraced });
11756
12149
  const [, status2] = r.ok && r.kind === "json" ? r.json : [0, 0];
11757
12150
  return exitedOf(status2);
11758
12151
  };
@@ -11766,7 +12159,7 @@ function childOps(kernel, io, defaults, sync) {
11766
12159
  ...stdin !== void 0 ? { stdin: writable(io, stdin) } : {},
11767
12160
  ...stdout !== void 0 ? { stdout: readable(io, stdout) } : {},
11768
12161
  ...stderr !== void 0 ? { stderr: readable(io, stderr) } : {},
11769
- wait: () => wait2(pid),
12162
+ wait: (options) => wait2(pid, options),
11770
12163
  kill: (signal) => kill(pid, signal)
11771
12164
  };
11772
12165
  };
@@ -12032,6 +12425,7 @@ function* lookup(abs) {
12032
12425
  const names = yield { op: "fd-tty-names" };
12033
12426
  if (names.includes(abs)) return { kind: "terminal", name: abs };
12034
12427
  }
12428
+ if (name2 === "pts") return { kind: "dir", mode: DIR | 365 };
12035
12429
  const pts = /^pts\/(\d+)$/.exec(name2)?.[1];
12036
12430
  if (pts !== void 0) {
12037
12431
  const open = yield { op: "pty-list" };
@@ -12063,7 +12457,8 @@ function* fdStat(fd, path) {
12063
12457
  if (info.kind === "file") {
12064
12458
  const file = yield { op: "fd-vfs-stat", fd };
12065
12459
  if (file.orphan) return { ...nodeStat(33152, file.size), isFile: true };
12066
- return yield* pathStat(file.path);
12460
+ const st = yield* pathStat(file.path);
12461
+ return { ...st, size: file.size };
12067
12462
  }
12068
12463
  if (info.terminal) return yield* terminalStat(info.terminal);
12069
12464
  if (CHAR_KINDS.has(info.kind)) return nodeStat(CHAR | 438);
@@ -12116,16 +12511,26 @@ function* devReadlink(abs) {
12116
12511
  if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
12117
12512
  throw new JsCallError("EINVAL", abs);
12118
12513
  }
12514
+ function* devResolveTarget(abs) {
12515
+ const node = yield* lookup(abs);
12516
+ if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
12517
+ if (node.kind === "link" && node.fd !== void 0) return yield* fdTarget(node.fd, abs);
12518
+ return void 0;
12519
+ }
12119
12520
  function* devReaddir(abs) {
12120
12521
  if (abs === "/dev/fd") {
12121
12522
  const fds = yield { op: "fd-list" };
12122
12523
  return fds.map(({ fd }) => String(fd));
12123
12524
  }
12525
+ if (abs === "/dev/pts") {
12526
+ const open = yield { op: "pty-list" };
12527
+ return open.map(String).sort();
12528
+ }
12124
12529
  const node = yield* lookup(abs);
12125
12530
  if (node.kind !== "dir") throw new JsCallError("ENOTDIR", abs);
12126
12531
  const names = yield { op: "fd-tty-names" };
12127
12532
  const ttys = names.filter((n) => /^\/dev\/tty\d+$/.test(n)).map((n) => n.slice(5));
12128
- return [...DEVICES2, "clipboard", "sealed", "tty", "fd", ...STDIO3, ...ttys].sort();
12533
+ return [...DEVICES2, "clipboard", "sealed", "tty", "fd", "pts", ...STDIO3, ...ttys].sort();
12129
12534
  }
12130
12535
  function* aliasOf(fd, abs, o) {
12131
12536
  const info = yield* fdInfo(fd, abs);
@@ -12134,6 +12539,9 @@ function* aliasOf(fd, abs, o) {
12134
12539
  const at = yield { op: "fd-vfs-stat", fd };
12135
12540
  if (!at.orphan)
12136
12541
  return { fd: yield openRequest(at.path, { ...o, create: false }), file };
12542
+ const wantWrite = o.write === true || o.append === true || o.truncate === true;
12543
+ if (wantWrite && info.access === "read") throw new JsCallError("EBADF", abs);
12544
+ if (!wantWrite && info.access === "write") throw new JsCallError("EBADF", abs);
12137
12545
  }
12138
12546
  const copy2 = yield { op: "fd-dup", fd, min: 3 };
12139
12547
  if (file && o.truncate) {
@@ -12439,11 +12847,18 @@ function plain(status2, text) {
12439
12847
  function local2(url) {
12440
12848
  return isKernelLoopbackHost(new URL(url).hostname);
12441
12849
  }
12850
+ function badPort(url) {
12851
+ const port2 = url.port ? Number(url.port) : 0;
12852
+ return port2 !== 0 && BAD_PORTS.has(port2);
12853
+ }
12442
12854
  function rewrite(hop, status2, location) {
12443
12855
  const next2 = new URL(location, hop.url);
12444
12856
  if (next2.protocol !== "http:" && next2.protocol !== "https:") {
12445
12857
  throw failed3(new JsCallError("EPROTONOSUPPORT", next2.protocol));
12446
12858
  }
12859
+ if (badPort(next2)) {
12860
+ throw failed3(new JsCallError("EACCES", `bad port: ${next2.href}`));
12861
+ }
12447
12862
  if (local2(next2.href) && !local2(hop.url)) {
12448
12863
  const from = new URL(hop.url).origin;
12449
12864
  throw failed3(
@@ -12729,6 +13144,9 @@ function fetchOp(kernel) {
12729
13144
  if (protocol !== "http:" && protocol !== "https:") {
12730
13145
  throw failed3(new JsCallError("EPROTONOSUPPORT", protocol));
12731
13146
  }
13147
+ if (badPort(new URL(request.url))) {
13148
+ throw failed3(new JsCallError("EACCES", `bad port: ${request.url}`));
13149
+ }
12732
13150
  let known = await traitsAt(request.url);
12733
13151
  if (!known.manualRedirects && request.redirect !== "follow") {
12734
13152
  throw failed3(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
@@ -12759,7 +13177,7 @@ function fetchOp(kernel) {
12759
13177
  }
12760
13178
  };
12761
13179
  }
12762
- var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
13180
+ var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, BAD_PORTS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
12763
13181
  var init_js_fetch = __esm({
12764
13182
  "src/process/js/js-fetch.ts"() {
12765
13183
  "use strict";
@@ -12778,6 +13196,89 @@ var init_js_fetch = __esm({
12778
13196
  ]);
12779
13197
  DECODED = /* @__PURE__ */ new Set(["gzip", "x-gzip", "deflate"]);
12780
13198
  CREDENTIALS = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2"]);
13199
+ BAD_PORTS = /* @__PURE__ */ new Set([
13200
+ 1,
13201
+ 7,
13202
+ 9,
13203
+ 11,
13204
+ 13,
13205
+ 15,
13206
+ 17,
13207
+ 19,
13208
+ 20,
13209
+ 21,
13210
+ 22,
13211
+ 23,
13212
+ 25,
13213
+ 37,
13214
+ 42,
13215
+ 43,
13216
+ 53,
13217
+ 69,
13218
+ 77,
13219
+ 79,
13220
+ 87,
13221
+ 95,
13222
+ 101,
13223
+ 102,
13224
+ 103,
13225
+ 104,
13226
+ 109,
13227
+ 110,
13228
+ 111,
13229
+ 113,
13230
+ 115,
13231
+ 117,
13232
+ 119,
13233
+ 123,
13234
+ 135,
13235
+ 137,
13236
+ 139,
13237
+ 143,
13238
+ 161,
13239
+ 179,
13240
+ 389,
13241
+ 427,
13242
+ 465,
13243
+ 512,
13244
+ 513,
13245
+ 514,
13246
+ 515,
13247
+ 526,
13248
+ 530,
13249
+ 531,
13250
+ 532,
13251
+ 540,
13252
+ 548,
13253
+ 554,
13254
+ 556,
13255
+ 563,
13256
+ 587,
13257
+ 601,
13258
+ 636,
13259
+ 989,
13260
+ 990,
13261
+ 993,
13262
+ 995,
13263
+ 1719,
13264
+ 1720,
13265
+ 1723,
13266
+ 2049,
13267
+ 3659,
13268
+ 4045,
13269
+ 4190,
13270
+ 5060,
13271
+ 5061,
13272
+ 6e3,
13273
+ 6566,
13274
+ 6665,
13275
+ 6666,
13276
+ 6667,
13277
+ 6668,
13278
+ 6669,
13279
+ 6697,
13280
+ 10080
13281
+ ]);
12781
13282
  OVER = /* @__PURE__ */ Symbol("over");
12782
13283
  TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
12783
13284
  QUOTABLE = /^[\t\x20-\x7e\x80-\xff]*$/;
@@ -13153,6 +13654,24 @@ function laneOf(lane) {
13153
13654
  }
13154
13655
  function syncOps(kernel, shared) {
13155
13656
  const { infos, handles, resolve } = shared;
13657
+ const tryDevSync = (abs) => {
13658
+ try {
13659
+ const resolved2 = physicalPath(
13660
+ {
13661
+ lstat(p) {
13662
+ return parseSyncFsStat(kernel.json({ op: "lstat", path: p })) ?? {};
13663
+ },
13664
+ readlink(p) {
13665
+ return String(kernel.json({ op: "readlink", path: p }));
13666
+ }
13667
+ },
13668
+ abs
13669
+ );
13670
+ return resolved2 !== abs && inDev(resolved2) ? resolved2 : void 0;
13671
+ } catch {
13672
+ return void 0;
13673
+ }
13674
+ };
13156
13675
  const info = (fd) => {
13157
13676
  const known = infos.get(fd);
13158
13677
  if (known) return known;
@@ -13185,10 +13704,17 @@ function syncOps(kernel, shared) {
13185
13704
  const statOf = (op, path) => {
13186
13705
  const abs = resolve(path);
13187
13706
  if (inDev(abs)) return devSync(kernel, devStat(abs, op === "stat"));
13188
- kernel.call({ op: "fd-path-flush", path: abs });
13189
- const s = parseSyncFsStat(kernel.json({ op, path: abs }));
13190
- if (!s) throw new JsCallError("EIO", op);
13191
- return s;
13707
+ try {
13708
+ kernel.call({ op: "fd-path-flush", path: abs });
13709
+ const s = parseSyncFsStat(kernel.json({ op, path: abs }));
13710
+ if (!s) throw new JsCallError("EIO", op);
13711
+ return s;
13712
+ } catch (err) {
13713
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
13714
+ const devPath = tryDevSync(abs);
13715
+ if (!devPath) throw err;
13716
+ return devSync(kernel, devStat(devPath, op === "stat"));
13717
+ }
13192
13718
  };
13193
13719
  const openDev2 = (abs, options) => {
13194
13720
  const { fd, file, ...access } = devSync(kernel, devOpen(abs, options));
@@ -13208,27 +13734,34 @@ function syncOps(kernel, shared) {
13208
13734
  const open = (path, options = {}) => {
13209
13735
  const abs = resolve(path);
13210
13736
  if (inDev(abs)) return openDev2(abs, options);
13211
- let existing;
13212
- try {
13213
- existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
13214
- } catch (err) {
13215
- existing = absent(err);
13216
- }
13217
- checkOpen(abs, options, existing);
13218
- const fd = kernel.json(openRequest(abs, options));
13219
13737
  try {
13220
- kernel.call({ op: "fd-vfs-stat", fd });
13738
+ let existing;
13739
+ try {
13740
+ existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
13741
+ } catch (err) {
13742
+ existing = absent(err);
13743
+ }
13744
+ checkOpen(abs, options, existing);
13745
+ const fd = kernel.json(openRequest(abs, options));
13746
+ try {
13747
+ kernel.call({ op: "fd-vfs-stat", fd });
13748
+ } catch (err) {
13749
+ kernel.raw({ op: "fd-close", fd });
13750
+ throw err;
13751
+ }
13752
+ infos.set(fd, { kind: "file" });
13753
+ const handle = syncFile(kernel, fd, abs, options.append === true, () => {
13754
+ infos.delete(fd);
13755
+ handles.delete(fd);
13756
+ });
13757
+ handles.set(fd, handle.invalidate);
13758
+ return handle.file;
13221
13759
  } catch (err) {
13222
- kernel.raw({ op: "fd-close", fd });
13223
- throw err;
13760
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
13761
+ const devPath = tryDevSync(abs);
13762
+ if (!devPath) throw err;
13763
+ return openDev2(devPath, options);
13224
13764
  }
13225
- infos.set(fd, { kind: "file" });
13226
- const handle = syncFile(kernel, fd, abs, options.append === true, () => {
13227
- infos.delete(fd);
13228
- handles.delete(fd);
13229
- });
13230
- handles.set(fd, handle.invalidate);
13231
- return handle.file;
13232
13765
  };
13233
13766
  return {
13234
13767
  read: read2,
@@ -13240,7 +13773,7 @@ function syncOps(kernel, shared) {
13240
13773
  kernel.call({ op: "fd-close", fd });
13241
13774
  },
13242
13775
  open: procOpenSync(open, kernel, { resolve, pid: shared.pid }),
13243
- fs: procFsSync(syncPathOps(kernel, resolve, statOf, open), kernel, {
13776
+ fs: procFsSync(syncPathOps(kernel, resolve, statOf, open, tryDevSync), kernel, {
13244
13777
  resolve,
13245
13778
  pid: shared.pid
13246
13779
  })
@@ -13310,14 +13843,16 @@ function syncFile(kernel, fd, path, append, forget) {
13310
13843
  }
13311
13844
  };
13312
13845
  }
13313
- function syncPathOps(kernel, resolve, statOf, open) {
13846
+ function syncPathOps(kernel, resolve, statOf, open, tryDev) {
13314
13847
  return {
13315
13848
  stat: (path) => statOf("stat", path),
13316
13849
  lstat: (path) => statOf("lstat", path),
13317
13850
  exists(path) {
13318
13851
  const abs = resolve(path);
13319
13852
  if (inDev(abs)) return devSync(kernel, devExists(abs));
13320
- return kernel.json({ op: "exists", path: abs }) === true;
13853
+ if (kernel.json({ op: "exists", path: abs }) === true) return true;
13854
+ const devPath = tryDev(abs);
13855
+ return devPath ? devSync(kernel, devExists(devPath)) : false;
13321
13856
  },
13322
13857
  readdir(path) {
13323
13858
  const abs = resolve(path);
@@ -13342,15 +13877,29 @@ function syncPathOps(kernel, resolve, statOf, open) {
13342
13877
  return String(kernel.json({ op: "readlink", path: abs }));
13343
13878
  },
13344
13879
  statfs(path) {
13345
- const abs = resolve(path);
13880
+ let abs = resolve(path);
13881
+ if (inDev(abs)) {
13882
+ try {
13883
+ const target = devSync(kernel, devResolveTarget(abs));
13884
+ if (target?.startsWith("/")) abs = target;
13885
+ } catch {
13886
+ }
13887
+ }
13346
13888
  statOf("stat", abs);
13347
13889
  return statFsOf(kernel.json({ op: "statfs", path: abs }));
13348
13890
  },
13349
13891
  readFile(path) {
13350
13892
  const abs = resolve(path);
13351
13893
  if (inDev(abs)) return readWholeSync(open(abs));
13352
- kernel.call({ op: "fd-path-flush", path: abs });
13353
- return kernel.bytes({ op: "read", path: abs });
13894
+ try {
13895
+ kernel.call({ op: "fd-path-flush", path: abs });
13896
+ return kernel.bytes({ op: "read", path: abs });
13897
+ } catch (err) {
13898
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
13899
+ const devPath = tryDev(abs);
13900
+ if (!devPath) throw err;
13901
+ return readWholeSync(open(devPath));
13902
+ }
13354
13903
  },
13355
13904
  writeFile(path, data, options) {
13356
13905
  const mode = options?.mode;
@@ -13372,6 +13921,7 @@ var encoder3, noLane, JsSyncKernel;
13372
13921
  var init_js_sync = __esm({
13373
13922
  "src/process/js/js-sync.ts"() {
13374
13923
  "use strict";
13924
+ init_physical_path();
13375
13925
  init_signals();
13376
13926
  init_sync_fs_wire();
13377
13927
  init_sync_sab_bridge();
@@ -13768,6 +14318,55 @@ function readable2(read2) {
13768
14318
  { highWaterMark: 0 }
13769
14319
  );
13770
14320
  }
14321
+ async function resolveDevAsync(kernel, abs) {
14322
+ try {
14323
+ const resolved2 = await physicalPathAsync(
14324
+ {
14325
+ async lstat(p) {
14326
+ return parseSyncFsStat(await kernel.json({ op: "lstat", path: p })) ?? {};
14327
+ },
14328
+ async readlink(p) {
14329
+ return String(await kernel.json({ op: "readlink", path: p }));
14330
+ }
14331
+ },
14332
+ abs
14333
+ );
14334
+ return resolved2 !== abs && inDev(resolved2) ? resolved2 : void 0;
14335
+ } catch {
14336
+ return void 0;
14337
+ }
14338
+ }
14339
+ async function vfsStat(kernel, abs, op, tryDev) {
14340
+ try {
14341
+ await kernel.call({ op: "fd-path-flush", path: abs });
14342
+ const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
14343
+ if (!s) throw new JsCallError("EIO", op);
14344
+ return s;
14345
+ } catch (err) {
14346
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
14347
+ const devPath = await tryDev(abs);
14348
+ if (!devPath) throw err;
14349
+ return devAsync(kernel, devStat(devPath, op === "stat"));
14350
+ }
14351
+ }
14352
+ async function vfsOpen(kernel, abs, options, statOf, infos, handles) {
14353
+ const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
14354
+ checkOpen(abs, options, existing);
14355
+ const fd = await kernel.json(openRequest(abs, options));
14356
+ try {
14357
+ await kernel.call({ op: "fd-vfs-stat", fd });
14358
+ } catch (err) {
14359
+ await kernel.raw({ op: "fd-close", fd });
14360
+ throw err;
14361
+ }
14362
+ infos.set(fd, { kind: "file" });
14363
+ const handle = fileHandle(kernel, fd, abs, options.append === true, () => {
14364
+ infos.delete(fd);
14365
+ handles.delete(fd);
14366
+ });
14367
+ handles.set(fd, handle.invalidate);
14368
+ return handle.file;
14369
+ }
13771
14370
  function createContext(o) {
13772
14371
  const { kernel } = o;
13773
14372
  const infos = /* @__PURE__ */ new Map();
@@ -13775,6 +14374,7 @@ function createContext(o) {
13775
14374
  const pending = /* @__PURE__ */ new Set();
13776
14375
  const random = o.random ?? ((bytes) => void crypto.getRandomValues(bytes));
13777
14376
  const resolve = (path) => resolvePath(o.cwd, path);
14377
+ const tryDev = (abs) => resolveDevAsync(kernel, abs);
13778
14378
  let exiting;
13779
14379
  const exit = (code2 = 0) => {
13780
14380
  exiting ??= code2;
@@ -13817,32 +14417,25 @@ function createContext(o) {
13817
14417
  const statOf = async (op, path) => {
13818
14418
  const abs = resolve(path);
13819
14419
  if (inDev(abs)) return devAsync(kernel, devStat(abs, op === "stat"));
13820
- await kernel.call({ op: "fd-path-flush", path: abs });
13821
- const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
13822
- if (!s) throw new JsCallError("EIO", op);
13823
- return s;
14420
+ return vfsStat(kernel, abs, op, tryDev);
13824
14421
  };
14422
+ const devIo = { infos, handles, read: read2, write: writeAll };
13825
14423
  const open = async (path, options = {}) => {
13826
14424
  const abs = resolve(path);
13827
- if (inDev(abs)) return openDev(kernel, abs, options, { infos, handles, read: read2, write: writeAll });
13828
- const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
13829
- checkOpen(abs, options, existing);
13830
- const fd = await kernel.json(openRequest(abs, options));
14425
+ if (inDev(abs)) return openDev(kernel, abs, options, devIo);
13831
14426
  try {
13832
- await kernel.call({ op: "fd-vfs-stat", fd });
14427
+ return await vfsOpen(kernel, abs, options, statOf, infos, handles);
13833
14428
  } catch (err) {
13834
- await kernel.raw({ op: "fd-close", fd });
13835
- throw err;
14429
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
14430
+ const devPath = await tryDev(abs);
14431
+ if (!devPath) throw err;
14432
+ return openDev(kernel, devPath, options, devIo);
13836
14433
  }
13837
- infos.set(fd, { kind: "file" });
13838
- const handle = fileHandle(kernel, fd, abs, options.append === true, () => {
13839
- infos.delete(fd);
13840
- handles.delete(fd);
13841
- });
13842
- handles.set(fd, handle.invalidate);
13843
- return handle.file;
13844
14434
  };
13845
- const fs = procFsAsync(pathOps(kernel, resolve, statOf, open), kernel, { resolve, pid: o.pid });
14435
+ const fs = procFsAsync(pathOps(kernel, resolve, statOf, open, tryDev), kernel, {
14436
+ resolve,
14437
+ pid: o.pid
14438
+ });
13846
14439
  const lane = o.lane ?? laneOf(void 0);
13847
14440
  if (o.lane && o.lane !== noLane) kernel.syncLane = o.lane;
13848
14441
  const syncKernel = new JsSyncKernel(lane, kernel, unwind);
@@ -14038,14 +14631,16 @@ async function sendSome(kernel, fd, body, signal) {
14038
14631
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
14039
14632
  }
14040
14633
  }
14041
- function pathOps(kernel, resolve, statOf, open) {
14634
+ function pathOps(kernel, resolve, statOf, open, tryDev) {
14042
14635
  return {
14043
14636
  stat: (path) => statOf("stat", path),
14044
14637
  lstat: (path) => statOf("lstat", path),
14045
14638
  async exists(path) {
14046
14639
  const abs = resolve(path);
14047
14640
  if (inDev(abs)) return devAsync(kernel, devExists(abs));
14048
- return await kernel.json({ op: "exists", path: abs }) === true;
14641
+ if (await kernel.json({ op: "exists", path: abs }) === true) return true;
14642
+ const devPath = await tryDev(abs);
14643
+ return devPath ? devAsync(kernel, devExists(devPath)) : false;
14049
14644
  },
14050
14645
  async readdir(path) {
14051
14646
  const abs = resolve(path);
@@ -14070,15 +14665,26 @@ function pathOps(kernel, resolve, statOf, open) {
14070
14665
  return String(await kernel.json({ op: "readlink", path: abs }));
14071
14666
  },
14072
14667
  async statfs(path) {
14073
- const abs = resolve(path);
14668
+ let abs = resolve(path);
14669
+ if (inDev(abs)) {
14670
+ const target = await devAsync(kernel, devResolveTarget(abs)).catch(() => void 0);
14671
+ if (target?.startsWith("/")) abs = target;
14672
+ }
14074
14673
  await statOf("stat", abs);
14075
14674
  return statFsOf(await kernel.json({ op: "statfs", path: abs }));
14076
14675
  },
14077
14676
  async readFile(path) {
14078
14677
  const abs = resolve(path);
14079
14678
  if (inDev(abs)) return readWhole(await open(abs));
14080
- await kernel.call({ op: "fd-path-flush", path: abs });
14081
- return kernel.bytes({ op: "read", path: abs });
14679
+ try {
14680
+ await kernel.call({ op: "fd-path-flush", path: abs });
14681
+ return await kernel.bytes({ op: "read", path: abs });
14682
+ } catch (err) {
14683
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
14684
+ const devPath = await tryDev(abs);
14685
+ if (!devPath) throw err;
14686
+ return readWhole(await open(devPath));
14687
+ }
14082
14688
  },
14083
14689
  async writeFile(path, data, options) {
14084
14690
  const mode = options?.mode;
@@ -14100,6 +14706,7 @@ var KERNEL_INFO, JsExit, encoder4;
14100
14706
  var init_js_context = __esm({
14101
14707
  "src/process/js/js-context.ts"() {
14102
14708
  "use strict";
14709
+ init_physical_path();
14103
14710
  init_signals();
14104
14711
  init_sync_fs_wire();
14105
14712
  init_version();