@ai-ecoverse/slicc-kernel 1.91.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.
@@ -44,17 +44,20 @@ function hide(target, names) {
44
44
  }
45
45
  function vacate(target, names) {
46
46
  for (const name2 of names) {
47
- for (let at = target; at && at !== Object.prototype; ) {
48
- if (Object.getOwnPropertyDescriptor(at, name2)?.configurable) Reflect.deleteProperty(at, name2);
49
- at = Object.getPrototypeOf(at);
47
+ const holders = chain(target);
48
+ for (const holder of holders) {
49
+ if (Object.getOwnPropertyDescriptor(holder, name2)?.configurable) {
50
+ Reflect.deleteProperty(holder, name2);
51
+ }
50
52
  }
51
- Reflect.defineProperty(target, name2, {
53
+ const kept = holders.slice(1).some((holder) => Object.hasOwn(holder, name2));
54
+ const opened2 = Reflect.defineProperty(target, name2, {
52
55
  value: void 0,
53
56
  writable: true,
54
57
  enumerable: false,
55
58
  configurable: true
56
59
  });
57
- if (Reflect.get(target, name2) !== void 0) {
60
+ if (kept || !opened2 || Reflect.get(target, name2) !== void 0) {
58
61
  throw new Error(`slicc-kernel: cannot withhold ${name2} from a JS program`);
59
62
  }
60
63
  }
@@ -80,7 +83,6 @@ var init_lockdown = __esm({
80
83
  "cookieStore",
81
84
  "Worker",
82
85
  "SharedWorker",
83
- "BroadcastChannel",
84
86
  "postMessage",
85
87
  "close",
86
88
  "webkitRequestFileSystem",
@@ -97,11 +99,18 @@ var init_lockdown = __esm({
97
99
  "hid",
98
100
  "serial"
99
101
  ];
100
- OPEN_SLOTS = ["fetch", "WebSocket"];
102
+ OPEN_SLOTS = ["fetch", "WebSocket", "BroadcastChannel"];
101
103
  }
102
104
  });
103
105
 
104
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
+ }
105
114
  function loadU53(header, lo, hi) {
106
115
  return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
107
116
  }
@@ -144,7 +153,7 @@ function sabViews(sab) {
144
153
  window: new Uint8Array(sab, SAB_HEADER_BYTES)
145
154
  };
146
155
  }
147
- 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;
148
157
  var init_sync_sab_wire = __esm({
149
158
  "src/realm/sync-sab-wire.ts"() {
150
159
  "use strict";
@@ -169,6 +178,8 @@ var init_sync_sab_wire = __esm({
169
178
  SAB_I_ASYNC = 14;
170
179
  SAB_I_STOP = 15;
171
180
  SAB_I_BLOCKED = 16;
181
+ SAB_I_BLOCKED_HI = 17;
182
+ anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
172
183
  U32 = 2 ** 32;
173
184
  SAB_STATE_IDLE = 0;
174
185
  SAB_STATE_PENDING = 1;
@@ -363,6 +374,73 @@ var init_signals = __esm({
363
374
  }
364
375
  });
365
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
+
366
444
  // src/fs/pages.ts
367
445
  var PAGE, READAHEAD, CLEAN_LIMIT, WRITEBACK, RUN, Pages;
368
446
  var init_pages = __esm({
@@ -617,34 +695,6 @@ var init_ranged = __esm({
617
695
  }
618
696
  });
619
697
 
620
- // src/fs/types.ts
621
- function normalizePath(path) {
622
- const parts = [];
623
- for (const part of path.split("/")) {
624
- if (part === "" || part === ".") continue;
625
- if (part === "..") parts.pop();
626
- else parts.push(part);
627
- }
628
- return `/${parts.join("/")}`;
629
- }
630
- function inodeOf(path) {
631
- let h1 = 3735928559;
632
- let h2 = 1103547991;
633
- for (let i = 0; i < path.length; i++) {
634
- const c = path.charCodeAt(i);
635
- h1 = Math.imul(h1 ^ c, 2654435761);
636
- h2 = Math.imul(h2 ^ c, 1597334677);
637
- }
638
- h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
639
- h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
640
- return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
641
- }
642
- var init_types = __esm({
643
- "src/fs/types.ts"() {
644
- "use strict";
645
- }
646
- });
647
-
648
698
  // src/process/wasi/wasi-abi.ts
649
699
  function wasiErrnoOf(code2) {
650
700
  if (!code2) return E.IO;
@@ -1069,12 +1119,21 @@ function createSyncFsSabBridge(transport, opts = {}) {
1069
1119
  lutimes: (path, atimeMs, mtimeMs, now) => {
1070
1120
  run({ op: "lutimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
1071
1121
  },
1072
- create: (path, mode) => {
1073
- 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);
1074
1125
  },
1075
- chown: (path, uid, gid, follow2) => {
1126
+ chown: (path, uid, gid, follow2, handle) => {
1076
1127
  const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
1077
- 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
+ );
1078
1137
  },
1079
1138
  ...opts.owners ? { owners: true } : {},
1080
1139
  ...opts.links ? { links: true } : {},
@@ -1135,6 +1194,7 @@ function toMs(v) {
1135
1194
  return v instanceof Date ? v.getTime() : v;
1136
1195
  }
1137
1196
  function wantOf(flags) {
1197
+ if (flags & O_PATH) return 0;
1138
1198
  const mode = flags & O_ACCMODE;
1139
1199
  const read2 = mode === 1 ? 0 : HOLD_READ;
1140
1200
  const write2 = mode !== 0 || (flags & O_TRUNC) !== 0 ? HOLD_WRITE : 0;
@@ -1150,15 +1210,36 @@ function refusal(err) {
1150
1210
  function cachedStat(s, dir) {
1151
1211
  return s.stat !== void 0 && (!dir || s.statAt === syncCallCount());
1152
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
+ }
1153
1234
  function linkedStates(bridgeOf) {
1154
1235
  const opens = /* @__PURE__ */ new Map();
1155
1236
  const byId = /* @__PURE__ */ new Map();
1156
- 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}`;
1157
1238
  function know(s, id) {
1158
1239
  s.id = id;
1159
1240
  if (!byId.has(id)) byId.set(id, s);
1160
1241
  }
1161
- function opening(node, on) {
1242
+ function opening2(node, on) {
1162
1243
  const s = node.live;
1163
1244
  if (!on) {
1164
1245
  opens.delete(s);
@@ -1167,14 +1248,14 @@ function linkedStates(bridgeOf) {
1167
1248
  return;
1168
1249
  }
1169
1250
  opens.set(s, node);
1170
- const id = idOf3(s.stat);
1251
+ const id = idOf4(s.stat);
1171
1252
  if (id !== void 0) know(s, id);
1172
1253
  }
1173
1254
  function sharedWith(node) {
1174
1255
  const st = node.live.stat;
1175
1256
  if (st?.ino === void 0) return void 0;
1176
1257
  const id = `${st.dev}:${st.ino}`;
1177
- if (!byId.has(id) && idOf3(st) !== void 0) {
1258
+ if (!byId.has(id) && idOf4(st) !== void 0) {
1178
1259
  for (const [s2, other] of opens) {
1179
1260
  if (s2.id !== void 0 || s2.orphan) continue;
1180
1261
  let st2;
@@ -1182,7 +1263,7 @@ function linkedStates(bridgeOf) {
1182
1263
  st2 = bridgeOf(other).lstat(liveNodePath(other));
1183
1264
  } catch {
1184
1265
  }
1185
- const known = idOf3(st2);
1266
+ const known = idOf4(st2);
1186
1267
  if (known !== void 0) know(s2, known);
1187
1268
  }
1188
1269
  }
@@ -1190,7 +1271,7 @@ function linkedStates(bridgeOf) {
1190
1271
  return s && s !== node.live && !stale(s) ? s : void 0;
1191
1272
  }
1192
1273
  const holder = (node) => opens.get(node.live) ?? node;
1193
- return { opening, sharedWith, know, idOf: idOf3, holder };
1274
+ return { opening: opening2, sharedWith, know, idOf: idOf4, holder };
1194
1275
  }
1195
1276
  function createHelpers(Fs, ops) {
1196
1277
  const bridgeOf = (node) => node.mount.opts.bridge;
@@ -1412,7 +1493,9 @@ function createNodeOps(h) {
1412
1493
  const owned = bridgeOf(node).owners === true;
1413
1494
  if (owned && Fs.isLink(node.mode) && statOf(node).uid === void 0)
1414
1495
  node.live.stat = void 0;
1496
+ const cached = owned && cachedStat(node.live, Fs.isDir(node.mode));
1415
1497
  const st = statOf(node);
1498
+ if (cached) searchParents(Fs, node, bridgeOf(node), call2);
1416
1499
  const s = node.live;
1417
1500
  const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
1418
1501
  const mtime = new Date(st.mtimeMs ?? 0);
@@ -1475,7 +1558,7 @@ function createNodeOps(h) {
1475
1558
  if (masked !== DEFAULT_DIR_PERM) metadataCall(() => bridge.chmod(path, masked));
1476
1559
  } else if (Fs.isFile(mode)) {
1477
1560
  call2(
1478
- () => 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))
1479
1562
  );
1480
1563
  } else {
1481
1564
  throw new Fs.ErrnoError(wasiErrno("EPERM"));
@@ -1721,10 +1804,24 @@ function createStreamOps(h) {
1721
1804
  }
1722
1805
  };
1723
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
+ }
1724
1820
  function createLiveVfsPlugin(Fs) {
1725
1821
  const mounts = /* @__PURE__ */ new Set();
1726
1822
  const ops = {};
1727
1823
  const h = createHelpers(Fs, ops);
1824
+ countOpens(Fs);
1728
1825
  const nodeOps = createNodeOps(h);
1729
1826
  const streamOps = createStreamOps(h);
1730
1827
  ops.node = nodeOps;
@@ -1857,12 +1954,12 @@ function liveRoot(Fs, bridge) {
1857
1954
  };
1858
1955
  }
1859
1956
  function crosses(Fs, from, to) {
1860
- const parentOf = (path) => Fs.lookupPath?.(path, { parent: true }).node;
1957
+ const parentOf2 = (path) => Fs.lookupPath?.(path, { parent: true }).node;
1861
1958
  const name2 = from.replace(/\/+$/, "").split("/").pop() ?? "";
1862
1959
  try {
1863
- const fromDir = parentOf(from);
1960
+ const fromDir = parentOf2(from);
1864
1961
  const node = fromDir && Fs.lookupNode?.(fromDir, name2);
1865
- const dir = parentOf(to);
1962
+ const dir = parentOf2(to);
1866
1963
  return !!node && !!dir && !!node.live !== !!dir.live;
1867
1964
  } catch {
1868
1965
  return false;
@@ -1926,6 +2023,25 @@ function guardRenames(Fs) {
1926
2023
  function idOf(value2) {
1927
2024
  return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
1928
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
+ }
1929
2045
  function useLiveChown(Fs) {
1930
2046
  const chown = Fs.chown?.bind(Fs);
1931
2047
  if (!chown) return;
@@ -1944,8 +2060,10 @@ function useLiveChown(Fs) {
1944
2060
  if (!Fs.fchown || !getStreamChecked) return;
1945
2061
  Fs.fchown = (fd, uid, gid) => {
1946
2062
  const stream = getStreamChecked.call(Fs, fd);
1947
- const live = stream.node.live !== void 0;
1948
- 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;
1949
2067
  Fs.chown(target, uid, gid);
1950
2068
  };
1951
2069
  }
@@ -2006,10 +2124,11 @@ function readingLinks(Fs) {
2006
2124
  }
2007
2125
  };
2008
2126
  }
2009
- 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;
2010
2128
  var init_live_vfs_fs = __esm({
2011
2129
  "src/realm/live-vfs-fs.ts"() {
2012
2130
  "use strict";
2131
+ init_access();
2013
2132
  init_ranged();
2014
2133
  init_types();
2015
2134
  init_wasi_errno();
@@ -2028,6 +2147,7 @@ var init_live_vfs_fs = __esm({
2028
2147
  O_TRUNC = 512;
2029
2148
  O_PATH = 2097152;
2030
2149
  stale = (s) => !!s.orphan && !s.kept;
2150
+ opening = /* @__PURE__ */ new WeakMap();
2031
2151
  }
2032
2152
  });
2033
2153
 
@@ -2051,6 +2171,22 @@ function topLevelDirs(bridge, warn) {
2051
2171
  }
2052
2172
  return dirs;
2053
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
+ }
2054
2190
  function mountVfsIntoEmscripten(Fs, deps) {
2055
2191
  const { bridge, warn } = deps;
2056
2192
  const dirs = topLevelDirs(bridge, warn);
@@ -2058,6 +2194,8 @@ function mountVfsIntoEmscripten(Fs, deps) {
2058
2194
  if (dirs) liveRoot(Fs, bridge);
2059
2195
  if (bridge.owners && Fs.lookupPath) useLiveChown(Fs);
2060
2196
  if (bridge.links && Fs.lookupPath) readingLinks(Fs);
2197
+ linuxRmdir(Fs);
2198
+ if (deps.cred) Fs.sliccCred = deps.cred;
2061
2199
  try {
2062
2200
  Fs.chdir(deps.cwd);
2063
2201
  } catch (err) {
@@ -2080,1406 +2218,1533 @@ var init_emscripten_vfs_hook = __esm({
2080
2218
  }
2081
2219
  });
2082
2220
 
2083
- // src/process/kernel-streams.ts
2084
- function isPtyPath(path) {
2085
- return PTY_PATH.test(path);
2221
+ // src/fs/dev-removal.ts
2222
+ function inDevTree(path) {
2223
+ return path === "/dev" || path.startsWith("/dev/");
2086
2224
  }
2087
- function ptyStat(path) {
2088
- const n = PTY_PATH.exec(path)?.[1];
2089
- const now = /* @__PURE__ */ new Date();
2090
- return {
2091
- dev: 22,
2092
- ino: n === void 0 ? 2 : 3 + Number(n),
2093
- mode: n === void 0 ? 8630 : 8592,
2094
- nlink: 1,
2095
- uid: 1e3,
2096
- gid: 1e3,
2097
- rdev: n === void 0 ? 5 << 8 | 2 : 136 << 8 | Number(n),
2098
- size: 0,
2099
- blksize: 4096,
2100
- blocks: 0,
2101
- atime: now,
2102
- mtime: now,
2103
- ctime: now
2104
- };
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";
2105
2229
  }
2106
- function sealedStat(minor = 250) {
2107
- const now = /* @__PURE__ */ new Date();
2108
- return {
2109
- dev: 22,
2110
- ino: 1,
2111
- mode: 8630,
2112
- nlink: 1,
2113
- uid: 0,
2114
- gid: 0,
2115
- rdev: 10 << 8 | minor,
2116
- size: 0,
2117
- blksize: 4096,
2118
- blocks: 0,
2119
- atime: now,
2120
- mtime: now,
2121
- 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
+ }
2122
2259
  };
2123
2260
  }
2124
- function nonblocking(stream) {
2125
- 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
+ }
2126
2281
  }
2127
- 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;
2128
- var init_kernel_streams = __esm({
2129
- "src/process/kernel-streams.ts"() {
2282
+ var TIOCGPTN, TIOCSPTLCK, TIOCSCTTY, TIOCSWINSZ, TIOCPKT;
2283
+ var init_process_pty = __esm({
2284
+ "src/process/process-pty.ts"() {
2130
2285
  "use strict";
2131
2286
  init_wasi_errno();
2132
- POLLIN = 1;
2133
- POLLOUT = 4;
2134
- POLLERR = 8;
2135
- POLLHUP = 16;
2136
- POLLRDNORM = 64;
2137
- POLLWRNORM = 256;
2138
- TCSETSF = 21508;
2139
- O_NONBLOCK = 2048;
2140
- SOCKET_MODE = 49663;
2141
- PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
2142
- TTY_PATH = /^\/dev\/tty\d+$/;
2143
- TTY_NAME = /^tty\d+$/;
2144
- SEALED_PATH = "/dev/sealed";
2145
- STRERROR = {
2146
- EACCES: "Permission denied",
2147
- EIO: "I/O error",
2148
- ENOTSUP: "Not supported",
2149
- EOPNOTSUPP: "Not supported",
2150
- EFBIG: "File too large",
2151
- EILSEQ: "Illegal byte sequence",
2152
- 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;
2153
2312
  };
2154
- CLIPBOARD_PATH = "/dev/clipboard";
2155
- O_CREAT = 64;
2156
- O_EXCL = 128;
2157
- O_NOCTTY = 256;
2158
- O_TRUNC2 = 512;
2159
- KILLED_BY_SIGPIPE = 128 + 13;
2160
- ProcessExit = class extends Error {
2161
- status;
2162
- constructor(status2) {
2163
- super(`exit ${status2}`);
2164
- this.status = status2;
2165
- }
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;
2166
2321
  };
2167
- SyscallError = class extends Error {
2168
- code;
2169
- constructor(code2) {
2170
- super(code2);
2171
- 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 {
2172
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;
2173
2481
  };
2174
- KernelStreams = class {
2175
- refs = /* @__PURE__ */ new Map();
2176
- socketRoot;
2177
- sockets = 0;
2178
- descriptions = /* @__PURE__ */ new Map();
2179
- described = 0;
2180
- Fs;
2181
- sys;
2182
- options;
2183
- constructor(Fs, sys, options = {}) {
2184
- this.Fs = Fs;
2185
- this.sys = sys;
2186
- this.options = options;
2187
- }
2188
- attach(stream, kfd, terminal) {
2189
- this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
2190
- stream.sliccKernelFd = kfd;
2191
- stream.stream_ops = this.ops(kfd, stream.stream_ops);
2192
- if (terminal ?? this.sys.isatty?.(kfd) ?? false) stream.tty = this.ttyOps(kfd);
2193
- else delete stream.tty;
2194
- }
2195
- attachSocket(stream, kfd) {
2196
- this.attach(stream, kfd, false);
2197
- stream.sliccKernelSocket = true;
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));
2198
2511
  }
2199
- socketStream(flags) {
2200
- const fs = this.Fs;
2201
- if (!fs.mount || !fs.createNode || !fs.createStream) {
2202
- const stream = this.Fs.open("/dev/null", 2);
2203
- stream.flags = flags;
2204
- return stream;
2205
- }
2206
- const createNode = fs.createNode;
2207
- this.socketRoot ??= fs.mount({ mount: () => createNode(null, "/", 16895, 0) }, {}, null);
2208
- const ino = ++this.sockets;
2209
- const node = fs.createNode(this.socketRoot, `socket:${ino}`, SOCKET_MODE, 0);
2210
- const now = /* @__PURE__ */ new Date();
2211
- const stat = { dev: 0, ino, mode: SOCKET_MODE, nlink: 1, uid: 0, gid: 0, rdev: 0, size: 0 };
2212
- const times = { atime: now, mtime: now, ctime: now, blksize: 4096, blocks: 0 };
2213
- node.node_ops = { getattr: () => ({ ...stat, ...times }) };
2214
- return fs.createStream({ node, flags, seekable: false, position: 0, stream_ops: {} });
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;
2215
2521
  }
2216
- nameTerminal(stream) {
2217
- const kfd = stream.sliccKernelFd;
2218
- if (!stream.tty || kfd === void 0) return;
2219
- const name2 = this.sys.ttyName?.(kfd);
2220
- if (name2) this.nameStream(stream, name2);
2221
- }
2222
- nameStream(stream, name2) {
2223
- stream.path = name2;
2224
- this.ttyNode(name2);
2225
- if (typeof this.Fs.stat !== "function") return;
2226
- stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name2) ?? {} };
2227
- }
2228
- nameDevice(stream, kind) {
2229
- this.nameStream(stream, kind === "sealed" ? SEALED_PATH : CLIPBOARD_PATH);
2230
- }
2231
- listSealed() {
2232
- const fs = this.Fs;
2233
- const { analyzePath, mkdev, makedev, registerDevice } = fs;
2234
- if (!analyzePath || !mkdev || !makedev) return;
2235
- const nodes = [
2236
- [SEALED_PATH, 250, this.sys.openSealed],
2237
- [CLIPBOARD_PATH, 251, this.sys.openClipboard]
2238
- ];
2239
- for (const [path, minor, opener] of nodes) {
2240
- if (!opener) continue;
2241
- const dev = makedev.call(fs, 10, minor);
2242
- registerDevice?.call(fs, dev, {
2243
- open: (stream) => this.openNode(stream, path, opener)
2244
- });
2245
- if (analyzePath.call(fs, path).exists) continue;
2246
- try {
2247
- const node = mkdev.call(fs, path, dev);
2248
- if (typeof node === "object" && node !== null) {
2249
- const made = node;
2250
- made.node_ops = { ...made.node_ops, getattr: () => sealedStat(minor) };
2251
- }
2252
- } catch {
2253
- }
2254
- }
2255
- }
2256
- openNode(stream, path, opener) {
2257
- let kfd;
2258
- try {
2259
- kfd = this.call(() => opener.call(this.sys, stream.flags & 3));
2260
- } catch (e) {
2261
- this.Fs.closeStream(stream.fd);
2262
- throw e;
2263
- }
2264
- this.attach(stream, kfd, false);
2265
- this.nameStream(stream, path);
2266
- if (path === CLIPBOARD_PATH) this.reportClose(kfd);
2267
- }
2268
- reporting = /* @__PURE__ */ new Set();
2269
- reportClose(kfd) {
2270
- this.reporting.add(kfd);
2271
- }
2272
- quitting = false;
2273
- atExit = false;
2274
- failedAtExit = false;
2275
- committed = /* @__PURE__ */ new Set();
2276
- exiting() {
2277
- this.atExit = true;
2278
- return () => {
2279
- this.atExit = false;
2280
- };
2281
- }
2282
- commitStdout() {
2283
- const kfd = this.Fs.getStream(1)?.sliccKernelFd;
2284
- if (kfd === void 0 || !this.reporting.delete(kfd)) return;
2285
- this.committed.add(kfd);
2286
- try {
2287
- this.sys.close(kfd);
2288
- } catch (e) {
2289
- if (e instanceof SyscallError) this.stdoutFailed(e.code);
2290
- }
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);
2291
2561
  }
2292
- exitStatus(status2) {
2293
- return this.failedAtExit && status2 === 0 ? 1 : status2;
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;
2294
2599
  }
2295
- reportedClose(stream, kfd) {
2296
- try {
2297
- this.sys.close(kfd);
2298
- } catch (e) {
2299
- if (this.quitting && stream.fd === 1 && e instanceof SyscallError) this.stdoutFailed(e.code);
2300
- this.call(() => {
2301
- throw e;
2302
- });
2303
- }
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);
2304
2616
  }
2305
- stdoutFailed(code2) {
2306
- this.failedAtExit = true;
2307
- const stderr = this.Fs.getStream(2)?.sliccKernelFd;
2308
- if (stderr === void 0) return;
2309
- const line = `${this.options.program ?? "program"}: write error: ${STRERROR[code2] ?? code2}
2310
- `;
2311
- try {
2312
- this.sys.write(stderr, new TextEncoder().encode(line));
2313
- } catch {
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);
2314
2647
  }
2315
2648
  }
2316
- creatingTerminal = false;
2317
- useTerminalNodes() {
2318
- const fs = this.Fs;
2319
- const { lookupNode, readdir, getPath, mkdev, makedev } = fs;
2320
- const ttyNames = this.sys.ttyNames?.bind(this.sys);
2321
- if (!lookupNode || !readdir || !getPath || !mkdev || !makedev || !ttyNames) return;
2322
- fs.lookupNode = (parent, name2) => {
2323
- try {
2324
- return lookupNode.call(fs, parent, name2);
2325
- } catch (e) {
2326
- const path = `/dev/${name2}`;
2327
- if (this.creatingTerminal || !TTY_NAME.test(name2) || getPath.call(fs, parent) !== "/dev")
2328
- throw e;
2329
- if (!ttyNames().includes(path)) throw e;
2330
- this.creatingTerminal = true;
2331
- try {
2332
- mkdev.call(fs, path, makedev.call(fs, 6, 0));
2333
- } finally {
2334
- this.creatingTerminal = false;
2335
- }
2336
- return lookupNode.call(fs, parent, name2);
2337
- }
2338
- };
2339
- fs.readdir = (path) => {
2340
- const names = readdir.call(fs, path);
2341
- if (path.replace(/\/+$/, "") !== "/dev") return names;
2342
- const missing2 = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name2) => TTY_NAME.test(name2) && !names.includes(name2));
2343
- return [...names, ...missing2];
2344
- };
2345
- }
2346
- ttyNode(name2) {
2347
- const { analyzePath, mkdev, makedev } = this.Fs;
2348
- if (!TTY_PATH.test(name2) || !analyzePath || !mkdev || !makedev) return;
2349
- if (!analyzePath.call(this.Fs, name2).exists)
2350
- mkdev.call(this.Fs, name2, makedev.call(this.Fs, 6, 0));
2351
- }
2352
- ttyOps(kfd) {
2353
- return {
2354
- ops: {
2355
- ioctl_tcgets: () => this.call(() => this.sys.tcgets?.(kfd)),
2356
- ioctl_tcsets: (_tty, op, termios) => this.call(() => {
2357
- this.sys.tcsets?.(kfd, termios, op === TCSETSF);
2358
- return 0;
2359
- }),
2360
- ioctl_tiocgwinsz: () => this.call(() => this.sys.winsize?.(kfd) ?? [24, 80]),
2361
- fsync: () => {
2362
- }
2363
- }
2364
- };
2365
- }
2366
- attachFile(stream, kfd) {
2367
- this.attach(stream, kfd, false);
2368
- stream.sliccKernelFile = true;
2369
- stream.stream_ops = {
2370
- ...stream.stream_ops,
2371
- llseek: (_s, offset, whence) => this.call(() => this.sys.seek(kfd, offset, whence)),
2372
- fsync: () => this.call(() => {
2373
- this.sys.flush(kfd);
2374
- return 0;
2375
- })
2376
- };
2377
- }
2378
- sizeFromKernel(stream, kfd) {
2379
- const { size } = this.sys;
2380
- if (!size) return;
2381
- const node = stream.node;
2382
- this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => ({
2383
- ...node.node_ops?.getattr?.(node),
2384
- size: this.call(() => size.call(this.sys, kfd))
2385
- }));
2386
- }
2387
- describe(stream, name2, getattr) {
2388
- if (this.descriptions.size === 0) this.useDescriptions();
2389
- this.descriptions.set(name2, getattr);
2390
- stream.path = name2;
2391
- stream.stream_ops = { ...stream.stream_ops, getattr };
2392
- }
2393
- useDescriptions() {
2394
- const fs = this.Fs;
2395
- for (const name2 of ["stat", "lstat"]) {
2396
- const original = fs[name2];
2397
- if (typeof original !== "function") continue;
2398
- fs[name2] = (path, ...rest2) => {
2399
- const getattr = this.descriptions.get(path);
2400
- return getattr ? getattr() : original.call(fs, path, ...rest2);
2401
- };
2402
- }
2403
- }
2404
- useControllingTerminal() {
2405
- if (typeof this.Fs.open !== "function") return;
2406
- this.usePtyPaths();
2407
- this.useTerminalNodes();
2408
- this.listSealed();
2409
- const open = this.Fs.open.bind(this.Fs);
2410
- this.Fs.open = (path, flags, mode) => {
2411
- const device2 = typeof path === "string" ? this.devicePath(path) : void 0;
2412
- if (device2 !== void 0 && TTY_PATH.test(device2) && !this.terminalExists(device2)) {
2413
- throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
2414
- }
2415
- const pty = this.openPty(open, path, flags, mode) ?? this.openSealed(open, path, flags, mode) ?? this.openClipboard(open, path, flags, mode);
2416
- if (pty) return pty;
2417
- this.refuseExclusiveLink(path, flags);
2418
- const stream = this.openRacing(open, path, flags, mode);
2419
- if (!stream.tty) return stream;
2420
- if (stream.path === "/dev/tty" && this.sys.openTty) {
2421
- let kfd;
2422
- try {
2423
- kfd = this.call(() => this.sys.openTty?.());
2424
- } catch (e) {
2425
- this.Fs.closeStream(stream.fd);
2426
- throw e;
2427
- }
2428
- this.attach(stream, kfd, true);
2429
- return stream;
2430
- }
2431
- let named;
2432
- try {
2433
- named = stream.path ? this.openNamedTerminal(stream.path) : void 0;
2434
- } catch (e) {
2435
- this.Fs.closeStream(stream.fd);
2436
- throw e;
2437
- }
2438
- if (named !== void 0) {
2439
- this.attach(stream, named, true);
2440
- return stream;
2441
- }
2442
- const terminal = this.stdioTerminal();
2443
- if (terminal !== void 0) this.attach(stream, terminal, true);
2444
- return stream;
2445
- };
2446
- }
2447
- openRacing(open, path, flags, mode) {
2448
- try {
2449
- return open(path, flags, mode);
2450
- } catch (err) {
2451
- const lost = err.errno === wasiErrno("EEXIST") && !(flags & O_EXCL);
2452
- if (!lost) throw err;
2453
- return open(path, flags, mode);
2454
- }
2455
- }
2456
- refuseExclusiveLink(path, flags) {
2457
- if ((flags & (O_CREAT | O_EXCL)) !== (O_CREAT | O_EXCL)) return;
2458
- let mode = 0;
2459
- try {
2460
- mode = this.Fs.stat?.(path, true)?.mode ?? 0;
2461
- } catch {
2462
- }
2463
- if ((mode & 61440) === 40960) throw new this.Fs.ErrnoError(wasiErrno("EEXIST"));
2464
- }
2465
- openPty(open, path, flags, mode) {
2466
- const pts = /^\/dev\/pts\/(\d+)$/.exec(path);
2467
- if (path !== "/dev/ptmx" && !pts) return void 0;
2468
- const { openPty, openPts } = this.sys;
2469
- if (!openPty || !openPts) return void 0;
2470
- const kfd = this.call(
2471
- () => pts ? openPts(Number(pts[1]), (flags & O_NOCTTY) !== 0) : openPty()
2472
- );
2473
- return this.vessel(open, kfd, { path, flags, mode }, true);
2474
- }
2475
- openSealed(open, path, flags, mode) {
2476
- const { openSealed } = this.sys;
2477
- if (path !== SEALED_PATH || !openSealed) return void 0;
2478
- const kfd = this.call(() => openSealed.call(this.sys, flags & 3));
2479
- return this.vessel(open, kfd, { path, flags, mode }, false);
2480
- }
2481
- openClipboard(open, path, flags, mode) {
2482
- const { openClipboard } = this.sys;
2483
- if (path !== CLIPBOARD_PATH || !openClipboard) return void 0;
2484
- const kfd = this.call(() => openClipboard.call(this.sys, flags & 3));
2485
- const stream = this.vessel(open, kfd, { path, flags, mode }, false);
2486
- this.reportClose(kfd);
2487
- return stream;
2488
- }
2489
- vessel(open, kfd, at, terminal) {
2490
- let stream;
2491
- try {
2492
- stream = open("/dev/null", at.flags & ~(O_CREAT | O_EXCL | O_TRUNC2), at.mode);
2493
- } catch (e) {
2494
- this.sys.close(kfd);
2495
- throw e;
2496
- }
2497
- this.attach(stream, kfd, terminal);
2498
- this.nameStream(stream, at.path);
2499
- return stream;
2500
- }
2501
- usePtyPaths() {
2502
- const fs = this.Fs;
2503
- for (const name2 of ["chown", "lchown", "chmod", "lchmod"]) {
2504
- const original = fs[name2];
2505
- if (typeof original !== "function") continue;
2506
- fs[name2] = (path, ...rest2) => isPtyPath(path) ? this.existingPty(path) : original.call(fs, path, ...rest2);
2507
- }
2508
- for (const name2 of ["stat", "lstat"]) {
2509
- const original = fs[name2];
2510
- if (typeof original !== "function") continue;
2511
- fs[name2] = (path, ...rest2) => {
2512
- if (path === SEALED_PATH && this.sys.openSealed) return sealedStat();
2513
- if (path === CLIPBOARD_PATH && this.sys.openClipboard) return sealedStat(251);
2514
- const owned = this.ownedTty(path);
2515
- if (owned && isPtyPath(path)) return this.owned(path, ptyStat(path));
2516
- if (!isPtyPath(path)) {
2517
- const st = original.call(fs, path, ...rest2);
2518
- return owned && TTY_PATH.test(path) ? this.owned(path, st) : st;
2519
- }
2520
- this.existingPty(path);
2521
- return ptyStat(path);
2522
- };
2523
- }
2524
- }
2525
- ownedTty(path) {
2526
- return this.options.owners === true && this.sys.ttyOwner !== void 0 && path !== "/dev/ptmx";
2527
- }
2528
- owned(path, st) {
2529
- const ask = this.sys.ttyOwner;
2530
- const owner = this.call(() => ask.call(this.sys, path));
2531
- if (!owner) return st;
2532
- const mode = st.mode & ~4095 | (owner.mode ?? 400);
2533
- return { ...st, uid: owner.uid, gid: owner.gid, mode };
2534
- }
2535
- existingPty(path) {
2536
- const n = PTY_PATH.exec(path)?.[1];
2537
- const exists = n === void 0 ? this.sys.openPty !== void 0 : this.sys.ptyNumbers?.().includes(Number(n)) ?? false;
2538
- if (!exists) throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
2539
- }
2540
- devicePath(path) {
2541
- const name2 = path.slice(path.lastIndexOf("/") + 1);
2542
- if (!TTY_NAME.test(name2)) return void 0;
2543
- const { lookupPath, cwd } = this.Fs;
2544
- const absolute = path.startsWith("/") ? path : `${cwd?.call(this.Fs) ?? "/"}/${path}`;
2545
- const dir = absolute.slice(0, absolute.lastIndexOf("/")) || "/";
2546
- try {
2547
- const real = lookupPath?.call(this.Fs, dir, { follow: true }).path ?? dir;
2548
- return `${real === "/" ? "" : real}/${name2}`;
2549
- } catch {
2550
- return absolute;
2551
- }
2552
- }
2553
- terminalExists(path) {
2554
- const { analyzePath } = this.Fs;
2555
- return analyzePath?.call(this.Fs, path).exists ?? true;
2556
- }
2557
- openNamedTerminal(path) {
2558
- const { openTty } = this.sys;
2559
- if (!openTty) return void 0;
2560
- try {
2561
- return openTty.call(this.sys, path);
2562
- } catch (e) {
2563
- if (e instanceof SyscallError && e.code === "ENXIO") return void 0;
2564
- return this.call(() => {
2565
- throw e;
2566
- });
2567
- }
2568
- }
2569
- stdioTerminal() {
2570
- for (const fd of [0, 1, 2]) {
2571
- const stream = this.Fs.getStream(fd);
2572
- if (stream?.sliccKernelFd !== void 0 && stream.tty) return stream.sliccKernelFd;
2573
- }
2574
- return void 0;
2575
- }
2576
- usePipes(pipefs) {
2577
- const createPipe = pipefs.createPipe.bind(pipefs);
2578
- pipefs.createPipe = () => {
2579
- const [read2, write2] = this.call(() => this.sys.pipe());
2580
- let fds;
2581
- try {
2582
- fds = createPipe();
2583
- } catch (e) {
2584
- for (const kfd of [read2, write2]) {
2585
- try {
2586
- this.sys.close(kfd);
2587
- } catch {
2588
- }
2589
- }
2590
- throw e;
2591
- }
2592
- this.attach(this.Fs.getStream(fds.readable_fd), read2, false);
2593
- this.attach(this.Fs.getStream(fds.writable_fd), write2, false);
2594
- return fds;
2595
- };
2596
- }
2597
- restarting(syscall) {
2598
- for (; ; ) {
2599
- try {
2600
- return syscall();
2601
- } catch (e) {
2602
- if (!(e instanceof SyscallError && e.code === "EINTR" && this.options.restartable?.())) {
2603
- throw e;
2604
- }
2605
- }
2606
- }
2607
- }
2608
- call(syscall) {
2609
- try {
2610
- return syscall();
2611
- } catch (e) {
2612
- if (e instanceof SyscallError) throw new this.Fs.ErrnoError(wasiErrno(e.code));
2613
- throw e;
2614
- }
2615
- }
2616
- ops(kfd, base) {
2617
- return {
2618
- ...base,
2619
- llseek: () => this.call(() => {
2620
- throw new SyscallError("ESPIPE");
2621
- }),
2622
- read: (s, buffer, offset, length) => this.call(() => {
2623
- const bytes = this.restarting(() => this.sys.read(kfd, length, nonblocking(s)));
2624
- buffer.set(bytes, offset);
2625
- return bytes.length;
2626
- }),
2627
- write: (s, buffer, offset, length) => {
2628
- try {
2629
- const bytes = buffer.slice(offset, offset + length);
2630
- return this.restarting(() => this.sys.write(kfd, bytes, nonblocking(s)));
2631
- } catch (e) {
2632
- if (e instanceof SyscallError && e.code === "EPIPE" && !this.options.sigpipe?.()) {
2633
- throw new ProcessExit(KILLED_BY_SIGPIPE);
2634
- }
2635
- return this.call(() => {
2636
- throw e;
2637
- });
2638
- }
2639
- },
2640
- fsync: () => 0,
2641
- poll: () => {
2642
- const state = this.call(() => this.sys.poll(kfd));
2643
- let mask = 0;
2644
- if (state.readable) mask |= POLLIN | POLLRDNORM;
2645
- if (state.writable) mask |= POLLOUT | POLLWRNORM;
2646
- if (state.hangup) mask |= state.readable ? POLLHUP : POLLERR;
2647
- return mask;
2648
- },
2649
- dup: (stream) => {
2650
- base.dup?.(stream);
2651
- this.refs.set(kfd, (this.refs.get(kfd) ?? 0) + 1);
2652
- },
2653
- close: (stream) => {
2654
- if (this.atExit && stream.fd === 2 && this.reporting.size > 0) this.commitStdout();
2655
- try {
2656
- base.close?.(stream);
2657
- } catch {
2658
- }
2659
- const left = (this.refs.get(kfd) ?? 1) - 1;
2660
- if (left > 0) {
2661
- this.refs.set(kfd, left);
2662
- return;
2663
- }
2664
- this.refs.delete(kfd);
2665
- if (this.committed.size > 0 && this.committed.delete(kfd)) return;
2666
- if (this.reporting.size > 0 && this.reporting.delete(kfd)) {
2667
- this.reportedClose(stream, kfd);
2668
- return;
2669
- }
2670
- try {
2671
- this.sys.close(kfd);
2672
- } catch {
2673
- }
2674
- }
2675
- };
2676
- }
2677
- };
2678
- }
2679
- });
2680
-
2681
- // src/process/process-pty.ts
2682
- function failed(e) {
2683
- const code2 = e?.code;
2684
- if (typeof code2 === "string") return -wasiErrno(code2);
2685
- throw e;
2686
- }
2687
- function ptyIoctl(ioctl, deps) {
2688
- return (fd, op, varargs) => {
2689
- const request = op >>> 0;
2690
- if (request !== TIOCGPTN && request !== TIOCSPTLCK && request !== TIOCSCTTY && request !== TIOCSWINSZ && request !== TIOCPKT) {
2691
- return ioctl(fd, op, varargs);
2692
- }
2693
- const stream = deps.fs()?.getStream(fd);
2694
- const kfd = stream?.sliccKernelFd;
2695
- if (kfd === void 0) return ioctl(fd, op, varargs);
2696
- const heap = deps.heap();
2697
- if (!heap) return -wasiErrno("EFAULT");
2698
- const argp = (heap[varargs >> 2] ?? 0) >>> 0;
2699
- try {
2700
- return answer(request, kfd, argp, heap, deps.kernel);
2701
- } catch (e) {
2702
- return failed(e);
2703
- }
2704
- };
2705
- }
2706
- function answer(request, kfd, argp, heap, kernel) {
2707
- switch (request) {
2708
- case TIOCGPTN:
2709
- heap[argp >> 2] = kernel.ptyNumber(kfd);
2710
- return 0;
2711
- case TIOCSPTLCK:
2712
- kernel.ptyLock(kfd, (heap[argp >> 2] ?? 0) !== 0);
2713
- return 0;
2714
- case TIOCSCTTY:
2715
- kernel.setControllingTerminal(kfd);
2716
- return 0;
2717
- case TIOCPKT:
2718
- kernel.setPacketMode(kfd, (heap[argp >> 2] ?? 0) !== 0);
2719
- return 0;
2720
- default: {
2721
- const word = heap[argp >> 2] ?? 0;
2722
- kernel.setWinsize(kfd, word & 65535, word >>> 16 & 65535);
2723
- return 0;
2724
- }
2725
- }
2726
- }
2727
- var TIOCGPTN, TIOCSPTLCK, TIOCSCTTY, TIOCSWINSZ, TIOCPKT;
2728
- var init_process_pty = __esm({
2729
- "src/process/process-pty.ts"() {
2730
- "use strict";
2731
- init_wasi_errno();
2732
- TIOCGPTN = 2147767344;
2733
- TIOCSPTLCK = 1074025521;
2734
- TIOCSCTTY = 21518;
2735
- TIOCSWINSZ = 21524;
2736
- TIOCPKT = 21536;
2737
- }
2738
- });
2739
-
2740
- // src/process/process-fds.ts
2741
- function closesOnExec(stream) {
2742
- return stream.sliccCloexec === true;
2743
- }
2744
- function setCloseOnExec(stream, on) {
2745
- if (on) stream.sliccCloexec = true;
2746
- else delete stream.sliccCloexec;
2747
- }
2748
- function trackCloseOnExec(Fs) {
2749
- if (tracked.has(Fs)) return;
2750
- tracked.add(Fs);
2751
- if (typeof Fs.dupStream === "function") {
2752
- const dupStream = Fs.dupStream.bind(Fs);
2753
- Fs.dupStream = (stream, fd) => {
2754
- const copy2 = dupStream(stream, fd);
2755
- setCloseOnExec(copy2, false);
2756
- return copy2;
2757
- };
2758
- }
2759
- if (typeof Fs.open === "function") {
2760
- const open = Fs.open.bind(Fs);
2761
- Fs.open = (path, flags, mode) => {
2762
- const cloexec = typeof flags === "number" && (flags & O_CLOEXEC) !== 0;
2763
- const stream = open(path, cloexec ? flags & ~O_CLOEXEC : flags, mode);
2764
- setCloseOnExec(stream, cloexec);
2765
- return stream;
2766
- };
2767
- }
2768
- }
2769
- function marker(deps) {
2770
- return (fd, on) => {
2771
- const stream = deps.fs()?.getStream(fd);
2772
- if (stream) setCloseOnExec(stream, on);
2773
- };
2774
- }
2775
- function cloexecFcntl(fcntl, deps) {
2776
- const mark = marker(deps);
2777
- return (fd, cmd, varargs) => {
2778
- if (cmd === F_DUPFD_CLOEXEC) {
2779
- const copy2 = fcntl(fd, F_DUPFD, varargs);
2780
- if (copy2 >= 0) mark(copy2, true);
2781
- return copy2;
2782
- }
2783
- if (cmd === F_GETFL) {
2784
- const flags = fcntl(fd, cmd, varargs);
2785
- return flags < 0 ? flags : flags & ~O_CLOEXEC;
2649
+ } catch (err) {
2650
+ throw new Fs.ErrnoError(errnoOf(err));
2786
2651
  }
2787
- if (cmd !== F_GETFD && cmd !== F_SETFD) return fcntl(fd, cmd, varargs);
2788
- const stream = deps.fs()?.getStream(fd);
2789
- if (!stream) return -wasiErrno("EBADF");
2790
- if (cmd === F_GETFD) return closesOnExec(stream) ? FD_CLOEXEC : 0;
2791
- const arg = deps.heap()?.[varargs >> 2];
2792
- if (arg === void 0) return -wasiErrno("EINVAL");
2793
- setCloseOnExec(stream, (arg & FD_CLOEXEC) !== 0);
2794
- return 0;
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 };
2795
2659
  };
2796
2660
  }
2797
- function cloexecPipe2(pipe2, deps) {
2798
- const mark = marker(deps);
2799
- return (fdPtr, flags) => {
2800
- const r = pipe2(fdPtr, flags & ~O_CLOEXEC);
2801
- const heap = deps.heap();
2802
- if (r === 0 && flags & O_CLOEXEC && heap) {
2803
- mark(heap[fdPtr >> 2], true);
2804
- mark(heap[(fdPtr >> 2) + 1], true);
2805
- }
2806
- return r;
2807
- };
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;
2808
2670
  }
2809
- function quietTarget(dup3, deps) {
2810
- return (fd = -1, newfd = -1, flags = 0, ...rest2) => {
2811
- const Fs = deps.fs();
2812
- const target = fd === newfd || flags !== 0 ? void 0 : Fs?.getStream(newfd);
2813
- if (target && Fs?.getStream(fd)) {
2814
- try {
2815
- Fs.close?.(target);
2816
- } catch {
2817
- }
2818
- }
2819
- return dup3(fd, newfd, flags, ...rest2);
2820
- };
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("/")}`;
2821
2679
  }
2822
- function cloexecByFlag(syscall, flagArg, deps) {
2823
- const mark = marker(deps);
2824
- return (...args) => {
2825
- const cloexec = ((args[flagArg] ?? 0) & O_CLOEXEC) !== 0;
2826
- if (cloexec) args[flagArg] = args[flagArg] & ~O_CLOEXEC;
2827
- const fd = syscall(...args);
2828
- if (fd >= 0) mark(fd, cloexec);
2829
- return fd;
2830
- };
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;
2831
2686
  }
2832
- function wrapperFactories(deps) {
2833
- const { pty, timer } = deps;
2687
+ function syntheticAttr(mode, ino) {
2688
+ const now = /* @__PURE__ */ new Date();
2834
2689
  return {
2835
- ...timer ? { setitimer: (f) => kernelTimer(f, timer) } : {},
2836
- fcntl: (f) => cloexecFcntl(f, deps),
2837
- pipe2: (f) => cloexecPipe2(f, deps),
2838
- dup3: (f) => cloexecByFlag(quietTarget(f, deps), 2, deps),
2839
- socket: (f) => cloexecByFlag(f, 1, deps),
2840
- accept4: (f) => cloexecByFlag(f, 3, deps),
2841
- ...pty ? { ioctl: (f) => ptyIoctl(f, { fs: deps.fs, heap: deps.heap, kernel: pty }) } : {}
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
2842
2703
  };
2843
2704
  }
2844
- function kernelTimer(setitimer, timer) {
2845
- return (which, ms) => {
2846
- if (which !== 0) return setitimer(which, ms);
2847
- timer.arm(ms ?? 0);
2848
- return 0;
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
+ }
2849
2726
  };
2850
2727
  }
2851
- function syscallOf(glue, name2, value2) {
2852
- const names = Object.keys(IMPORT_NAMES);
2853
- const own = names.find((key) => glue[key] !== void 0 && glue[key] === value2);
2854
- if (own) return own;
2855
- return typeof value2 === "function" ? names.find((key) => glue[key] !== void 0 && IMPORT_NAMES[key] === name2) : void 0;
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;
2743
+ }
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
+ }
2856
2752
  }
2857
- function wrapCloexecSyscalls(imports, glue, deps) {
2858
- if (!glue) return;
2859
- const factories = wrapperFactories(deps);
2860
- const seen = /* @__PURE__ */ new Set();
2861
- for (const namespace of Object.values(imports)) {
2862
- if (!namespace || typeof namespace !== "object" || seen.has(namespace)) continue;
2863
- seen.add(namespace);
2864
- for (const [name2, value2] of Object.entries(namespace)) {
2865
- const key = syscallOf(glue, name2, value2);
2866
- const wrap2 = key && factories[key];
2867
- if (wrap2) namespace[name2] = wrap2(value2);
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 {
2868
2776
  }
2869
2777
  }
2870
2778
  }
2871
- function pathOpensLinks(Fs) {
2872
- const fs = Fs;
2873
- const { mayOpen, isLink } = fs;
2874
- if (!mayOpen || !isLink) return;
2875
- fs.mayOpen = (node, flags) => flags & O_PATH2 && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
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
+ };
2876
2809
  }
2877
- function importKey(namespace, name2, glue) {
2878
- const own = glue?.[name2];
2879
- if (typeof own === "function") {
2880
- const found = Object.keys(namespace).find((k) => namespace[k] === own);
2881
- if (found !== void 0) return found;
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
+ );
2882
2823
  }
2883
- const literal = LITERALS[name2];
2884
- return typeof namespace[literal] === "function" ? literal : void 0;
2824
+ return `${lines.join("\n")}
2825
+ `;
2885
2826
  }
2886
- function wrapImport(imports, name2, glue, wrap2, optional = false) {
2887
- let wrapped = false;
2888
- for (const ns of namespaces(imports)) {
2889
- const key = importKey(ns, name2, glue);
2890
- if (key === void 0) continue;
2891
- ns[key] = wrap2(ns[key]);
2892
- wrapped = true;
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;
2893
2849
  }
2894
- if (!wrapped && !optional && typeof glue?.[name2] === "function") {
2895
- throw new Error(`slicc-kernel cannot find the glue's ${LITERALS[name2]} among its imports`);
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 {
2896
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
+ };
2897
2874
  }
2898
- function kernelUmask(imports, deps) {
2899
- let umask = deps.initial & 511;
2900
- const { glue } = deps;
2901
- wrapImport(imports, "openat", glue, (openat) => (dirfd, path, flags, varargs) => {
2902
- const memory = deps.memory();
2903
- if (flags & O_CREAT2 && varargs && memory) new Int32Array(memory.buffer)[varargs >> 2] &= ~umask;
2904
- return openat(dirfd, path, flags, varargs);
2905
- });
2906
- wrapImport(
2907
- imports,
2908
- "mkdirat",
2909
- glue,
2910
- (mkdirat) => (dirfd, path, mode) => mkdirat(dirfd, path, mode & ~umask)
2911
- );
2912
- wrapImport(
2913
- imports,
2914
- "mknodat",
2915
- glue,
2916
- (mknodat) => (dirfd, path, mode, dev) => mknodat(dirfd, path, mode & ~umask, dev)
2917
- );
2918
- wrapImport(imports, "umask", glue, (own) => {
2919
- own(umask);
2920
- return (mask) => {
2921
- const old = umask;
2922
- umask = mask & 511;
2923
- own(umask);
2924
- deps.set(umask);
2925
- return old;
2926
- };
2927
- });
2875
+ function cString(memory, at) {
2876
+ const bytes = new Uint8Array(memory.buffer, at);
2877
+ return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
2928
2878
  }
2929
- function touching(times, memory) {
2930
- if (times === 0) return true;
2931
- if (!memory) return false;
2932
- const heap = new Int32Array(memory.buffer);
2933
- const nsec = [heap[times + 8 >> 2], heap[times + 24 >> 2]];
2934
- return nsec.every((n) => n === UTIME_NOW || n === UTIME_OMIT);
2879
+ function baseOf(Fs, dirfd) {
2880
+ return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
2935
2881
  }
2936
- function touch(Fs, on, run) {
2937
- if (!Fs || !on) return run();
2938
- Fs.sliccTouch = true;
2882
+ function readonlyRefusal(Fs, memory, call2) {
2883
+ if (!(call2.amode & W_ACCESS)) return 0;
2939
2884
  try {
2940
- return run();
2941
- } finally {
2942
- Fs.sliccTouch = void 0;
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;
2943
2897
  }
2944
2898
  }
2945
- function noFollowUtimes(imports, fs, glue, memory = () => void 0) {
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) {
2946
2927
  wrapImport(
2947
2928
  imports,
2948
- "utimensat",
2949
- { utimensat: glue },
2950
- (utimensat) => (dirfd, path, times, flags) => {
2929
+ "linkat",
2930
+ glue,
2931
+ (own) => (olddirfd, oldpath, newdirfd, newpath, flags) => {
2951
2932
  const Fs = fs();
2952
- const on = touching(times, memory());
2953
- const { utime, lookupPath, ErrnoError } = Fs ?? {};
2954
- if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW) || !utime || !lookupPath || !ErrnoError) {
2955
- return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2956
- }
2957
- Fs.utime = (at, atime, mtime) => {
2958
- const { node } = lookupPath.call(Fs, at, { follow: false });
2959
- if (!node.node_ops.setattr) throw new ErrnoError(EMSCRIPTEN_EPERM);
2960
- node.node_ops.setattr(node, { atime, mtime });
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}`;
2961
2938
  };
2962
2939
  try {
2963
- return touch(Fs, on, () => utimensat(dirfd, path, times, flags));
2964
- } finally {
2965
- Fs.utime = utime;
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);
2966
2946
  }
2967
- }
2947
+ return own(olddirfd, oldpath, newdirfd, newpath, flags);
2948
+ },
2949
+ true
2968
2950
  );
2969
2951
  }
2970
- function errnoOf(err) {
2971
- const { errno: errno2, code: code2 } = err ?? {};
2972
- if (typeof errno2 === "number") return errno2;
2973
- if (typeof code2 === "string") return wasiErrno(code2);
2974
- throw err;
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;
2975
3063
  }
2976
- function persistsItself(stream) {
2977
- const type = stream.node.mount?.type;
2978
- return typeof type?.syncfs === "function";
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
+ }
2979
3124
  }
2980
- function namespaces(imports) {
2981
- const seen = /* @__PURE__ */ new Set();
2982
- for (const namespace of Object.values(imports)) {
2983
- if (namespace && typeof namespace === "object") seen.add(namespace);
3125
+ var init_fd_metadata = __esm({
3126
+ "src/process/fd-metadata.ts"() {
3127
+ "use strict";
3128
+ init_process_fds();
2984
3129
  }
2985
- return [...seen];
3130
+ });
3131
+
3132
+ // src/process/kernel-streams.ts
3133
+ function isPtyPath(path) {
3134
+ return PTY_PATH.test(path);
2986
3135
  }
2987
- function keyOf(namespace, name2, glue) {
2988
- const own = glue?.[name2];
2989
- const found = typeof own === "function" ? Object.keys(namespace).find((k) => namespace[k] === own) : void 0;
2990
- return found ?? (typeof namespace[name2] === "function" ? name2 : void 0);
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
+ };
2991
3154
  }
2992
- function syncFsync(imports, fs, glue) {
2993
- for (const namespace of namespaces(imports)) {
2994
- const key = keyOf(namespace, "fd_sync", glue);
2995
- const original = key === void 0 ? void 0 : namespace[key];
2996
- if (key === void 0 || !original?.isAsync) continue;
2997
- namespace[key] = (fd) => {
2998
- const stream = fs()?.getStream(fd);
2999
- if (!stream) return EBADF;
3000
- if (persistsItself(stream)) return original(fd);
3001
- try {
3002
- const result = stream.stream_ops.fsync?.(stream);
3003
- return typeof result === "number" ? result : 0;
3004
- } catch (err) {
3005
- return errnoOf(err);
3006
- }
3007
- };
3008
- }
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
+ };
3009
3172
  }
3010
- function offsetOf(rest2) {
3011
- const at = rest2.length >= 3 ? Number(rest2[1]) * 2 ** 32 + (Number(rest2[0]) >>> 0) : Number(BigInt.asIntN(64, BigInt(rest2[0])));
3012
- return at >= 0 && Number.isSafeInteger(at) ? at : void 0;
3173
+ function nonblocking(stream) {
3174
+ return (stream.flags & O_NONBLOCK) !== 0 ? { nonblock: true } : void 0;
3013
3175
  }
3014
- function readInto(sys, kfd, target, at) {
3015
- let done = 0;
3016
- while (done < target.length) {
3017
- const got = sys.pread?.(kfd, target.length - done, at + done) ?? new Uint8Array(0);
3018
- if (got.length === 0) break;
3019
- target.set(got, done);
3020
- done += got.length;
3021
- }
3022
- return done;
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;
3023
3182
  }
3024
- function positioned(original, write2, deps) {
3025
- return (fd, iov, iovcnt, ...rest2) => {
3026
- const stream = deps.fs()?.getStream(Number(fd));
3027
- const memory = deps.memory();
3028
- const kfd = stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
3029
- if (kfd === void 0 || !memory || !(write2 ? deps.sys.pwrite : deps.sys.pread)) {
3030
- return original(fd, iov, iovcnt, ...rest2);
3031
- }
3032
- const at = offsetOf(rest2);
3033
- if (at === void 0) return wasiErrno("EINVAL");
3034
- const view = new DataView(memory.buffer);
3035
- let done = 0;
3036
- try {
3037
- for (let i = 0; i < Number(iovcnt); i++) {
3038
- const ptr = view.getUint32(Number(iov) + i * 8, true);
3039
- const len = view.getUint32(Number(iov) + i * 8 + 4, true);
3040
- const part = new Uint8Array(memory.buffer, ptr, len);
3041
- const moved = write2 ? deps.sys.pwrite?.(kfd, part.slice(), at + done) ?? 0 : readInto(deps.sys, kfd, part, at + done);
3042
- done += moved;
3043
- if (moved < len) break;
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;
3223
+ }
3224
+ };
3225
+ SyscallError = class extends Error {
3226
+ code;
3227
+ constructor(code2) {
3228
+ super(code2);
3229
+ this.code = code2;
3230
+ }
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
+ }
3044
3313
  }
3045
- } catch (err) {
3046
- return errnoOf(err);
3047
- }
3048
- view.setUint32(Number(rest2[rest2.length - 1]), done, true);
3049
- return 0;
3050
- };
3051
- }
3052
- function positionalIo(imports, deps) {
3053
- for (const namespace of namespaces(imports)) {
3054
- for (const [name2, write2] of [
3055
- ["fd_pread", false],
3056
- ["fd_pwrite", true]
3057
- ]) {
3058
- const key = keyOf(namespace, name2, deps.glue);
3059
- if (key !== void 0) {
3060
- namespace[key] = positioned(namespace[key], write2, deps);
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);
3061
3325
  }
3062
- }
3063
- }
3064
- }
3065
- function staging(Fs, length) {
3066
- try {
3067
- return new Uint8Array(length);
3068
- } catch {
3069
- throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
3070
- }
3071
- }
3072
- function useFileMmap(Fs, deps) {
3073
- const fs = Fs;
3074
- const mmap = fs.mmap;
3075
- if (typeof mmap !== "function") return;
3076
- fs.mmap = (stream, length, position, prot, flags) => {
3077
- const memalign = deps.memalign();
3078
- const memory = deps.memory();
3079
- const shared = (flags & MAP_TYPE) !== MAP_PRIVATE && (prot & PROT_WRITE) !== 0;
3080
- const kfd = stream.sliccKernelFile ? stream.sliccKernelFd : void 0;
3081
- if (shared && kfd !== void 0) throw new Fs.ErrnoError(wasiErrno("ENODEV"));
3082
- if (stream.stream_ops.mmap && kfd === void 0 || !memalign || !memory || length <= 0 || shared || (stream.flags & O_ACCMODE2) === O_WRONLY || !Fs.isFile(stream.node.mode)) {
3083
- return mmap.call(fs, stream, length, position, prot, flags);
3084
- }
3085
- const data = staging(Fs, length);
3086
- let done = 0;
3087
- try {
3088
- if (kfd !== void 0) done = readInto(deps.sys, kfd, data, position);
3089
- else {
3090
- for (let got = 1; done < length && got > 0; done += got) {
3091
- got = Fs.read(stream, data, done, length - done, position + done);
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);
3092
3348
  }
3093
3349
  }
3094
- } catch (err) {
3095
- throw new Fs.ErrnoError(errnoOf(err));
3096
- }
3097
- const size = Math.ceil(length / MAP_ALIGN) * MAP_ALIGN;
3098
- const ptr = memalign(MAP_ALIGN, size);
3099
- if (!ptr) throw new Fs.ErrnoError(wasiErrno("ENOMEM"));
3100
- const target = new Uint8Array(memory.buffer, ptr, size);
3101
- target.fill(0);
3102
- target.set(data.subarray(0, done));
3103
- return { ptr, allocated: true };
3104
- };
3105
- }
3106
- function wasmMemory(instance, imports) {
3107
- const isMemory = (v) => v instanceof WebAssembly.Memory;
3108
- const exported = Object.values(instance.exports).find(isMemory);
3109
- if (exported) return exported;
3110
- for (const namespace of Object.values(imports)) {
3111
- const found = Object.values(namespace ?? {}).find(isMemory);
3112
- if (found) return found;
3113
- }
3114
- return void 0;
3115
- }
3116
- function fdOfPath(path, cwd) {
3117
- const parts = [];
3118
- for (const part of `${path.startsWith("/") ? "" : cwd}/${path}`.split("/")) {
3119
- if (part === "" || part === ".") continue;
3120
- if (part === "..") parts.pop();
3121
- else parts.push(part);
3122
- }
3123
- const abs = `/${parts.join("/")}`;
3124
- const std = ["/dev/stdin", "/dev/stdout", "/dev/stderr"].indexOf(abs);
3125
- if (std >= 0) return std;
3126
- const m = /^\/(?:dev|proc\/self)\/fd\/(\d+)$/.exec(abs);
3127
- return m ? Number(m[1]) : void 0;
3128
- }
3129
- function syntheticAttr(mode, ino) {
3130
- const now = /* @__PURE__ */ new Date();
3131
- return {
3132
- dev: 1,
3133
- ino,
3134
- mode,
3135
- nlink: 1,
3136
- uid: 0,
3137
- gid: 0,
3138
- rdev: 0,
3139
- size: 0,
3140
- atime: now,
3141
- mtime: now,
3142
- ctime: now,
3143
- blksize: 4096,
3144
- blocks: 0
3145
- };
3146
- }
3147
- function describeFdDir(Fs) {
3148
- let dir;
3149
- try {
3150
- dir = Fs.lookupPath?.("/proc/self/fd", { follow: true })?.node;
3151
- } catch {
3152
- return;
3153
- }
3154
- const ops = dir?.node_ops;
3155
- const lookup2 = ops?.lookup;
3156
- if (!dir || !lookup2 || ops.getattr) return;
3157
- dir.node_ops = {
3158
- ...ops,
3159
- getattr: () => syntheticAttr(DIR_MODE, 1),
3160
- lookup: (parent, name2) => {
3161
- const entry = lookup2(parent, name2);
3162
- entry.node_ops = {
3163
- ...entry.node_ops,
3164
- getattr: () => syntheticAttr(LINK_MODE, entry.id ?? 0)
3165
- };
3166
- return entry;
3167
- }
3168
- };
3169
- }
3170
- function useZeroDevices(Fs) {
3171
- const { analyzePath, registerDevice, mkdev, makedev } = Fs;
3172
- if (!analyzePath || !registerDevice || !mkdev || !makedev) return;
3173
- const zeros = (_s, buffer, offset, length) => {
3174
- buffer.fill(0, offset, offset + length);
3175
- return length;
3176
- };
3177
- const devices = [
3178
- ["/dev/zero", 5, (_s, _b, _o, length) => length],
3179
- [
3180
- "/dev/full",
3181
- 7,
3182
- (_s, _b, _o, length) => {
3183
- if (length > 0) throw new Fs.ErrnoError(wasiErrno("ENOSPC"));
3184
- return 0;
3350
+ exitStatus(status2) {
3351
+ return this.failedAtExit && status2 === 0 ? 1 : status2;
3185
3352
  }
3186
- ]
3187
- ];
3188
- for (const [path, minor, write2] of devices) {
3189
- if (analyzePath.call(Fs, path).exists) continue;
3190
- const dev = makedev.call(Fs, 1, minor);
3191
- registerDevice.call(Fs, dev, { read: zeros, write: write2, llseek: () => 0 });
3192
- mkdev.call(Fs, path, CHAR_DEVICE, dev);
3193
- }
3194
- }
3195
- function linkStdio(Fs) {
3196
- const { unlink, symlink } = Fs;
3197
- if (!unlink || !symlink) return;
3198
- for (const [fd, name2] of ["stdin", "stdout", "stderr"].entries()) {
3199
- try {
3200
- unlink.call(Fs, `/dev/${name2}`);
3201
- } catch {
3202
- }
3203
- try {
3204
- symlink.call(Fs, `/proc/self/fd/${fd}`, `/dev/${name2}`);
3205
- } catch {
3206
- }
3207
- }
3208
- }
3209
- function useDevFd(Fs) {
3210
- if (typeof Fs.open !== "function") return;
3211
- try {
3212
- Fs.symlink?.("/proc/self/fd", "/dev/fd");
3213
- } catch {
3214
- }
3215
- linkStdio(Fs);
3216
- describeFdDir(Fs);
3217
- const fdOf = (path) => typeof path === "string" ? fdOfPath(path, Fs.cwd()) : void 0;
3218
- const target = (fd) => {
3219
- const stream = Fs.getStream(fd);
3220
- if (!stream) throw new Fs.ErrnoError(wasiErrno("EBADF"));
3221
- return stream;
3222
- };
3223
- const open = Fs.open.bind(Fs);
3224
- Fs.open = (path, flags, mode) => {
3225
- const fd = fdOf(path);
3226
- if (fd === void 0) return open(path, flags, mode);
3227
- const copy2 = Fs.dupStream(target(fd), -1);
3228
- setCloseOnExec(copy2, typeof flags === "number" && (flags & O_CLOEXEC) !== 0);
3229
- return copy2;
3230
- };
3231
- const { stat, fstat } = Fs;
3232
- if (typeof stat !== "function" || typeof fstat !== "function") return;
3233
- Fs.stat = (path, dontFollow) => {
3234
- const fd = dontFollow ? void 0 : fdOf(path);
3235
- if (fd === void 0) return stat.call(Fs, path, dontFollow);
3236
- target(fd);
3237
- return fstat.call(Fs, fd);
3238
- };
3239
- }
3240
- function pinRootKind() {
3241
- pinnedRoot = rootKind();
3242
- }
3243
- function mountTable(mounts = []) {
3244
- const root = pinnedRoot ?? rootKind();
3245
- const lines = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
3246
- for (const m of mounts) {
3247
- const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
3248
- if (m.state !== "ok") options.push(m.state);
3249
- const access = options.includes("ro") ? [] : ["rw"];
3250
- lines.push(
3251
- `${field(m.source)} ${field(m.target)} ${m.type} ${[...access, ...options].join(",")} 0 0`
3252
- );
3253
- }
3254
- return `${lines.join("\n")}
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}
3255
3368
  `;
3256
- }
3257
- function accounts(env = {}) {
3258
- const user = env.USER ?? "web_user";
3259
- const name2 = NAME.test(user) && user !== "root" ? user : "user";
3260
- const home = env.HOME || "/home";
3261
- return {
3262
- passwd: `root:x:0:0:root:/root:/bin/sh
3263
- ${name2}:x:1000:1000:${name2}:${home}:/bin/bash
3264
- `,
3265
- group: `root:x:0:
3266
- ${name2}:x:1000:
3267
- `
3268
- };
3269
- }
3270
- function useMounts(Fs, env = {}, live = false) {
3271
- const { writeFile, mkdirTree } = Fs;
3272
- if (typeof Fs.open !== "function" || typeof writeFile !== "function") return;
3273
- const { passwd, group } = accounts(env);
3274
- const backing = { "/etc/mtab": "/proc/mounts" };
3275
- try {
3276
- if (!live) writeFile.call(Fs, "/proc/mounts", mountTable());
3277
- } catch {
3278
- return;
3279
- }
3280
- try {
3281
- mkdirTree.call(Fs, "/dev/.etc");
3282
- writeFile.call(Fs, "/dev/.etc/passwd", passwd);
3283
- writeFile.call(Fs, "/dev/.etc/group", group);
3284
- writeFile.call(Fs, "/dev/.etc/hosts", hostsFile(hostnameOf(env)));
3285
- writeFile.call(Fs, "/dev/.etc/hostname", `${hostnameOf(env)}
3286
- `);
3287
- backing["/etc/passwd"] = "/dev/.etc/passwd";
3288
- backing["/etc/group"] = "/dev/.etc/group";
3289
- backing["/etc/hosts"] = "/dev/.etc/hosts";
3290
- backing["/etc/hostname"] = "/dev/.etc/hostname";
3291
- } catch {
3292
- }
3293
- const open = Fs.open.bind(Fs);
3294
- Fs.open = (path, flags, mode) => {
3295
- const instead = backing[path];
3296
- if (!instead || (flags & (O_ACCMODE2 | O_CREAT2)) !== 0) return open(path, flags, mode);
3297
- try {
3298
- return open(path, flags, mode);
3299
- } catch (e) {
3300
- if (e?.errno !== wasiErrno("ENOENT")) throw e;
3301
- return open(instead, flags, mode);
3302
- }
3303
- };
3304
- }
3305
- function cString(memory, at) {
3306
- const bytes = new Uint8Array(memory.buffer, at);
3307
- return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0)));
3308
- }
3309
- function baseOf(Fs, dirfd) {
3310
- return dirfd === AT_FDCWD ? Fs.cwd?.() ?? "/" : Fs.getStream?.(dirfd)?.path ?? "/";
3311
- }
3312
- function readonlyRefusal(Fs, memory, call2) {
3313
- if (!(call2.amode & W_ACCESS)) return 0;
3314
- try {
3315
- const name2 = cString(memory, call2.path);
3316
- const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
3317
- const follow2 = (call2.flags & AT_SYMLINK_NOFOLLOW) === 0;
3318
- const { node } = Fs.lookupPath.call(Fs, abs, {
3319
- follow: follow2
3320
- });
3321
- const bridge = node.live ? node.mount.opts.bridge : void 0;
3322
- const stats = bridge;
3323
- const stat = follow2 ? stats?.stat : stats?.lstat;
3324
- return stat?.call(stats, liveNodePath(node)).readonly ? -wasiErrno("EROFS") : 0;
3325
- } catch {
3326
- return 0;
3327
- }
3328
- }
3329
- function kernelChecks(Fs, memory, call2) {
3330
- const name2 = cString(memory, call2.path);
3331
- const abs = name2.startsWith("/") ? name2 : `${baseOf(Fs, call2.dirfd)}/${name2}`;
3332
- const lookupPath = Fs.lookupPath;
3333
- const { node } = lookupPath.call(Fs, abs, { follow: (call2.flags & AT_SYMLINK_NOFOLLOW) === 0 });
3334
- const bridge = node.live ? node.mount.opts.bridge : void 0;
3335
- if (!bridge?.owners || !bridge.access) return 0;
3336
- const kind = call2.flags & AT_EACCESS ? "eaccess" : "access";
3337
- bridge.access(liveNodePath(node), call2.amode, kind, (call2.flags & AT_SYMLINK_NOFOLLOW) !== 0);
3338
- return 0;
3339
- }
3340
- function kernelAccess(imports, fs, memory, glue) {
3341
- wrapImport(imports, "faccessat", glue, (own) => (dirfd, path, amode, flags) => {
3342
- const Fs = fs();
3343
- const heap = memory();
3344
- const call2 = { dirfd, path, amode: amode & 7, flags };
3345
- const refused = Fs?.lookupPath && heap ? readonlyRefusal(Fs, heap, call2) : 0;
3346
- if (refused !== 0) return refused;
3347
- const rc = own(dirfd, path, amode, flags);
3348
- if (rc !== 0 || !Fs?.lookupPath || !heap) return rc;
3349
- try {
3350
- return kernelChecks(Fs, heap, { dirfd, path, amode: amode & 7, flags });
3351
- } catch (err) {
3352
- return -errnoOf(err);
3353
- }
3354
- });
3355
- }
3356
- function kernelLink(imports, fs, memory, glue) {
3357
- wrapImport(
3358
- imports,
3359
- "linkat",
3360
- glue,
3361
- (own) => (olddirfd, oldpath, newdirfd, newpath, flags) => {
3362
- const Fs = fs();
3363
- const heap = memory();
3364
- if (!Fs?.lookupPath || !heap) return own(olddirfd, oldpath, newdirfd, newpath, flags);
3365
- const at = (dirfd, ptr) => {
3366
- const name2 = cString(heap, ptr);
3367
- return name2.startsWith("/") ? name2 : `${baseOf(Fs, dirfd)}/${name2}`;
3368
- };
3369
- try {
3370
- const from = at(olddirfd, oldpath);
3371
- const to = at(newdirfd, newpath);
3372
- const follow2 = (flags & AT_SYMLINK_FOLLOW) !== 0;
3373
- if (linkLive(Fs, from, to, follow2)) return 0;
3374
- } catch (err) {
3375
- return -errnoOf(err);
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
+ };
3435
+ }
3436
+ sizeFromKernel(stream, kfd) {
3437
+ const { size, fdStat: fdStat2 } = this.sys;
3438
+ if (!size) return;
3439
+ const node = stream.node;
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
+ });
3446
+ }
3447
+ describe(stream, name2, getattr) {
3448
+ if (this.descriptions.size === 0) this.useDescriptions();
3449
+ this.descriptions.set(name2, getattr);
3450
+ stream.path = name2;
3451
+ stream.stream_ops = { ...stream.stream_ops, getattr };
3452
+ }
3453
+ useDescriptions() {
3454
+ const fs = this.Fs;
3455
+ for (const name2 of ["stat", "lstat"]) {
3456
+ const original = fs[name2];
3457
+ if (typeof original !== "function") continue;
3458
+ fs[name2] = (path, ...rest2) => {
3459
+ const getattr = this.descriptions.get(path);
3460
+ return getattr ? getattr() : original.call(fs, path, ...rest2);
3461
+ };
3462
+ }
3463
+ }
3464
+ useKernelFdMetadata() {
3465
+ useKernelFdMetadata(this.Fs, this.sys, this.call.bind(this));
3466
+ }
3467
+ useControllingTerminal() {
3468
+ if (typeof this.Fs.open !== "function") return;
3469
+ this.usePtyPaths();
3470
+ this.useTerminalNodes();
3471
+ this.listSealed();
3472
+ const open = this.Fs.open.bind(this.Fs);
3473
+ this.Fs.open = (path, flags, mode) => {
3474
+ const device2 = typeof path === "string" ? this.devicePath(path) : void 0;
3475
+ if (device2 !== void 0 && TTY_PATH.test(device2) && !this.terminalExists(device2)) {
3476
+ throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
3477
+ }
3478
+ const pty = this.openPty(open, path, flags, mode) ?? this.openSealed(open, path, flags, mode) ?? this.openClipboard(open, path, flags, mode);
3479
+ if (pty) return pty;
3480
+ this.refuseExclusiveLink(path, flags);
3481
+ const stream = this.openRacing(open, path, flags, mode);
3482
+ if (!stream.tty) return stream;
3483
+ if (stream.path === "/dev/tty" && this.sys.openTty) {
3484
+ let kfd;
3485
+ try {
3486
+ kfd = this.call(() => this.sys.openTty?.());
3487
+ } catch (e) {
3488
+ this.Fs.closeStream(stream.fd);
3489
+ throw e;
3490
+ }
3491
+ this.attach(stream, kfd, true);
3492
+ return stream;
3493
+ }
3494
+ let named;
3495
+ try {
3496
+ named = stream.path ? this.openNamedTerminal(stream.path) : void 0;
3497
+ } catch (e) {
3498
+ this.Fs.closeStream(stream.fd);
3499
+ throw e;
3500
+ }
3501
+ if (named !== void 0) {
3502
+ this.attach(stream, named, true);
3503
+ return stream;
3504
+ }
3505
+ const terminal = this.stdioTerminal();
3506
+ if (terminal !== void 0) this.attach(stream, terminal, true);
3507
+ return stream;
3508
+ };
3509
+ }
3510
+ openRacing(open, path, flags, mode) {
3511
+ try {
3512
+ return open(path, flags, mode);
3513
+ } catch (err) {
3514
+ const lost = err.errno === wasiErrno("EEXIST") && !(flags & O_EXCL);
3515
+ if (!lost) throw err;
3516
+ return open(path, flags, mode);
3517
+ }
3518
+ }
3519
+ refuseExclusiveLink(path, flags) {
3520
+ if ((flags & (O_CREAT2 | O_EXCL)) !== (O_CREAT2 | O_EXCL)) return;
3521
+ let mode = 0;
3522
+ try {
3523
+ mode = this.Fs.stat?.(path, true)?.mode ?? 0;
3524
+ } catch {
3525
+ }
3526
+ if ((mode & 61440) === 40960) throw new this.Fs.ErrnoError(wasiErrno("EEXIST"));
3527
+ }
3528
+ openPty(open, path, flags, mode) {
3529
+ const pts = /^\/dev\/pts\/(\d+)$/.exec(path);
3530
+ if (path !== "/dev/ptmx" && !pts) return void 0;
3531
+ const { openPty, openPts } = this.sys;
3532
+ if (!openPty || !openPts) return void 0;
3533
+ const kfd = this.call(
3534
+ () => pts ? openPts(Number(pts[1]), (flags & O_NOCTTY) !== 0) : openPty()
3535
+ );
3536
+ return this.vessel(open, kfd, { path, flags, mode }, true);
3537
+ }
3538
+ openSealed(open, path, flags, mode) {
3539
+ const { openSealed } = this.sys;
3540
+ if (path !== SEALED_PATH || !openSealed) return void 0;
3541
+ const kfd = this.call(() => openSealed.call(this.sys, flags & 3));
3542
+ return this.vessel(open, kfd, { path, flags, mode }, false);
3543
+ }
3544
+ openClipboard(open, path, flags, mode) {
3545
+ const { openClipboard } = this.sys;
3546
+ if (path !== CLIPBOARD_PATH || !openClipboard) return void 0;
3547
+ if (flags & O_DIRECTORY) throw new this.Fs.ErrnoError(wasiErrno("ENOTDIR"));
3548
+ const kfd = this.call(() => openClipboard.call(this.sys, flags & 3));
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
+ }
3558
+ }
3559
+ vessel(open, kfd, at, terminal) {
3560
+ let stream;
3561
+ try {
3562
+ stream = open("/dev/null", at.flags & ~(O_CREAT2 | O_EXCL | O_TRUNC2), at.mode);
3563
+ } catch (e) {
3564
+ this.sys.close(kfd);
3565
+ throw e;
3566
+ }
3567
+ this.attach(stream, kfd, terminal);
3568
+ this.nameStream(stream, at.path);
3569
+ return stream;
3570
+ }
3571
+ usePtyPaths() {
3572
+ const fs = this.Fs;
3573
+ for (const name2 of ["chown", "lchown", "chmod", "lchmod"]) {
3574
+ const original = fs[name2];
3575
+ if (typeof original !== "function") continue;
3576
+ fs[name2] = (path, ...rest2) => isPtyPath(path) ? this.existingPty(path) : original.call(fs, path, ...rest2);
3577
+ }
3578
+ for (const name2 of ["stat", "lstat"]) {
3579
+ const original = fs[name2];
3580
+ if (typeof original !== "function") continue;
3581
+ fs[name2] = (path, ...rest2) => {
3582
+ if (path === SEALED_PATH && this.sys.openSealed) return sealedStat();
3583
+ if (path === CLIPBOARD_PATH && this.sys.openClipboard) return sealedStat(251);
3584
+ const owned = this.ownedTty(path);
3585
+ if (owned && isPtyPath(path)) return this.owned(path, ptyStat(path));
3586
+ if (!isPtyPath(path)) {
3587
+ const st = original.call(fs, path, ...rest2);
3588
+ return owned && TTY_PATH.test(path) ? this.owned(path, st) : st;
3589
+ }
3590
+ this.existingPty(path);
3591
+ return ptyStat(path);
3592
+ };
3593
+ }
3594
+ }
3595
+ ownedTty(path) {
3596
+ return this.options.owners === true && this.sys.ttyOwner !== void 0 && path !== "/dev/ptmx";
3597
+ }
3598
+ owned(path, st) {
3599
+ const ask = this.sys.ttyOwner;
3600
+ const owner = this.call(() => ask.call(this.sys, path));
3601
+ if (!owner) return st;
3602
+ const mode = st.mode & ~4095 | (owner.mode ?? 400);
3603
+ return { ...st, uid: owner.uid, gid: owner.gid, mode };
3604
+ }
3605
+ existingPty(path) {
3606
+ const n = PTY_PATH.exec(path)?.[1];
3607
+ const exists = n === void 0 ? this.sys.openPty !== void 0 : this.sys.ptyNumbers?.().includes(Number(n)) ?? false;
3608
+ if (!exists) throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
3609
+ }
3610
+ devicePath(path) {
3611
+ const name2 = path.slice(path.lastIndexOf("/") + 1);
3612
+ if (!TTY_NAME.test(name2)) return void 0;
3613
+ const { lookupPath, cwd } = this.Fs;
3614
+ const absolute = path.startsWith("/") ? path : `${cwd?.call(this.Fs) ?? "/"}/${path}`;
3615
+ const dir = absolute.slice(0, absolute.lastIndexOf("/")) || "/";
3616
+ try {
3617
+ const real = lookupPath?.call(this.Fs, dir, { follow: true }).path ?? dir;
3618
+ return `${real === "/" ? "" : real}/${name2}`;
3619
+ } catch {
3620
+ return absolute;
3621
+ }
3622
+ }
3623
+ terminalExists(path) {
3624
+ const { analyzePath } = this.Fs;
3625
+ return analyzePath?.call(this.Fs, path).exists ?? true;
3626
+ }
3627
+ openNamedTerminal(path) {
3628
+ const { openTty } = this.sys;
3629
+ if (!openTty) return void 0;
3630
+ try {
3631
+ return openTty.call(this.sys, path);
3632
+ } catch (e) {
3633
+ if (e instanceof SyscallError && e.code === "ENXIO") return void 0;
3634
+ return this.call(() => {
3635
+ throw e;
3636
+ });
3637
+ }
3638
+ }
3639
+ stdioTerminal() {
3640
+ for (const fd of [0, 1, 2]) {
3641
+ const stream = this.Fs.getStream(fd);
3642
+ if (stream?.sliccKernelFd !== void 0 && stream.tty) return stream.sliccKernelFd;
3643
+ }
3644
+ return void 0;
3645
+ }
3646
+ usePipes(pipefs) {
3647
+ const createPipe = pipefs.createPipe.bind(pipefs);
3648
+ pipefs.createPipe = () => {
3649
+ const [read2, write2] = this.call(() => this.sys.pipe());
3650
+ let fds;
3651
+ try {
3652
+ fds = createPipe();
3653
+ } catch (e) {
3654
+ for (const kfd of [read2, write2]) {
3655
+ try {
3656
+ this.sys.close(kfd);
3657
+ } catch {
3658
+ }
3659
+ }
3660
+ throw e;
3661
+ }
3662
+ this.attach(this.Fs.getStream(fds.readable_fd), read2, false);
3663
+ this.attach(this.Fs.getStream(fds.writable_fd), write2, false);
3664
+ return fds;
3665
+ };
3666
+ }
3667
+ restarting(syscall) {
3668
+ for (; ; ) {
3669
+ try {
3670
+ return syscall();
3671
+ } catch (e) {
3672
+ if (!(e instanceof SyscallError && e.code === "EINTR" && this.options.restartable?.())) {
3673
+ throw e;
3674
+ }
3675
+ }
3676
+ }
3677
+ }
3678
+ call(syscall) {
3679
+ try {
3680
+ return syscall();
3681
+ } catch (e) {
3682
+ if (e instanceof SyscallError) throw new this.Fs.ErrnoError(wasiErrno(e.code));
3683
+ throw e;
3684
+ }
3685
+ }
3686
+ ops(kfd, base) {
3687
+ return {
3688
+ ...base,
3689
+ llseek: () => this.call(() => {
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
+ };
3376
3746
  }
3377
- return own(olddirfd, oldpath, newdirfd, newpath, flags);
3378
- },
3379
- true
3380
- );
3381
- }
3382
- function kernelChdir(Fs) {
3383
- const { chdir, lookupPath, ErrnoError } = Fs;
3384
- if (!chdir || !lookupPath || !ErrnoError) return;
3385
- Fs.chdir = (path) => {
3386
- const { node } = lookupPath.call(Fs, path, { follow: true });
3387
- const directory = Fs.isDir?.(node.mode) === true;
3388
- const bridge = node.live && directory ? node.mount.opts.bridge : void 0;
3389
- try {
3390
- bridge?.access?.(liveNodePath(node), X_ACCESS, "eaccess", false);
3391
- } catch (err) {
3392
- throw new ErrnoError(errnoOf(err));
3393
- }
3394
- chdir.call(Fs, path);
3395
- };
3396
- }
3397
- function linuxDevices(Fs) {
3398
- Fs.ignorePermissions = true;
3399
- kernelChdir(Fs);
3400
- const { chmod } = Fs;
3401
- if (!chmod) return;
3402
- for (const [path, mode] of DEVICE_MODES) {
3403
- try {
3404
- chmod.call(Fs, path, mode);
3405
- } catch {
3406
- }
3407
- }
3408
- }
3409
- 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;
3410
- var init_process_fds = __esm({
3411
- "src/process/process-fds.ts"() {
3412
- "use strict";
3413
- init_loopback_names();
3414
- init_live_vfs_fs();
3415
- init_process_pty();
3416
- init_wasi_errno();
3417
- O_CLOEXEC = 524288;
3418
- FD_CLOEXEC = 1;
3419
- F_DUPFD = 0;
3420
- F_GETFD = 1;
3421
- F_SETFD = 2;
3422
- F_GETFL = 3;
3423
- F_DUPFD_CLOEXEC = 1030;
3424
- tracked = /* @__PURE__ */ new WeakSet();
3425
- IMPORT_NAMES = {
3426
- fcntl: "__syscall_fcntl64",
3427
- pipe2: "__syscall_pipe2",
3428
- dup3: "__syscall_dup3",
3429
- socket: "__syscall_socket",
3430
- accept4: "__syscall_accept4",
3431
- ioctl: "__syscall_ioctl",
3432
- setitimer: "_setitimer_js"
3433
- };
3434
- EBADF = 8;
3435
- AT_SYMLINK_NOFOLLOW = 256;
3436
- EMSCRIPTEN_EPERM = 63;
3437
- O_PATH2 = 2097152;
3438
- LITERALS = {
3439
- openat: "__syscall_openat",
3440
- mkdirat: "__syscall_mkdirat",
3441
- mknodat: "__syscall_mknodat",
3442
- umask: "__syscall_umask",
3443
- faccessat: "__syscall_faccessat",
3444
- linkat: "__syscall_linkat",
3445
- utimensat: "__syscall_utimensat",
3446
- getppid: "slicc_getppid_js",
3447
- resizeHeap: "emscripten_resize_heap",
3448
- fdWrite: "fd_write",
3449
- fdRead: "fd_read",
3450
- sleepMs: "slicc_sleep_ms"
3451
3747
  };
3452
- UTIME_NOW = 1073741823;
3453
- UTIME_OMIT = 1073741822;
3454
- PROT_WRITE = 2;
3455
- MAP_PRIVATE = 2;
3456
- MAP_TYPE = 15;
3457
- O_WRONLY = 1;
3458
- MAP_ALIGN = 65536;
3459
- DIR_MODE = 16749;
3460
- LINK_MODE = 41408;
3461
- CHAR_DEVICE = 8630;
3462
- O_ACCMODE2 = 3;
3463
- O_CREAT2 = 64;
3464
- field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
3465
- rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
3466
- NAME = /^[a-z_][a-z0-9_-]*$/i;
3467
- AT_FDCWD = -100;
3468
- AT_EACCESS = 512;
3469
- W_ACCESS = 2;
3470
- X_ACCESS = 1;
3471
- AT_SYMLINK_FOLLOW = 1024;
3472
- DEVICE_MODES = [
3473
- ["/", 493],
3474
- ["/dev", 493],
3475
- ["/dev/null", 438],
3476
- ["/dev/zero", 438],
3477
- ["/dev/full", 438],
3478
- ["/dev/random", 438],
3479
- ["/dev/urandom", 438],
3480
- ["/dev/tty", 438],
3481
- ["/dev/shm", 1023]
3482
- ];
3483
3748
  }
3484
3749
  });
3485
3750
 
@@ -3539,7 +3804,8 @@ function kernelEntry(stream, kernel) {
3539
3804
  }
3540
3805
  const device2 = stream.path === void 0 ? void 0 : NAMED_DEVICES[stream.path];
3541
3806
  const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : device2 ?? "stream";
3542
- 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 };
3543
3809
  }
3544
3810
  function describeInherited(Fs, sys, streams, livePath, actions = []) {
3545
3811
  const table = /* @__PURE__ */ new Map();
@@ -3586,12 +3852,13 @@ function place(Fs, stream, fd) {
3586
3852
  return moved;
3587
3853
  }
3588
3854
  function placeholder(Fs, streams, entry) {
3589
- 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);
3590
3857
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
3591
3858
  if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
3592
- return Fs.open("/dev/null", O_RDWR);
3859
+ return Fs.open("/dev/null", access);
3593
3860
  Fs.mkdirTree(PLACEHOLDER_DIR);
3594
- return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, O_RDWR | O_CREAT3);
3861
+ return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, access | O_CREAT3);
3595
3862
  }
3596
3863
  function asFifo(stream, streams, identity) {
3597
3864
  const inos = streamInos.get(streams) ?? /* @__PURE__ */ new Map();
@@ -4292,7 +4559,7 @@ var KERNEL_VERSION, OS_RELEASE;
4292
4559
  var init_version = __esm({
4293
4560
  "src/version.ts"() {
4294
4561
  "use strict";
4295
- KERNEL_VERSION = true ? "1.91.0" : "0.0.0-dev";
4562
+ KERNEL_VERSION = true ? "1.93.0" : "0.0.0-dev";
4296
4563
  OS_RELEASE = "6.0.0-slicc";
4297
4564
  }
4298
4565
  });
@@ -4793,6 +5060,20 @@ function kernelSys(transport) {
4793
5060
  size(fd) {
4794
5061
  return json2(call2({ op: "fd-vfs-stat", fd }, `fd-vfs-stat ${fd}`)).size;
4795
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
+ },
4796
5077
  ttyNames() {
4797
5078
  return json2(call2({ op: "fd-tty-names" }, "fd-tty-names"));
4798
5079
  },
@@ -4824,6 +5105,9 @@ function kernelSys(transport) {
4824
5105
  openClipboard(flags) {
4825
5106
  return json2(call2({ op: "fd-open-clipboard", flags }, "fd-open-clipboard"));
4826
5107
  },
5108
+ clipboardAbort(fd) {
5109
+ call2({ op: "fd-clipboard-abort", fd }, "fd-clipboard-abort");
5110
+ },
4827
5111
  ptyNumbers() {
4828
5112
  return json2(call2({ op: "pty-list" }, "pty-list"));
4829
5113
  },
@@ -4862,7 +5146,7 @@ function openDevice(Fs, fd, meta) {
4862
5146
  return openAt(Fs, fd, `/dev/${meta.device}`, accessMode(meta.access));
4863
5147
  }
4864
5148
  function openHeld(Fs, fd, meta) {
4865
- 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);
4866
5150
  }
4867
5151
  function openAt(Fs, fd, path, flags) {
4868
5152
  let stream;
@@ -4974,6 +5258,17 @@ function kernelWrappers(imports, module, deps) {
4974
5258
  function bridgeFlags(init) {
4975
5259
  return { ...init.owners ? { owners: true } : {}, ...init.links ? { links: true } : {} };
4976
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
+ }
4977
5272
  async function runWasmProcess(init, port2, deps = {}) {
4978
5273
  const signals = new SignalGate(
4979
5274
  createSyncSabTransport(init.sab, port2, {
@@ -4992,12 +5287,7 @@ async function runWasmProcess(init, port2, deps = {}) {
4992
5287
  const gated = signals.transport();
4993
5288
  let early = () => {
4994
5289
  };
4995
- const transport = {
4996
- call: (req, timeoutMs, label) => {
4997
- if (!FS_OPS.has(req.op)) early();
4998
- return gated.call(req, timeoutMs, label);
4999
- }
5000
- };
5290
+ const transport = credSyncTransport(gated, () => early(), init.cred);
5001
5291
  const sys = kernelSys(transport);
5002
5292
  const encoder5 = new TextEncoder();
5003
5293
  const say = (fd) => (text) => sys.write(fd, encoder5.encode(`${text}
@@ -5080,7 +5370,8 @@ async function runWasmProcess(init, port2, deps = {}) {
5080
5370
  const vfs = mountVfsIntoEmscripten(running.FS, {
5081
5371
  bridge: createSyncFsSabBridge(transport, bridgeFlags(init)),
5082
5372
  cwd: init.cwd,
5083
- warn: deps.warn ?? say(2)
5373
+ warn: deps.warn ?? say(2),
5374
+ cred: init.owners ? init.cred : void 0
5084
5375
  });
5085
5376
  early = () => signals.quiet(() => vfs.flushDirty());
5086
5377
  const sigpipe = () => running.sliccSigpipe?.() === 1;
@@ -5099,6 +5390,7 @@ async function runWasmProcess(init, port2, deps = {}) {
5099
5390
  atExit = () => streams.exiting();
5100
5391
  useMounts(running.FS, init.env, true);
5101
5392
  useZeroDevices(running.FS);
5393
+ useDevRemoval(running.FS);
5102
5394
  useProcfs(running.FS, sys, init.pid);
5103
5395
  if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
5104
5396
  else {
@@ -5108,6 +5400,7 @@ async function runWasmProcess(init, port2, deps = {}) {
5108
5400
  const pipefs = ownValue(running, "PIPEFS");
5109
5401
  if (pipefs) streams.usePipes(pipefs);
5110
5402
  streams.useControllingTerminal();
5403
+ streams.useKernelFdMetadata();
5111
5404
  useDevFd(running.FS);
5112
5405
  useFileMmap(running.FS, {
5113
5406
  sys,
@@ -5119,9 +5412,9 @@ async function runWasmProcess(init, port2, deps = {}) {
5119
5412
  transport,
5120
5413
  Fs: running.FS,
5121
5414
  env: init.env,
5415
+ pid: init.pid,
5122
5416
  beforeSpawn: () => vfs.flush(),
5123
5417
  afterChild: () => vfs.invalidate(),
5124
- pid: init.pid,
5125
5418
  raise: (sig) => running.sliccRaise?.(sig),
5126
5419
  restartable,
5127
5420
  memory: () => memory,
@@ -5141,6 +5434,9 @@ async function runWasmProcess(init, port2, deps = {}) {
5141
5434
  sigpipe,
5142
5435
  restartable
5143
5436
  });
5437
+ return runWithFlush(running, init, streams, vfs);
5438
+ }
5439
+ function runWithFlush(running, init, streams, vfs) {
5144
5440
  try {
5145
5441
  return streams.exitStatus(runMain(running, init));
5146
5442
  } finally {
@@ -5205,7 +5501,7 @@ function runMain(running, init) {
5205
5501
  return status2;
5206
5502
  }
5207
5503
  }
5208
- 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;
5209
5505
  var init_process_runtime = __esm({
5210
5506
  "src/process/process-runtime.ts"() {
5211
5507
  "use strict";
@@ -5231,7 +5527,7 @@ var init_process_runtime = __esm({
5231
5527
  O_WRONLY3 = 1;
5232
5528
  O_RDWR3 = 2;
5233
5529
  O_ACCMODE4 = 3;
5234
- O_DIRECTORY = 65536;
5530
+ O_DIRECTORY2 = 65536;
5235
5531
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY3 : O_RDWR3;
5236
5532
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard", "sealed"]);
5237
5533
  GLUE_TRAILER = [
@@ -5357,6 +5653,21 @@ function physicalPath(fs, path) {
5357
5653
  }
5358
5654
  return `/${walk.done.join("/")}`;
5359
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
+ }
5360
5671
  var MAX_HOPS;
5361
5672
  var init_physical_path = __esm({
5362
5673
  "src/fs/physical-path.ts"() {
@@ -5581,9 +5892,11 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
5581
5892
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
5582
5893
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
5583
5894
  ...bridge.pinned ? { pinned: (handle) => pinnedIo2(bridge, handle, rewriting) } : {},
5584
- ...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
+ } : {},
5585
5898
  ...chown ? {
5586
- 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))
5587
5900
  } : {},
5588
5901
  ...bridge.pread && bridge.pwrite && bridge.truncate ? {
5589
5902
  pread: bridge.pread.bind(bridge),
@@ -6353,6 +6666,7 @@ var init_wasi_fds = __esm({
6353
6666
  const { buffer } = e.file;
6354
6667
  try {
6355
6668
  buffer.flush();
6669
+ this.reported.delete(buffer);
6356
6670
  } catch (err) {
6357
6671
  this.reported.add(buffer);
6358
6672
  this.drop(buffer);
@@ -6418,6 +6732,7 @@ var init_wasi_fds = __esm({
6418
6732
  for (const buffer of this.buffers.values()) {
6419
6733
  try {
6420
6734
  buffer.flush();
6735
+ this.reported.delete(buffer);
6421
6736
  } catch (err) {
6422
6737
  if (!this.reported.has(buffer)) throw err;
6423
6738
  }
@@ -6640,7 +6955,7 @@ var init_wasi_fds = __esm({
6640
6955
  return true;
6641
6956
  }
6642
6957
  try {
6643
- this.fs.create(path);
6958
+ this.fs.create(path, void 0, true);
6644
6959
  return true;
6645
6960
  } catch (err) {
6646
6961
  if (oflags & OFLAGS.EXCL || err.code !== "EEXIST") throw err;
@@ -6954,7 +7269,7 @@ var init_wasi_termios = __esm({
6954
7269
  });
6955
7270
 
6956
7271
  // src/process/wasi/wasi-host.ts
6957
- function idOf2(value2) {
7272
+ function idOf3(value2) {
6958
7273
  return value2 >>> 0 === 4294967295 ? void 0 : value2 >>> 0;
6959
7274
  }
6960
7275
  function linkedOf(st) {
@@ -7031,6 +7346,7 @@ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, AT_EACCESS2, ROOT_IDS, GONE,
7031
7346
  var init_wasi_host = __esm({
7032
7347
  "src/process/wasi/wasi-host.ts"() {
7033
7348
  "use strict";
7349
+ init_dev_removal();
7034
7350
  init_physical_path();
7035
7351
  init_cpu_clock();
7036
7352
  init_cred();
@@ -7128,10 +7444,10 @@ var init_wasi_host = __esm({
7128
7444
  return path;
7129
7445
  };
7130
7446
  const modeOf2 = (st) => (st.mode ?? 0) & 4095;
7131
- const chown = (path, uid, gid, follow2) => {
7447
+ const chown = (path, uid, gid, follow2, handle) => {
7132
7448
  const { chown: own } = this.o.fs;
7133
7449
  if (!own) throw new WasiError("ENOSYS");
7134
- own.call(this.o.fs, path, idOf2(uid), idOf2(gid), follow2);
7450
+ own.call(this.o.fs, path, idOf3(uid), idOf3(gid), follow2, handle);
7135
7451
  };
7136
7452
  const caller = () => {
7137
7453
  const cred = this.o.kernel.call({ op: "proc-cred" });
@@ -7162,7 +7478,11 @@ var init_wasi_host = __esm({
7162
7478
  return follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path);
7163
7479
  };
7164
7480
  return wrap({
7165
- 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
+ },
7166
7486
  path_chown: (dirfd, p, l, uid, gid, flags) => void chown(at(dirfd, p, l), uid, gid, (flags & AT_SYMLINK_NOFOLLOW2) === 0),
7167
7487
  fd_owner: (fd, out) => {
7168
7488
  if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
@@ -7174,14 +7494,14 @@ var init_wasi_host = __esm({
7174
7494
  owner(fdOwned(fd), out);
7175
7495
  },
7176
7496
  path_filestat_owner: (dirfd, lookup2, p, l, statOut, out) => {
7177
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7178
7497
  const path = at(dirfd, p, l);
7498
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7179
7499
  this.writeFilestat(statOut, this.pathFilestat(path, lookup2));
7180
7500
  owner(pathOwned(path, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0), out);
7181
7501
  },
7182
7502
  path_owner: (dirfd, p, l, flags, out) => {
7183
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7184
7503
  const path = at(dirfd, p, l);
7504
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
7185
7505
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW2) === 0), out);
7186
7506
  },
7187
7507
  path_access: (dirfd, p, l, amode, flags) => {
@@ -7438,14 +7758,35 @@ var init_wasi_host = __esm({
7438
7758
  const { mem, fds, o } = this;
7439
7759
  const at = (dirfd, p, l) => fds.resolve(dirfd, mem.string(p, l));
7440
7760
  return {
7441
- path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
7442
- const path = at(dirfd, p, l);
7443
- if (deviceOf(path)) this.interrupted?.();
7444
- const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
7445
- mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
7446
- 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
+ }
7447
7789
  },
7448
- path_filestat_get: (dirfd, lookup2, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2)),
7449
7790
  path_filestat_set_times: (dirfd, lookup2, p, l, atim, mtim, flags) => {
7450
7791
  const path = at(dirfd, p, l);
7451
7792
  fds.flushPath(path);
@@ -7460,6 +7801,7 @@ var init_wasi_host = __esm({
7460
7801
  path_remove_directory: (dirfd, p, l) => void o.fs.rmdir(at(dirfd, p, l)),
7461
7802
  path_unlink_file: (dirfd, p, l) => {
7462
7803
  const path = at(dirfd, p, l);
7804
+ if (inDevTree(path)) return void o.fs.unlink(path);
7463
7805
  const st = o.fs.lstat(path);
7464
7806
  if (st.isDirectory) throw new WasiError("EISDIR");
7465
7807
  const linked = linkedOf(st);
@@ -7691,7 +8033,12 @@ var init_wasi_host = __esm({
7691
8033
  const v = this.mem.view();
7692
8034
  v.setUint8(out, filetype);
7693
8035
  v.setUint16(out + 2, flags, true);
7694
- 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
+ }
7695
8042
  v.setBigUint64(out + 8, rights, true);
7696
8043
  v.setBigUint64(out + 16, RIGHTS.ALL, true);
7697
8044
  }
@@ -7757,6 +8104,21 @@ var init_wasi_host = __esm({
7757
8104
  synthetic(path) {
7758
8105
  return deviceOf(path) !== void 0 || path === SEALED_PATH2 && !!this.o.kernel.sys.openSealed || path === CLIPBOARD_PATH2 && !!this.o.kernel.sys.openClipboard;
7759
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
+ }
7760
8122
  pathFilestat(path, lookup2) {
7761
8123
  if (this.synthetic(path)) {
7762
8124
  return this.local({
@@ -7768,7 +8130,19 @@ var init_wasi_host = __esm({
7768
8130
  }
7769
8131
  this.fds.flushPath(path);
7770
8132
  const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
7771
- 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
+ }
7772
8146
  }
7773
8147
  setTimes(path, atim, mtim, flags, follow2 = true) {
7774
8148
  const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
@@ -7840,6 +8214,7 @@ var init_wasi_threads = __esm({
7840
8214
  "src/process/wasi/wasi-threads.ts"() {
7841
8215
  "use strict";
7842
8216
  init_protocol();
8217
+ init_sync_sab_wire();
7843
8218
  init_wasi_files();
7844
8219
  LAST_TID = 0;
7845
8220
  RUNNING = 1;
@@ -7875,7 +8250,7 @@ var init_wasi_threads = __esm({
7875
8250
  this.beforeSpawn?.();
7876
8251
  const tid = Atomics.add(this.ids, LAST_TID, 1) + 1;
7877
8252
  const modules = this.modules?.();
7878
- const blocked = this.blocked?.() ?? 0;
8253
+ const blocked = this.blocked?.();
7879
8254
  this.port.postMessage({
7880
8255
  type: WASM_THREAD_SPAWN,
7881
8256
  thread: {
@@ -7884,7 +8259,7 @@ var init_wasi_threads = __esm({
7884
8259
  memory: this.memory,
7885
8260
  ids: this.ids.buffer,
7886
8261
  ...modules ? { modules } : {},
7887
- ...blocked ? { blocked } : {}
8262
+ ...anyBlocked(blocked) ? { blocked } : {}
7888
8263
  }
7889
8264
  });
7890
8265
  return tid;
@@ -8105,7 +8480,8 @@ var init_wasix_process = __esm({
8105
8480
  cwd: this.host.cwd,
8106
8481
  ...fds.isShared ? { shared: true } : {},
8107
8482
  setjmps: this.driver.setjmps(),
8108
- ...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() } : {}
8109
8485
  };
8110
8486
  return this.call({
8111
8487
  op: "proc-fork",
@@ -8235,6 +8611,7 @@ function importsContext({
8235
8611
  fs,
8236
8612
  fds,
8237
8613
  syscall: call2,
8614
+ net: network(raw, call2),
8238
8615
  ...processes(host, call2, tid !== MAIN_TID),
8239
8616
  async: {
8240
8617
  submit: (req) => call2({ op: "async-submit", req }),
@@ -8270,6 +8647,30 @@ function importsContext({
8270
8647
  gid: { get: () => live().gid, enumerable: true }
8271
8648
  });
8272
8649
  }
8650
+ function loopbackHost(host) {
8651
+ if (host === "localhost") return "127.0.0.1";
8652
+ if (typeof host === "string" && LOOPBACK.test(host)) return host;
8653
+ throw new WasiError("EINVAL");
8654
+ }
8655
+ function network(raw, call2) {
8656
+ return {
8657
+ connect({ host, port: port2, nonblock = false }) {
8658
+ const to = loopbackHost(host);
8659
+ if (!Number.isInteger(port2) || port2 < 1 || port2 > 65535) throw new WasiError("EINVAL");
8660
+ const fd = call2({ op: "sock-open", domain: "inet" });
8661
+ const addr = { family: "inet", host: to, port: port2 };
8662
+ const r = raw({ op: "sock-connect", fd, addr, ...nonblock ? { nonblock: true } : {} });
8663
+ if (r.ok || nonblock && r.errno === "EINPROGRESS") return fd;
8664
+ raw({ op: "fd-close", fd });
8665
+ throw new WasiError(r.errno);
8666
+ },
8667
+ ready(fd) {
8668
+ const sel = call2({ op: "fd-select", read: [], write: [fd], timeoutMs: 0 });
8669
+ if (!sel.write.includes(fd)) return E.INPROGRESS;
8670
+ return call2({ op: "sock-getopt", fd, level: SOL_SOCKET, name: SO_ERROR });
8671
+ }
8672
+ };
8673
+ }
8273
8674
  function processes(host, call2, inThread) {
8274
8675
  const close = (fd) => void call2({ op: "fd-close", fd });
8275
8676
  const slot2 = (n, how, mine, theirs) => {
@@ -8327,7 +8728,7 @@ function processes(host, call2, inThread) {
8327
8728
  }
8328
8729
  };
8329
8730
  }
8330
- var UID2, STDIO;
8731
+ var UID2, LOOPBACK, SOL_SOCKET, SO_ERROR, STDIO;
8331
8732
  var init_wasi_imports = __esm({
8332
8733
  "src/process/wasi/wasi-imports.ts"() {
8333
8734
  "use strict";
@@ -8336,6 +8737,9 @@ var init_wasi_imports = __esm({
8336
8737
  init_wasi_threads();
8337
8738
  init_wasix_process();
8338
8739
  UID2 = 1e3;
8740
+ LOOPBACK = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
8741
+ SOL_SOCKET = 1;
8742
+ SO_ERROR = 4;
8339
8743
  STDIO = ["stdin", "stdout", "stderr"];
8340
8744
  }
8341
8745
  });
@@ -8583,7 +8987,7 @@ function procfsBridge(fs, tree) {
8583
8987
  }
8584
8988
  const { chown } = fs;
8585
8989
  if (chown) {
8586
- 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));
8587
8991
  }
8588
8992
  return new Proxy(fs, {
8589
8993
  get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
@@ -8741,7 +9145,7 @@ var init_wasi_sigmask = __esm({
8741
9145
  };
8742
9146
  WasiSigmask = class {
8743
9147
  lo;
8744
- hi = 0;
9148
+ hi;
8745
9149
  header;
8746
9150
  deliver;
8747
9151
  process;
@@ -8750,9 +9154,10 @@ var init_wasi_sigmask = __esm({
8750
9154
  this.deliver = deliver;
8751
9155
  this.process = process;
8752
9156
  this.lo = libcBits(Atomics.load(header, SAB_I_BLOCKED));
9157
+ this.hi = Atomics.load(header, SAB_I_BLOCKED_HI);
8753
9158
  }
8754
9159
  static unsupported(header) {
8755
- Atomics.store(header, SAB_I_BLOCKED, 0);
9160
+ storeBlocked(header, [0, 0]);
8756
9161
  }
8757
9162
  set(how, setLo, setHi, old) {
8758
9163
  if (how !== SIG_BLOCK && how !== SIG_UNBLOCK && how !== SIG_SETMASK) return E.INVAL;
@@ -8760,7 +9165,7 @@ var init_wasi_sigmask = __esm({
8760
9165
  this.lo = apply(how, this.lo, setLo | 0) & ~LIBC_UNBLOCKABLE;
8761
9166
  this.hi = apply(how, this.hi, setHi | 0);
8762
9167
  const now = kernelBits(this.lo);
8763
- Atomics.store(this.header, SAB_I_BLOCKED, now);
9168
+ storeBlocked(this.header, [now, this.hi]);
8764
9169
  if ((Atomics.load(this.header, SAB_I_SIGNALS) & ~now) !== 0) this.deliver();
8765
9170
  return E.SUCCESS;
8766
9171
  }
@@ -8768,7 +9173,7 @@ var init_wasi_sigmask = __esm({
8768
9173
  const old = [this.lo, this.hi];
8769
9174
  this.lo = setLo & ~LIBC_UNBLOCKABLE;
8770
9175
  this.hi = setHi | 0;
8771
- Atomics.store(this.header, SAB_I_BLOCKED, kernelBits(this.lo));
9176
+ storeBlocked(this.header, [kernelBits(this.lo), this.hi]);
8772
9177
  return old;
8773
9178
  }
8774
9179
  deliverUnblocked() {
@@ -8781,6 +9186,9 @@ var init_wasi_sigmask = __esm({
8781
9186
  this.set(SIG_SETMASK, lo, hi, () => {
8782
9187
  });
8783
9188
  }
9189
+ inherited() {
9190
+ return [kernelBits(this.lo), this.hi];
9191
+ }
8784
9192
  discard(sig) {
8785
9193
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
8786
9194
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
@@ -10060,7 +10468,7 @@ function readAddr(view, ptr) {
10060
10468
  function ipv6Host(bytes) {
10061
10469
  const zeros = (n) => bytes.subarray(0, n).every((b) => b === 0);
10062
10470
  if (zeros(16)) return "0.0.0.0";
10063
- if (zeros(15) && bytes[15] === 1) return LOOPBACK;
10471
+ if (zeros(15) && bytes[15] === 1) return LOOPBACK2;
10064
10472
  if (zeros(10) && bytes[10] === 255 && bytes[11] === 255) return bytes.subarray(12).join(".");
10065
10473
  const groups = [0, 2, 4, 6, 8, 10, 12, 14].map(
10066
10474
  (i) => (bytes[i] << 8 | bytes[i + 1]).toString(16)
@@ -10217,7 +10625,7 @@ function wasixSocketImports(host, preview1) {
10217
10625
  }
10218
10626
  };
10219
10627
  }
10220
- var INET4, INET6, UNIX, STREAM, ADDR_IP_SIZE, LOOPBACK, OPTIONS;
10628
+ var INET4, INET6, UNIX, STREAM, ADDR_IP_SIZE, LOOPBACK2, OPTIONS;
10221
10629
  var init_wasix_sockets = __esm({
10222
10630
  "src/process/wasi/wasix-sockets.ts"() {
10223
10631
  "use strict";
@@ -10229,7 +10637,7 @@ var init_wasix_sockets = __esm({
10229
10637
  UNIX = 3;
10230
10638
  STREAM = 1;
10231
10639
  ADDR_IP_SIZE = 18;
10232
- LOOPBACK = "127.0.0.1";
10640
+ LOOPBACK2 = "127.0.0.1";
10233
10641
  OPTIONS = {
10234
10642
  1: [1, 15],
10235
10643
  2: [1, 2],
@@ -10758,6 +11166,7 @@ __export(wasi_runtime_exports, {
10758
11166
  runWasiProcess: () => runWasiProcess,
10759
11167
  runWasiThread: () => runWasiThread,
10760
11168
  sigmaskOf: () => sigmaskOf,
11169
+ takeThreadDefault: () => takeThreadDefault,
10761
11170
  trapMessage: () => trapMessage,
10762
11171
  unsupportedImport: () => unsupportedImport,
10763
11172
  wireSignals: () => wireSignals
@@ -10801,7 +11210,7 @@ function sigmaskOf(module, sab, gate, threads, process) {
10801
11210
  WasiSigmask.unsupported(header);
10802
11211
  return void 0;
10803
11212
  }
10804
- if (threads) threads.blocked = () => Atomics.load(header, SAB_I_BLOCKED);
11213
+ if (threads) threads.blocked = () => loadBlocked(header);
10805
11214
  const shared = process && new Int32Array(process, 0, SAB_HEADER_I32);
10806
11215
  return new WasiSigmask(header, () => gate.deliver(), shared);
10807
11216
  }
@@ -11195,7 +11604,7 @@ async function runWasiThread(init, port2) {
11195
11604
  masks: () => null,
11196
11605
  raise: (sig) => signals.raise(sig)
11197
11606
  });
11198
- const signals = new WasiSignals(takeDefault(call2, init.pid));
11607
+ const signals = new WasiSignals(takeThreadDefault(call2, init.pid));
11199
11608
  const threads = new WasiThreads(port2, thread.memory, threadCap(init.env), thread.tid, thread.ids);
11200
11609
  threads.received = thread.modules;
11201
11610
  const id = identify(transport, init);
@@ -11249,7 +11658,7 @@ async function runWasiThread(init, port2) {
11249
11658
  throw e;
11250
11659
  }
11251
11660
  }
11252
- 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;
11253
11662
  var init_wasi_runtime = __esm({
11254
11663
  "src/process/wasi/wasi-runtime.ts"() {
11255
11664
  "use strict";
@@ -11284,6 +11693,17 @@ var init_wasi_runtime = __esm({
11284
11693
  call2({ op: "proc-kill", pid, sig });
11285
11694
  if (defaultAction(sig) === "terminate") throw new WasiExit(128 + sig);
11286
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
+ };
11287
11707
  SLICC_FS = "slicc_fs";
11288
11708
  SLICC_TTY = "slicc_tty";
11289
11709
  RESERVED2 = RESERVED_NAMESPACES;
@@ -11453,6 +11873,13 @@ var init_async_sab = __esm({
11453
11873
  });
11454
11874
 
11455
11875
  // src/process/js/js-kernel.ts
11876
+ function umaskRequest(mask) {
11877
+ if (mask === void 0) return { op: "proc-umask" };
11878
+ if (!Number.isInteger(mask) || mask < 0 || mask > 511) {
11879
+ throw new JsCallError("EINVAL", "umask");
11880
+ }
11881
+ return { op: "proc-umask", mask };
11882
+ }
11456
11883
  function modeOf(mode) {
11457
11884
  if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
11458
11885
  throw new JsCallError("EINVAL", "chmod");
@@ -11677,6 +12104,8 @@ var init_js_kernel = __esm({
11677
12104
 
11678
12105
  // src/process/js/js-children.ts
11679
12106
  function exitedOf(status2) {
12107
+ if ((status2 & 255) === 127)
12108
+ return { status: 128 + (status2 >> 8 & 255), signal: status2 >> 8 & 255, stopped: true };
11680
12109
  const signal = status2 & 127;
11681
12110
  return signal ? { status: 128 + signal, signal } : { status: status2 >> 8 & 255 };
11682
12111
  }
@@ -11713,8 +12142,10 @@ function writable(io, fd) {
11713
12142
  });
11714
12143
  }
11715
12144
  function childOps(kernel, io, defaults, sync) {
11716
- const wait2 = async (pid) => {
11717
- 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 });
11718
12149
  const [, status2] = r.ok && r.kind === "json" ? r.json : [0, 0];
11719
12150
  return exitedOf(status2);
11720
12151
  };
@@ -11728,7 +12159,7 @@ function childOps(kernel, io, defaults, sync) {
11728
12159
  ...stdin !== void 0 ? { stdin: writable(io, stdin) } : {},
11729
12160
  ...stdout !== void 0 ? { stdout: readable(io, stdout) } : {},
11730
12161
  ...stderr !== void 0 ? { stderr: readable(io, stderr) } : {},
11731
- wait: () => wait2(pid),
12162
+ wait: (options) => wait2(pid, options),
11732
12163
  kill: (signal) => kill(pid, signal)
11733
12164
  };
11734
12165
  };
@@ -11934,7 +12365,8 @@ function openRequest(abs, o) {
11934
12365
  flags: flagsOf(o),
11935
12366
  position: 0,
11936
12367
  ...isExclusive(o) ? { exclusive: true } : o.create ? { create: true } : { existing: true },
11937
- ...o.truncate ? { truncate: true } : {}
12368
+ ...o.truncate ? { truncate: true } : {},
12369
+ ...o.create || isExclusive(o) ? { mode: o.mode === void 0 ? 438 : modeOf(o.mode) } : {}
11938
12370
  };
11939
12371
  }
11940
12372
  function index2(n, what) {
@@ -11993,6 +12425,7 @@ function* lookup(abs) {
11993
12425
  const names = yield { op: "fd-tty-names" };
11994
12426
  if (names.includes(abs)) return { kind: "terminal", name: abs };
11995
12427
  }
12428
+ if (name2 === "pts") return { kind: "dir", mode: DIR | 365 };
11996
12429
  const pts = /^pts\/(\d+)$/.exec(name2)?.[1];
11997
12430
  if (pts !== void 0) {
11998
12431
  const open = yield { op: "pty-list" };
@@ -12024,7 +12457,8 @@ function* fdStat(fd, path) {
12024
12457
  if (info.kind === "file") {
12025
12458
  const file = yield { op: "fd-vfs-stat", fd };
12026
12459
  if (file.orphan) return { ...nodeStat(33152, file.size), isFile: true };
12027
- return yield* pathStat(file.path);
12460
+ const st = yield* pathStat(file.path);
12461
+ return { ...st, size: file.size };
12028
12462
  }
12029
12463
  if (info.terminal) return yield* terminalStat(info.terminal);
12030
12464
  if (CHAR_KINDS.has(info.kind)) return nodeStat(CHAR | 438);
@@ -12077,16 +12511,26 @@ function* devReadlink(abs) {
12077
12511
  if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
12078
12512
  throw new JsCallError("EINVAL", abs);
12079
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
+ }
12080
12520
  function* devReaddir(abs) {
12081
12521
  if (abs === "/dev/fd") {
12082
12522
  const fds = yield { op: "fd-list" };
12083
12523
  return fds.map(({ fd }) => String(fd));
12084
12524
  }
12525
+ if (abs === "/dev/pts") {
12526
+ const open = yield { op: "pty-list" };
12527
+ return open.map(String).sort();
12528
+ }
12085
12529
  const node = yield* lookup(abs);
12086
12530
  if (node.kind !== "dir") throw new JsCallError("ENOTDIR", abs);
12087
12531
  const names = yield { op: "fd-tty-names" };
12088
12532
  const ttys = names.filter((n) => /^\/dev\/tty\d+$/.test(n)).map((n) => n.slice(5));
12089
- return [...DEVICES2, "clipboard", "sealed", "tty", "fd", ...STDIO3, ...ttys].sort();
12533
+ return [...DEVICES2, "clipboard", "sealed", "tty", "fd", "pts", ...STDIO3, ...ttys].sort();
12090
12534
  }
12091
12535
  function* aliasOf(fd, abs, o) {
12092
12536
  const info = yield* fdInfo(fd, abs);
@@ -12095,6 +12539,9 @@ function* aliasOf(fd, abs, o) {
12095
12539
  const at = yield { op: "fd-vfs-stat", fd };
12096
12540
  if (!at.orphan)
12097
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);
12098
12545
  }
12099
12546
  const copy2 = yield { op: "fd-dup", fd, min: 3 };
12100
12547
  if (file && o.truncate) {
@@ -12400,11 +12847,18 @@ function plain(status2, text) {
12400
12847
  function local2(url) {
12401
12848
  return isKernelLoopbackHost(new URL(url).hostname);
12402
12849
  }
12850
+ function badPort(url) {
12851
+ const port2 = url.port ? Number(url.port) : 0;
12852
+ return port2 !== 0 && BAD_PORTS.has(port2);
12853
+ }
12403
12854
  function rewrite(hop, status2, location) {
12404
12855
  const next2 = new URL(location, hop.url);
12405
12856
  if (next2.protocol !== "http:" && next2.protocol !== "https:") {
12406
12857
  throw failed3(new JsCallError("EPROTONOSUPPORT", next2.protocol));
12407
12858
  }
12859
+ if (badPort(next2)) {
12860
+ throw failed3(new JsCallError("EACCES", `bad port: ${next2.href}`));
12861
+ }
12408
12862
  if (local2(next2.href) && !local2(hop.url)) {
12409
12863
  const from = new URL(hop.url).origin;
12410
12864
  throw failed3(
@@ -12690,6 +13144,9 @@ function fetchOp(kernel) {
12690
13144
  if (protocol !== "http:" && protocol !== "https:") {
12691
13145
  throw failed3(new JsCallError("EPROTONOSUPPORT", protocol));
12692
13146
  }
13147
+ if (badPort(new URL(request.url))) {
13148
+ throw failed3(new JsCallError("EACCES", `bad port: ${request.url}`));
13149
+ }
12693
13150
  let known = await traitsAt(request.url);
12694
13151
  if (!known.manualRedirects && request.redirect !== "follow") {
12695
13152
  throw failed3(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
@@ -12720,7 +13177,7 @@ function fetchOp(kernel) {
12720
13177
  }
12721
13178
  };
12722
13179
  }
12723
- 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;
12724
13181
  var init_js_fetch = __esm({
12725
13182
  "src/process/js/js-fetch.ts"() {
12726
13183
  "use strict";
@@ -12739,6 +13196,89 @@ var init_js_fetch = __esm({
12739
13196
  ]);
12740
13197
  DECODED = /* @__PURE__ */ new Set(["gzip", "x-gzip", "deflate"]);
12741
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
+ ]);
12742
13282
  OVER = /* @__PURE__ */ Symbol("over");
12743
13283
  TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
12744
13284
  QUOTABLE = /^[\t\x20-\x7e\x80-\xff]*$/;
@@ -12865,8 +13405,8 @@ function netOps(kernel, io) {
12865
13405
  const failed5 = await kernel.json({
12866
13406
  op: "sock-getopt",
12867
13407
  fd,
12868
- level: SOL_SOCKET,
12869
- name: SO_ERROR
13408
+ level: SOL_SOCKET2,
13409
+ name: SO_ERROR2
12870
13410
  });
12871
13411
  if (failed5 !== 0) throw new JsCallError(errnoName(failed5), "connect");
12872
13412
  return connection(fd);
@@ -12874,7 +13414,7 @@ function netOps(kernel, io) {
12874
13414
  }
12875
13415
  };
12876
13416
  }
12877
- var SHUT_RD, SHUT_WR, IPV4, NEVER, SOL_SOCKET, SO_ERROR;
13417
+ var SHUT_RD, SHUT_WR, IPV4, NEVER, SOL_SOCKET2, SO_ERROR2;
12878
13418
  var init_js_net = __esm({
12879
13419
  "src/process/js/js-net.ts"() {
12880
13420
  "use strict";
@@ -12884,8 +13424,8 @@ var init_js_net = __esm({
12884
13424
  SHUT_WR = 1;
12885
13425
  IPV4 = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
12886
13426
  NEVER = new AbortController().signal;
12887
- SOL_SOCKET = 1;
12888
- SO_ERROR = 4;
13427
+ SOL_SOCKET2 = 1;
13428
+ SO_ERROR2 = 4;
12889
13429
  }
12890
13430
  });
12891
13431
 
@@ -13114,6 +13654,24 @@ function laneOf(lane) {
13114
13654
  }
13115
13655
  function syncOps(kernel, shared) {
13116
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
+ };
13117
13675
  const info = (fd) => {
13118
13676
  const known = infos.get(fd);
13119
13677
  if (known) return known;
@@ -13146,10 +13704,17 @@ function syncOps(kernel, shared) {
13146
13704
  const statOf = (op, path) => {
13147
13705
  const abs = resolve(path);
13148
13706
  if (inDev(abs)) return devSync(kernel, devStat(abs, op === "stat"));
13149
- kernel.call({ op: "fd-path-flush", path: abs });
13150
- const s = parseSyncFsStat(kernel.json({ op, path: abs }));
13151
- if (!s) throw new JsCallError("EIO", op);
13152
- 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
+ }
13153
13718
  };
13154
13719
  const openDev2 = (abs, options) => {
13155
13720
  const { fd, file, ...access } = devSync(kernel, devOpen(abs, options));
@@ -13169,27 +13734,34 @@ function syncOps(kernel, shared) {
13169
13734
  const open = (path, options = {}) => {
13170
13735
  const abs = resolve(path);
13171
13736
  if (inDev(abs)) return openDev2(abs, options);
13172
- let existing;
13173
13737
  try {
13174
- existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
13175
- } catch (err) {
13176
- existing = absent(err);
13177
- }
13178
- checkOpen(abs, options, existing);
13179
- const fd = kernel.json(openRequest(abs, options));
13180
- try {
13181
- 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;
13182
13759
  } catch (err) {
13183
- kernel.raw({ op: "fd-close", fd });
13184
- 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);
13185
13764
  }
13186
- infos.set(fd, { kind: "file" });
13187
- const handle = syncFile(kernel, fd, abs, options.append === true, () => {
13188
- infos.delete(fd);
13189
- handles.delete(fd);
13190
- });
13191
- handles.set(fd, handle.invalidate);
13192
- return handle.file;
13193
13765
  };
13194
13766
  return {
13195
13767
  read: read2,
@@ -13201,7 +13773,7 @@ function syncOps(kernel, shared) {
13201
13773
  kernel.call({ op: "fd-close", fd });
13202
13774
  },
13203
13775
  open: procOpenSync(open, kernel, { resolve, pid: shared.pid }),
13204
- fs: procFsSync(syncPathOps(kernel, resolve, statOf, open), kernel, {
13776
+ fs: procFsSync(syncPathOps(kernel, resolve, statOf, open, tryDevSync), kernel, {
13205
13777
  resolve,
13206
13778
  pid: shared.pid
13207
13779
  })
@@ -13271,14 +13843,16 @@ function syncFile(kernel, fd, path, append, forget) {
13271
13843
  }
13272
13844
  };
13273
13845
  }
13274
- function syncPathOps(kernel, resolve, statOf, open) {
13846
+ function syncPathOps(kernel, resolve, statOf, open, tryDev) {
13275
13847
  return {
13276
13848
  stat: (path) => statOf("stat", path),
13277
13849
  lstat: (path) => statOf("lstat", path),
13278
13850
  exists(path) {
13279
13851
  const abs = resolve(path);
13280
13852
  if (inDev(abs)) return devSync(kernel, devExists(abs));
13281
- 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;
13282
13856
  },
13283
13857
  readdir(path) {
13284
13858
  const abs = resolve(path);
@@ -13288,7 +13862,8 @@ function syncPathOps(kernel, resolve, statOf, open) {
13288
13862
  mkdir: (path, options) => void kernel.call({
13289
13863
  op: "mkdir",
13290
13864
  path: resolve(path),
13291
- ...options?.recursive === false ? { exclusive: true } : {}
13865
+ ...options?.recursive === false ? { exclusive: true } : {},
13866
+ mode: options?.mode === void 0 ? 511 : modeOf(options.mode)
13292
13867
  }),
13293
13868
  rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
13294
13869
  unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
@@ -13302,18 +13877,38 @@ function syncPathOps(kernel, resolve, statOf, open) {
13302
13877
  return String(kernel.json({ op: "readlink", path: abs }));
13303
13878
  },
13304
13879
  statfs(path) {
13305
- 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
+ }
13306
13888
  statOf("stat", abs);
13307
13889
  return statFsOf(kernel.json({ op: "statfs", path: abs }));
13308
13890
  },
13309
13891
  readFile(path) {
13310
13892
  const abs = resolve(path);
13311
13893
  if (inDev(abs)) return readWholeSync(open(abs));
13312
- kernel.call({ op: "fd-path-flush", path: abs });
13313
- return kernel.bytes({ op: "read", path: abs });
13314
- },
13315
- writeFile(path, data) {
13316
- const file = open(path, { write: true, create: true, truncate: true });
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
+ }
13903
+ },
13904
+ writeFile(path, data, options) {
13905
+ const mode = options?.mode;
13906
+ const file = open(path, {
13907
+ write: true,
13908
+ create: true,
13909
+ truncate: true,
13910
+ ...mode !== void 0 ? { mode } : {}
13911
+ });
13317
13912
  try {
13318
13913
  file.write(0, typeof data === "string" ? encoder3.encode(data) : data);
13319
13914
  } finally {
@@ -13326,6 +13921,7 @@ var encoder3, noLane, JsSyncKernel;
13326
13921
  var init_js_sync = __esm({
13327
13922
  "src/process/js/js-sync.ts"() {
13328
13923
  "use strict";
13924
+ init_physical_path();
13329
13925
  init_signals();
13330
13926
  init_sync_fs_wire();
13331
13927
  init_sync_sab_bridge();
@@ -13722,6 +14318,55 @@ function readable2(read2) {
13722
14318
  { highWaterMark: 0 }
13723
14319
  );
13724
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
+ }
13725
14370
  function createContext(o) {
13726
14371
  const { kernel } = o;
13727
14372
  const infos = /* @__PURE__ */ new Map();
@@ -13729,6 +14374,7 @@ function createContext(o) {
13729
14374
  const pending = /* @__PURE__ */ new Set();
13730
14375
  const random = o.random ?? ((bytes) => void crypto.getRandomValues(bytes));
13731
14376
  const resolve = (path) => resolvePath(o.cwd, path);
14377
+ const tryDev = (abs) => resolveDevAsync(kernel, abs);
13732
14378
  let exiting;
13733
14379
  const exit = (code2 = 0) => {
13734
14380
  exiting ??= code2;
@@ -13771,32 +14417,25 @@ function createContext(o) {
13771
14417
  const statOf = async (op, path) => {
13772
14418
  const abs = resolve(path);
13773
14419
  if (inDev(abs)) return devAsync(kernel, devStat(abs, op === "stat"));
13774
- await kernel.call({ op: "fd-path-flush", path: abs });
13775
- const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
13776
- if (!s) throw new JsCallError("EIO", op);
13777
- return s;
14420
+ return vfsStat(kernel, abs, op, tryDev);
13778
14421
  };
14422
+ const devIo = { infos, handles, read: read2, write: writeAll };
13779
14423
  const open = async (path, options = {}) => {
13780
14424
  const abs = resolve(path);
13781
- if (inDev(abs)) return openDev(kernel, abs, options, { infos, handles, read: read2, write: writeAll });
13782
- const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
13783
- checkOpen(abs, options, existing);
13784
- const fd = await kernel.json(openRequest(abs, options));
14425
+ if (inDev(abs)) return openDev(kernel, abs, options, devIo);
13785
14426
  try {
13786
- await kernel.call({ op: "fd-vfs-stat", fd });
14427
+ return await vfsOpen(kernel, abs, options, statOf, infos, handles);
13787
14428
  } catch (err) {
13788
- await kernel.raw({ op: "fd-close", fd });
13789
- 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);
13790
14433
  }
13791
- infos.set(fd, { kind: "file" });
13792
- const handle = fileHandle(kernel, fd, abs, options.append === true, () => {
13793
- infos.delete(fd);
13794
- handles.delete(fd);
13795
- });
13796
- handles.set(fd, handle.invalidate);
13797
- return handle.file;
13798
14434
  };
13799
- 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
+ });
13800
14439
  const lane = o.lane ?? laneOf(void 0);
13801
14440
  if (o.lane && o.lane !== noLane) kernel.syncLane = o.lane;
13802
14441
  const syncKernel = new JsSyncKernel(lane, kernel, unwind);
@@ -13812,6 +14451,7 @@ function createContext(o) {
13812
14451
  },
13813
14452
  kill: killer({ self: o.pid, kernel, syncKernel, lane, writes, modes: terminal.modes }),
13814
14453
  cred: () => syncKernel.json({ op: "proc-cred" }),
14454
+ umask: (mask) => syncKernel.json(umaskRequest(mask)),
13815
14455
  setcred(change) {
13816
14456
  if (typeof change !== "object" || change === null || Array.isArray(change)) {
13817
14457
  throw new JsCallError("EINVAL", "setcred");
@@ -13858,6 +14498,7 @@ function createContext(o) {
13858
14498
  },
13859
14499
  sync,
13860
14500
  fetch: fetchOp(kernel),
14501
+ umask: async (mask) => await kernel.json(umaskRequest(mask)),
13861
14502
  sudo: async (args) => await kernel.json({
13862
14503
  op: "proc-sudo",
13863
14504
  args: [...args],
@@ -13990,14 +14631,16 @@ async function sendSome(kernel, fd, body, signal) {
13990
14631
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
13991
14632
  }
13992
14633
  }
13993
- function pathOps(kernel, resolve, statOf, open) {
14634
+ function pathOps(kernel, resolve, statOf, open, tryDev) {
13994
14635
  return {
13995
14636
  stat: (path) => statOf("stat", path),
13996
14637
  lstat: (path) => statOf("lstat", path),
13997
14638
  async exists(path) {
13998
14639
  const abs = resolve(path);
13999
14640
  if (inDev(abs)) return devAsync(kernel, devExists(abs));
14000
- 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;
14001
14644
  },
14002
14645
  async readdir(path) {
14003
14646
  const abs = resolve(path);
@@ -14007,7 +14650,8 @@ function pathOps(kernel, resolve, statOf, open) {
14007
14650
  mkdir: async (path, options) => void await kernel.call({
14008
14651
  op: "mkdir",
14009
14652
  path: resolve(path),
14010
- ...options?.recursive === false ? { exclusive: true } : {}
14653
+ ...options?.recursive === false ? { exclusive: true } : {},
14654
+ mode: options?.mode === void 0 ? 511 : modeOf(options.mode)
14011
14655
  }),
14012
14656
  rm: async (path) => void await kernel.call({ op: "rm", path: resolve(path) }),
14013
14657
  unlink: async (path) => void await kernel.call({ op: "unlink", path: resolve(path) }),
@@ -14021,18 +14665,35 @@ function pathOps(kernel, resolve, statOf, open) {
14021
14665
  return String(await kernel.json({ op: "readlink", path: abs }));
14022
14666
  },
14023
14667
  async statfs(path) {
14024
- 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
+ }
14025
14673
  await statOf("stat", abs);
14026
14674
  return statFsOf(await kernel.json({ op: "statfs", path: abs }));
14027
14675
  },
14028
14676
  async readFile(path) {
14029
14677
  const abs = resolve(path);
14030
14678
  if (inDev(abs)) return readWhole(await open(abs));
14031
- await kernel.call({ op: "fd-path-flush", path: abs });
14032
- return kernel.bytes({ op: "read", path: abs });
14033
- },
14034
- async writeFile(path, data) {
14035
- const file = await open(path, { write: true, create: true, truncate: true });
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
+ }
14688
+ },
14689
+ async writeFile(path, data, options) {
14690
+ const mode = options?.mode;
14691
+ const file = await open(path, {
14692
+ write: true,
14693
+ create: true,
14694
+ truncate: true,
14695
+ ...mode !== void 0 ? { mode } : {}
14696
+ });
14036
14697
  try {
14037
14698
  await file.write(0, typeof data === "string" ? encoder4.encode(data) : data);
14038
14699
  } finally {
@@ -14045,6 +14706,7 @@ var KERNEL_INFO, JsExit, encoder4;
14045
14706
  var init_js_context = __esm({
14046
14707
  "src/process/js/js-context.ts"() {
14047
14708
  "use strict";
14709
+ init_physical_path();
14048
14710
  init_signals();
14049
14711
  init_sync_fs_wire();
14050
14712
  init_version();