@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,7 +99,7 @@ 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
 
@@ -653,9 +655,11 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
653
655
  ...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
654
656
  ...bridge.keptStat ? { keptStat: bridge.keptStat.bind(bridge) } : {},
655
657
  ...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle, rewriting) } : {},
656
- ...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p), ...entry(p)) } : {},
658
+ ...bridge.create ? {
659
+ create: (p, mode, opening2) => mutating(() => bridge.create?.(p, mode, opening2), ...entry(p))
660
+ } : {},
657
661
  ...chown ? {
658
- chown: (p, uid, gid, follow2) => rewriting(p, () => chown.call(bridge, p, uid, gid, follow2))
662
+ chown: (p, ...rest2) => rewriting(p, () => chown.call(bridge, p, ...rest2))
659
663
  } : {},
660
664
  ...bridge.pread && bridge.pwrite && bridge.truncate ? {
661
665
  pread: bridge.pread.bind(bridge),
@@ -993,6 +997,100 @@ var init_protocol = __esm({
993
997
  }
994
998
  });
995
999
 
1000
+ // src/realm/sync-sab-wire.ts
1001
+ function loadBlocked(header) {
1002
+ return [Atomics.load(header, SAB_I_BLOCKED), Atomics.load(header, SAB_I_BLOCKED_HI)];
1003
+ }
1004
+ function storeBlocked(header, [low, high]) {
1005
+ Atomics.store(header, SAB_I_BLOCKED_HI, high);
1006
+ Atomics.store(header, SAB_I_BLOCKED, low);
1007
+ }
1008
+ function loadU53(header, lo, hi) {
1009
+ return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
1010
+ }
1011
+ function publishMemory(sab, bytes) {
1012
+ if (bytes > 0)
1013
+ Atomics.store(new Int32Array(sab, 0, SAB_HEADER_I32), SAB_I_MEMORY, Math.ceil(bytes / 65536));
1014
+ }
1015
+ function decodeSabResult(status2, payload) {
1016
+ switch (status2) {
1017
+ case SAB_STATUS_BYTES:
1018
+ return { ok: true, kind: "bytes", bytes: payload };
1019
+ case SAB_STATUS_VOID:
1020
+ return { ok: true, kind: "void" };
1021
+ case SAB_STATUS_JSON: {
1022
+ try {
1023
+ return { ok: true, kind: "json", json: JSON.parse(decoder.decode(payload)) };
1024
+ } catch {
1025
+ return { ok: false, errno: "EIO", message: "sync-sab: malformed json payload" };
1026
+ }
1027
+ }
1028
+ case SAB_STATUS_ERRNO: {
1029
+ try {
1030
+ const parsed = JSON.parse(decoder.decode(payload));
1031
+ const errno2 = typeof parsed.errno === "string" && /^E[A-Z]+$|^EAI_[A-Z]+$/.test(parsed.errno) ? parsed.errno : "EIO";
1032
+ return { ok: false, errno: errno2, message: String(parsed.message ?? errno2) };
1033
+ } catch {
1034
+ return { ok: false, errno: "EIO", message: "sync-sab: malformed errno payload" };
1035
+ }
1036
+ }
1037
+ default:
1038
+ return { ok: false, errno: "EIO", message: `sync-sab: unknown status ${status2}` };
1039
+ }
1040
+ }
1041
+ function sabViews(sab) {
1042
+ if (sab.byteLength < SAB_MIN_BYTES) {
1043
+ throw new Error(`sync-sab: buffer too small (${sab.byteLength} < ${SAB_MIN_BYTES})`);
1044
+ }
1045
+ return {
1046
+ header: new Int32Array(sab, 0, SAB_HEADER_I32),
1047
+ window: new Uint8Array(sab, SAB_HEADER_BYTES)
1048
+ };
1049
+ }
1050
+ 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;
1051
+ var init_sync_sab_wire = __esm({
1052
+ "src/realm/sync-sab-wire.ts"() {
1053
+ "use strict";
1054
+ SAB_HEADER_I32 = 18;
1055
+ SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
1056
+ SAB_CLOCK_I64 = 3;
1057
+ SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
1058
+ SAB_I_STATE = 0;
1059
+ SAB_I_SEQ = 1;
1060
+ SAB_I_STATUS = 2;
1061
+ SAB_I_TOTAL = 3;
1062
+ SAB_I_CHUNK = 4;
1063
+ SAB_I_OFFSET = 5;
1064
+ SAB_I_REQ = 6;
1065
+ SAB_I_PUB = 7;
1066
+ SAB_I_SIGNALS = 8;
1067
+ SAB_I_TIMERS = 9;
1068
+ SAB_I_MEMORY = 10;
1069
+ SAB_I_TOTAL_HI = 11;
1070
+ SAB_I_OFFSET_HI = 12;
1071
+ SAB_I_KILLED = 13;
1072
+ SAB_I_ASYNC = 14;
1073
+ SAB_I_STOP = 15;
1074
+ SAB_I_BLOCKED = 16;
1075
+ SAB_I_BLOCKED_HI = 17;
1076
+ anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
1077
+ U32 = 2 ** 32;
1078
+ SAB_STATE_IDLE = 0;
1079
+ SAB_STATE_PENDING = 1;
1080
+ SAB_STATE_READY = 2;
1081
+ SAB_STATUS_BYTES = 1;
1082
+ SAB_STATUS_JSON = 2;
1083
+ SAB_STATUS_VOID = 3;
1084
+ SAB_STATUS_ERRNO = 4;
1085
+ SAB_DEFAULT_WINDOW_BYTES = 1024 * 1024;
1086
+ SAB_MIN_BYTES = SAB_HEADER_BYTES + 4096;
1087
+ SYNC_SAB_REQ_MSG = "sync-sab-req";
1088
+ SYNC_SAB_NEXT_MSG = "sync-sab-next";
1089
+ encoder = new TextEncoder();
1090
+ decoder = new TextDecoder();
1091
+ }
1092
+ });
1093
+
996
1094
  // src/process/wasi/wasi-threads.ts
997
1095
  function threadCap(env) {
998
1096
  const asked = Number.parseInt(env.SLICC_WASM_THREADS ?? "", 10);
@@ -1003,6 +1101,7 @@ var init_wasi_threads = __esm({
1003
1101
  "src/process/wasi/wasi-threads.ts"() {
1004
1102
  "use strict";
1005
1103
  init_protocol();
1104
+ init_sync_sab_wire();
1006
1105
  init_wasi_files();
1007
1106
  LAST_TID = 0;
1008
1107
  RUNNING = 1;
@@ -1038,7 +1137,7 @@ var init_wasi_threads = __esm({
1038
1137
  this.beforeSpawn?.();
1039
1138
  const tid = Atomics.add(this.ids, LAST_TID, 1) + 1;
1040
1139
  const modules = this.modules?.();
1041
- const blocked = this.blocked?.() ?? 0;
1140
+ const blocked = this.blocked?.();
1042
1141
  this.port.postMessage({
1043
1142
  type: WASM_THREAD_SPAWN,
1044
1143
  thread: {
@@ -1047,7 +1146,7 @@ var init_wasi_threads = __esm({
1047
1146
  memory: this.memory,
1048
1147
  ids: this.ids.buffer,
1049
1148
  ...modules ? { modules } : {},
1050
- ...blocked ? { blocked } : {}
1149
+ ...anyBlocked(blocked) ? { blocked } : {}
1051
1150
  }
1052
1151
  });
1053
1152
  return tid;
@@ -1114,6 +1213,21 @@ function physicalPath(fs, path) {
1114
1213
  }
1115
1214
  return `/${walk.done.join("/")}`;
1116
1215
  }
1216
+ async function physicalPathAsync(fs, path) {
1217
+ const walk = start(path);
1218
+ for (let part = next(walk); part !== void 0; part = next(walk)) {
1219
+ const at = `/${[...walk.done, part].join("/")}`;
1220
+ let target;
1221
+ try {
1222
+ target = (await fs.lstat(at)).isSymbolicLink ? await fs.readlink(at) : void 0;
1223
+ } catch {
1224
+ return rest(walk, part);
1225
+ }
1226
+ if (target === void 0) walk.done.push(part);
1227
+ else if (!follow(walk, target)) return lexical(path);
1228
+ }
1229
+ return `/${walk.done.join("/")}`;
1230
+ }
1117
1231
  var MAX_HOPS;
1118
1232
  var init_physical_path = __esm({
1119
1233
  "src/fs/physical-path.ts"() {
@@ -1122,88 +1236,18 @@ var init_physical_path = __esm({
1122
1236
  }
1123
1237
  });
1124
1238
 
1125
- // src/realm/sync-sab-wire.ts
1126
- function loadU53(header, lo, hi) {
1127
- return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
1239
+ // src/fs/dev-removal.ts
1240
+ function inDevTree(path) {
1241
+ return path === "/dev" || path.startsWith("/dev/");
1128
1242
  }
1129
- function publishMemory(sab, bytes) {
1130
- if (bytes > 0)
1131
- Atomics.store(new Int32Array(sab, 0, SAB_HEADER_I32), SAB_I_MEMORY, Math.ceil(bytes / 65536));
1132
- }
1133
- function decodeSabResult(status2, payload) {
1134
- switch (status2) {
1135
- case SAB_STATUS_BYTES:
1136
- return { ok: true, kind: "bytes", bytes: payload };
1137
- case SAB_STATUS_VOID:
1138
- return { ok: true, kind: "void" };
1139
- case SAB_STATUS_JSON: {
1140
- try {
1141
- return { ok: true, kind: "json", json: JSON.parse(decoder.decode(payload)) };
1142
- } catch {
1143
- return { ok: false, errno: "EIO", message: "sync-sab: malformed json payload" };
1144
- }
1145
- }
1146
- case SAB_STATUS_ERRNO: {
1147
- try {
1148
- const parsed = JSON.parse(decoder.decode(payload));
1149
- const errno2 = typeof parsed.errno === "string" && /^E[A-Z]+$|^EAI_[A-Z]+$/.test(parsed.errno) ? parsed.errno : "EIO";
1150
- return { ok: false, errno: errno2, message: String(parsed.message ?? errno2) };
1151
- } catch {
1152
- return { ok: false, errno: "EIO", message: "sync-sab: malformed errno payload" };
1153
- }
1154
- }
1155
- default:
1156
- return { ok: false, errno: "EIO", message: `sync-sab: unknown status ${status2}` };
1157
- }
1243
+ function devRemoval(path, cred) {
1244
+ if (!inDevTree(path)) return void 0;
1245
+ if (cred && cred.euid !== 0) return "EACCES";
1246
+ return path === "/dev" ? "EBUSY" : "EPERM";
1158
1247
  }
1159
- function sabViews(sab) {
1160
- if (sab.byteLength < SAB_MIN_BYTES) {
1161
- throw new Error(`sync-sab: buffer too small (${sab.byteLength} < ${SAB_MIN_BYTES})`);
1162
- }
1163
- return {
1164
- header: new Int32Array(sab, 0, SAB_HEADER_I32),
1165
- window: new Uint8Array(sab, SAB_HEADER_BYTES)
1166
- };
1167
- }
1168
- 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;
1169
- var init_sync_sab_wire = __esm({
1170
- "src/realm/sync-sab-wire.ts"() {
1248
+ var init_dev_removal = __esm({
1249
+ "src/fs/dev-removal.ts"() {
1171
1250
  "use strict";
1172
- SAB_HEADER_I32 = 18;
1173
- SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
1174
- SAB_CLOCK_I64 = 3;
1175
- SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
1176
- SAB_I_STATE = 0;
1177
- SAB_I_SEQ = 1;
1178
- SAB_I_STATUS = 2;
1179
- SAB_I_TOTAL = 3;
1180
- SAB_I_CHUNK = 4;
1181
- SAB_I_OFFSET = 5;
1182
- SAB_I_REQ = 6;
1183
- SAB_I_PUB = 7;
1184
- SAB_I_SIGNALS = 8;
1185
- SAB_I_TIMERS = 9;
1186
- SAB_I_MEMORY = 10;
1187
- SAB_I_TOTAL_HI = 11;
1188
- SAB_I_OFFSET_HI = 12;
1189
- SAB_I_KILLED = 13;
1190
- SAB_I_ASYNC = 14;
1191
- SAB_I_STOP = 15;
1192
- SAB_I_BLOCKED = 16;
1193
- U32 = 2 ** 32;
1194
- SAB_STATE_IDLE = 0;
1195
- SAB_STATE_PENDING = 1;
1196
- SAB_STATE_READY = 2;
1197
- SAB_STATUS_BYTES = 1;
1198
- SAB_STATUS_JSON = 2;
1199
- SAB_STATUS_VOID = 3;
1200
- SAB_STATUS_ERRNO = 4;
1201
- SAB_DEFAULT_WINDOW_BYTES = 1024 * 1024;
1202
- SAB_MIN_BYTES = SAB_HEADER_BYTES + 4096;
1203
- SYNC_SAB_REQ_MSG = "sync-sab-req";
1204
- SYNC_SAB_NEXT_MSG = "sync-sab-next";
1205
- encoder = new TextEncoder();
1206
- decoder = new TextDecoder();
1207
1251
  }
1208
1252
  });
1209
1253
 
@@ -1830,6 +1874,7 @@ var init_wasi_fds = __esm({
1830
1874
  const { buffer } = e.file;
1831
1875
  try {
1832
1876
  buffer.flush();
1877
+ this.reported.delete(buffer);
1833
1878
  } catch (err) {
1834
1879
  this.reported.add(buffer);
1835
1880
  this.drop(buffer);
@@ -1895,6 +1940,7 @@ var init_wasi_fds = __esm({
1895
1940
  for (const buffer of this.buffers.values()) {
1896
1941
  try {
1897
1942
  buffer.flush();
1943
+ this.reported.delete(buffer);
1898
1944
  } catch (err) {
1899
1945
  if (!this.reported.has(buffer)) throw err;
1900
1946
  }
@@ -2117,7 +2163,7 @@ var init_wasi_fds = __esm({
2117
2163
  return true;
2118
2164
  }
2119
2165
  try {
2120
- this.fs.create(path);
2166
+ this.fs.create(path, void 0, true);
2121
2167
  return true;
2122
2168
  } catch (err) {
2123
2169
  if (oflags & OFLAGS.EXCL || err.code !== "EEXIST") throw err;
@@ -2508,6 +2554,7 @@ var WasiExit, IDS, NS_PER_MS, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S
2508
2554
  var init_wasi_host = __esm({
2509
2555
  "src/process/wasi/wasi-host.ts"() {
2510
2556
  "use strict";
2557
+ init_dev_removal();
2511
2558
  init_physical_path();
2512
2559
  init_cpu_clock();
2513
2560
  init_cred();
@@ -2605,10 +2652,10 @@ var init_wasi_host = __esm({
2605
2652
  return path;
2606
2653
  };
2607
2654
  const modeOf2 = (st) => (st.mode ?? 0) & 4095;
2608
- const chown = (path, uid, gid, follow2) => {
2655
+ const chown = (path, uid, gid, follow2, handle) => {
2609
2656
  const { chown: own } = this.o.fs;
2610
2657
  if (!own) throw new WasiError("ENOSYS");
2611
- own.call(this.o.fs, path, idOf(uid), idOf(gid), follow2);
2658
+ own.call(this.o.fs, path, idOf(uid), idOf(gid), follow2, handle);
2612
2659
  };
2613
2660
  const caller = () => {
2614
2661
  const cred = this.o.kernel.call({ op: "proc-cred" });
@@ -2639,7 +2686,11 @@ var init_wasi_host = __esm({
2639
2686
  return follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path);
2640
2687
  };
2641
2688
  return wrap({
2642
- fd_chown: (fd, uid, gid) => void chown(pathOf(fd), uid, gid, true),
2689
+ fd_chown: (fd, uid, gid) => {
2690
+ const e = fds.get(fd);
2691
+ const handle = e.type === "file" ? e.file.buffer.handle : void 0;
2692
+ void chown(pathOf(fd), uid, gid, true, handle);
2693
+ },
2643
2694
  path_chown: (dirfd, p, l, uid, gid, flags) => void chown(at(dirfd, p, l), uid, gid, (flags & AT_SYMLINK_NOFOLLOW) === 0),
2644
2695
  fd_owner: (fd, out) => {
2645
2696
  if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
@@ -2651,14 +2702,14 @@ var init_wasi_host = __esm({
2651
2702
  owner(fdOwned(fd), out);
2652
2703
  },
2653
2704
  path_filestat_owner: (dirfd, lookup2, p, l, statOut, out) => {
2654
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
2655
2705
  const path = at(dirfd, p, l);
2706
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
2656
2707
  this.writeFilestat(statOut, this.pathFilestat(path, lookup2));
2657
2708
  owner(pathOwned(path, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0), out);
2658
2709
  },
2659
2710
  path_owner: (dirfd, p, l, flags, out) => {
2660
- if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
2661
2711
  const path = at(dirfd, p, l);
2712
+ if (!this.o.fs.owners) throw new WasiError("ENOTSUP");
2662
2713
  owner(pathOwned(path, (flags & AT_SYMLINK_NOFOLLOW) === 0), out);
2663
2714
  },
2664
2715
  path_access: (dirfd, p, l, amode, flags) => {
@@ -2915,14 +2966,35 @@ var init_wasi_host = __esm({
2915
2966
  const { mem, fds, o } = this;
2916
2967
  const at = (dirfd, p, l) => fds.resolve(dirfd, mem.string(p, l));
2917
2968
  return {
2918
- path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
2919
- const path = at(dirfd, p, l);
2920
- if (deviceOf(path)) this.interrupted?.();
2921
- const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
2922
- mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
2923
- if (fresh) this.created(path, 438);
2969
+ path_open: (dirfd, lookup2, p, l, oflags, rights, _inheriting, fdflags, out) => {
2970
+ const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
2971
+ try {
2972
+ const path = at(dirfd, p, l);
2973
+ if (deviceOf(path)) this.interrupted?.();
2974
+ const fresh = (oflags & OFLAGS.CREAT) !== 0 && !this.synthetic(path) && !o.fs.exists(path);
2975
+ mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
2976
+ if (fresh) this.created(path, 438);
2977
+ } catch (err) {
2978
+ if (err.code !== "ENOENT") throw err;
2979
+ const raw = mem.string(p, l);
2980
+ const joined2 = raw.startsWith("/") ? raw : `${fds.dir(dirfd).path}/${raw}`;
2981
+ const resolved2 = this.resolveForDev(joined2, follow2);
2982
+ if (!resolved2) throw err;
2983
+ mem.view().setUint32(out, fds.open(resolved2, oflags, rights, fdflags), true);
2984
+ }
2985
+ },
2986
+ path_filestat_get: (dirfd, lookup2, p, l, out) => {
2987
+ try {
2988
+ this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2));
2989
+ } catch (err) {
2990
+ if (err.code !== "ENOENT") throw err;
2991
+ const raw = mem.string(p, l);
2992
+ const joined2 = raw.startsWith("/") ? raw : `${fds.dir(dirfd).path}/${raw}`;
2993
+ const resolved2 = this.resolveForDev(joined2, (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0);
2994
+ if (!resolved2) throw err;
2995
+ this.writeFilestat(out, this.pathFilestat(resolved2, lookup2));
2996
+ }
2924
2997
  },
2925
- path_filestat_get: (dirfd, lookup2, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup2)),
2926
2998
  path_filestat_set_times: (dirfd, lookup2, p, l, atim, mtim, flags) => {
2927
2999
  const path = at(dirfd, p, l);
2928
3000
  fds.flushPath(path);
@@ -2937,6 +3009,7 @@ var init_wasi_host = __esm({
2937
3009
  path_remove_directory: (dirfd, p, l) => void o.fs.rmdir(at(dirfd, p, l)),
2938
3010
  path_unlink_file: (dirfd, p, l) => {
2939
3011
  const path = at(dirfd, p, l);
3012
+ if (inDevTree(path)) return void o.fs.unlink(path);
2940
3013
  const st = o.fs.lstat(path);
2941
3014
  if (st.isDirectory) throw new WasiError("EISDIR");
2942
3015
  const linked = linkedOf(st);
@@ -3168,7 +3241,12 @@ var init_wasi_host = __esm({
3168
3241
  const v = this.mem.view();
3169
3242
  v.setUint8(out, filetype);
3170
3243
  v.setUint16(out + 2, flags, true);
3171
- const rights = seeks ? RIGHTS.ALL : RIGHTS.ALL & ~(RIGHTS.FD_SEEK | RIGHTS.FD_TELL);
3244
+ let rights = seeks ? RIGHTS.ALL : RIGHTS.ALL & ~(RIGHTS.FD_SEEK | RIGHTS.FD_TELL);
3245
+ if (e.type === "kernel") {
3246
+ const access = this.o.kernel.sys.access?.(fd);
3247
+ if (access === "read") rights &= ~RIGHTS.FD_WRITE;
3248
+ else if (access === "write") rights &= ~RIGHTS.FD_READ;
3249
+ }
3172
3250
  v.setBigUint64(out + 8, rights, true);
3173
3251
  v.setBigUint64(out + 16, RIGHTS.ALL, true);
3174
3252
  }
@@ -3234,6 +3312,21 @@ var init_wasi_host = __esm({
3234
3312
  synthetic(path) {
3235
3313
  return deviceOf(path) !== void 0 || path === SEALED_PATH && !!this.o.kernel.sys.openSealed || path === CLIPBOARD_PATH && !!this.o.kernel.sys.openClipboard;
3236
3314
  }
3315
+ resolveForDev(path, follow2 = true) {
3316
+ try {
3317
+ if (!follow2) {
3318
+ const slash = path.lastIndexOf("/");
3319
+ if (slash <= 0) return void 0;
3320
+ const parent = physicalPath(this.o.fs, path.slice(0, slash));
3321
+ const resolved3 = `${parent}/${path.slice(slash + 1)}`;
3322
+ return resolved3 !== path && this.synthetic(resolved3) ? resolved3 : void 0;
3323
+ }
3324
+ const resolved2 = physicalPath(this.o.fs, path);
3325
+ return resolved2 !== path && this.synthetic(resolved2) ? resolved2 : void 0;
3326
+ } catch {
3327
+ return void 0;
3328
+ }
3329
+ }
3237
3330
  pathFilestat(path, lookup2) {
3238
3331
  if (this.synthetic(path)) {
3239
3332
  return this.local({
@@ -3245,7 +3338,19 @@ var init_wasi_host = __esm({
3245
3338
  }
3246
3339
  this.fds.flushPath(path);
3247
3340
  const follow2 = (lookup2 & LOOKUP_SYMLINK_FOLLOW) !== 0;
3248
- return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
3341
+ try {
3342
+ return filestatOf(path, follow2 ? this.o.fs.stat(path) : this.o.fs.lstat(path));
3343
+ } catch (err) {
3344
+ if (err.code !== "ENOENT") throw err;
3345
+ const resolved2 = this.resolveForDev(path, follow2);
3346
+ if (!resolved2) throw err;
3347
+ return this.local({
3348
+ filetype: FILETYPE.CHARACTER_DEVICE,
3349
+ size: 0n,
3350
+ ino: pathInode(resolved2),
3351
+ mtimeNs: 0n
3352
+ });
3353
+ }
3249
3354
  }
3250
3355
  setTimes(path, atim, mtim, flags, follow2 = true) {
3251
3356
  const asked = FSTFLAGS.ATIM | FSTFLAGS.ATIM_NOW | FSTFLAGS.MTIM | FSTFLAGS.MTIM_NOW;
@@ -3508,7 +3613,8 @@ var init_wasix_process = __esm({
3508
3613
  cwd: this.host.cwd,
3509
3614
  ...fds.isShared ? { shared: true } : {},
3510
3615
  setjmps: this.driver.setjmps(),
3511
- ...this.host.signals ? { signals: this.host.signals.snapshot() } : {}
3616
+ ...this.host.signals ? { signals: this.host.signals.snapshot() } : {},
3617
+ ...this.host.sigmask ? { blocked: this.host.sigmask.inherited() } : {}
3512
3618
  };
3513
3619
  return this.call({
3514
3620
  op: "proc-fork",
@@ -3638,6 +3744,7 @@ function importsContext({
3638
3744
  fs,
3639
3745
  fds,
3640
3746
  syscall: call2,
3747
+ net: network(raw, call2),
3641
3748
  ...processes(host, call2, tid !== MAIN_TID),
3642
3749
  async: {
3643
3750
  submit: (req) => call2({ op: "async-submit", req }),
@@ -3673,6 +3780,30 @@ function importsContext({
3673
3780
  gid: { get: () => live().gid, enumerable: true }
3674
3781
  });
3675
3782
  }
3783
+ function loopbackHost(host) {
3784
+ if (host === "localhost") return "127.0.0.1";
3785
+ if (typeof host === "string" && LOOPBACK.test(host)) return host;
3786
+ throw new WasiError("EINVAL");
3787
+ }
3788
+ function network(raw, call2) {
3789
+ return {
3790
+ connect({ host, port: port3, nonblock = false }) {
3791
+ const to = loopbackHost(host);
3792
+ if (!Number.isInteger(port3) || port3 < 1 || port3 > 65535) throw new WasiError("EINVAL");
3793
+ const fd = call2({ op: "sock-open", domain: "inet" });
3794
+ const addr = { family: "inet", host: to, port: port3 };
3795
+ const r = raw({ op: "sock-connect", fd, addr, ...nonblock ? { nonblock: true } : {} });
3796
+ if (r.ok || nonblock && r.errno === "EINPROGRESS") return fd;
3797
+ raw({ op: "fd-close", fd });
3798
+ throw new WasiError(r.errno);
3799
+ },
3800
+ ready(fd) {
3801
+ const sel = call2({ op: "fd-select", read: [], write: [fd], timeoutMs: 0 });
3802
+ if (!sel.write.includes(fd)) return E.INPROGRESS;
3803
+ return call2({ op: "sock-getopt", fd, level: SOL_SOCKET, name: SO_ERROR });
3804
+ }
3805
+ };
3806
+ }
3676
3807
  function processes(host, call2, inThread) {
3677
3808
  const close = (fd) => void call2({ op: "fd-close", fd });
3678
3809
  const slot2 = (n, how, mine, theirs) => {
@@ -3730,7 +3861,7 @@ function processes(host, call2, inThread) {
3730
3861
  }
3731
3862
  };
3732
3863
  }
3733
- var UID, STDIO;
3864
+ var UID, LOOPBACK, SOL_SOCKET, SO_ERROR, STDIO;
3734
3865
  var init_wasi_imports = __esm({
3735
3866
  "src/process/wasi/wasi-imports.ts"() {
3736
3867
  "use strict";
@@ -3739,6 +3870,9 @@ var init_wasi_imports = __esm({
3739
3870
  init_wasi_threads();
3740
3871
  init_wasix_process();
3741
3872
  UID = 1e3;
3873
+ LOOPBACK = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
3874
+ SOL_SOCKET = 1;
3875
+ SO_ERROR = 4;
3742
3876
  STDIO = ["stdin", "stdout", "stderr"];
3743
3877
  }
3744
3878
  });
@@ -3884,12 +4018,19 @@ var KERNEL_VERSION, OS_RELEASE;
3884
4018
  var init_version = __esm({
3885
4019
  "src/version.ts"() {
3886
4020
  "use strict";
3887
- KERNEL_VERSION = true ? "1.91.0" : "0.0.0-dev";
4021
+ KERNEL_VERSION = true ? "1.93.0" : "0.0.0-dev";
3888
4022
  OS_RELEASE = "6.0.0-slicc";
3889
4023
  }
3890
4024
  });
3891
4025
 
3892
4026
  // src/process/js/js-kernel.ts
4027
+ function umaskRequest(mask) {
4028
+ if (mask === void 0) return { op: "proc-umask" };
4029
+ if (!Number.isInteger(mask) || mask < 0 || mask > 511) {
4030
+ throw new JsCallError("EINVAL", "umask");
4031
+ }
4032
+ return { op: "proc-umask", mask };
4033
+ }
3893
4034
  function modeOf(mode) {
3894
4035
  if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
3895
4036
  throw new JsCallError("EINVAL", "chmod");
@@ -4114,6 +4255,8 @@ var init_js_kernel = __esm({
4114
4255
 
4115
4256
  // src/process/js/js-children.ts
4116
4257
  function exitedOf(status2) {
4258
+ if ((status2 & 255) === 127)
4259
+ return { status: 128 + (status2 >> 8 & 255), signal: status2 >> 8 & 255, stopped: true };
4117
4260
  const signal = status2 & 127;
4118
4261
  return signal ? { status: 128 + signal, signal } : { status: status2 >> 8 & 255 };
4119
4262
  }
@@ -4150,8 +4293,10 @@ function writable(io, fd) {
4150
4293
  });
4151
4294
  }
4152
4295
  function childOps(kernel, io, defaults, sync) {
4153
- const wait2 = async (pid) => {
4154
- const r = await kernel.blocking({ op: "proc-wait", pid, nohang: false });
4296
+ const wait2 = async (pid, options = {}) => {
4297
+ if (typeof options !== "object" || options === null) throw new JsCallError("EINVAL", "wait");
4298
+ const untraced = options.untraced === true ? { untraced: true } : {};
4299
+ const r = await kernel.blocking({ op: "proc-wait", pid, nohang: false, ...untraced });
4155
4300
  const [, status2] = r.ok && r.kind === "json" ? r.json : [0, 0];
4156
4301
  return exitedOf(status2);
4157
4302
  };
@@ -4165,7 +4310,7 @@ function childOps(kernel, io, defaults, sync) {
4165
4310
  ...stdin !== void 0 ? { stdin: writable(io, stdin) } : {},
4166
4311
  ...stdout !== void 0 ? { stdout: readable(io, stdout) } : {},
4167
4312
  ...stderr !== void 0 ? { stderr: readable(io, stderr) } : {},
4168
- wait: () => wait2(pid),
4313
+ wait: (options) => wait2(pid, options),
4169
4314
  kill: (signal) => kill(pid, signal)
4170
4315
  };
4171
4316
  };
@@ -4371,7 +4516,8 @@ function openRequest(abs, o) {
4371
4516
  flags: flagsOf(o),
4372
4517
  position: 0,
4373
4518
  ...isExclusive(o) ? { exclusive: true } : o.create ? { create: true } : { existing: true },
4374
- ...o.truncate ? { truncate: true } : {}
4519
+ ...o.truncate ? { truncate: true } : {},
4520
+ ...o.create || isExclusive(o) ? { mode: o.mode === void 0 ? 438 : modeOf(o.mode) } : {}
4375
4521
  };
4376
4522
  }
4377
4523
  function index2(n, what) {
@@ -4430,6 +4576,7 @@ function* lookup(abs) {
4430
4576
  const names = yield { op: "fd-tty-names" };
4431
4577
  if (names.includes(abs)) return { kind: "terminal", name: abs };
4432
4578
  }
4579
+ if (name2 === "pts") return { kind: "dir", mode: DIR | 365 };
4433
4580
  const pts = /^pts\/(\d+)$/.exec(name2)?.[1];
4434
4581
  if (pts !== void 0) {
4435
4582
  const open = yield { op: "pty-list" };
@@ -4461,7 +4608,8 @@ function* fdStat(fd, path) {
4461
4608
  if (info.kind === "file") {
4462
4609
  const file = yield { op: "fd-vfs-stat", fd };
4463
4610
  if (file.orphan) return { ...nodeStat(33152, file.size), isFile: true };
4464
- return yield* pathStat(file.path);
4611
+ const st = yield* pathStat(file.path);
4612
+ return { ...st, size: file.size };
4465
4613
  }
4466
4614
  if (info.terminal) return yield* terminalStat(info.terminal);
4467
4615
  if (CHAR_KINDS.has(info.kind)) return nodeStat(CHAR | 438);
@@ -4514,16 +4662,26 @@ function* devReadlink(abs) {
4514
4662
  if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
4515
4663
  throw new JsCallError("EINVAL", abs);
4516
4664
  }
4665
+ function* devResolveTarget(abs) {
4666
+ const node = yield* lookup(abs);
4667
+ if (node.kind === "fd") return yield* fdTarget(node.fd, abs);
4668
+ if (node.kind === "link" && node.fd !== void 0) return yield* fdTarget(node.fd, abs);
4669
+ return void 0;
4670
+ }
4517
4671
  function* devReaddir(abs) {
4518
4672
  if (abs === "/dev/fd") {
4519
4673
  const fds = yield { op: "fd-list" };
4520
4674
  return fds.map(({ fd }) => String(fd));
4521
4675
  }
4676
+ if (abs === "/dev/pts") {
4677
+ const open = yield { op: "pty-list" };
4678
+ return open.map(String).sort();
4679
+ }
4522
4680
  const node = yield* lookup(abs);
4523
4681
  if (node.kind !== "dir") throw new JsCallError("ENOTDIR", abs);
4524
4682
  const names = yield { op: "fd-tty-names" };
4525
4683
  const ttys = names.filter((n) => /^\/dev\/tty\d+$/.test(n)).map((n) => n.slice(5));
4526
- return [...DEVICES, "clipboard", "sealed", "tty", "fd", ...STDIO3, ...ttys].sort();
4684
+ return [...DEVICES, "clipboard", "sealed", "tty", "fd", "pts", ...STDIO3, ...ttys].sort();
4527
4685
  }
4528
4686
  function* aliasOf(fd, abs, o) {
4529
4687
  const info = yield* fdInfo(fd, abs);
@@ -4532,6 +4690,9 @@ function* aliasOf(fd, abs, o) {
4532
4690
  const at = yield { op: "fd-vfs-stat", fd };
4533
4691
  if (!at.orphan)
4534
4692
  return { fd: yield openRequest(at.path, { ...o, create: false }), file };
4693
+ const wantWrite = o.write === true || o.append === true || o.truncate === true;
4694
+ if (wantWrite && info.access === "read") throw new JsCallError("EBADF", abs);
4695
+ if (!wantWrite && info.access === "write") throw new JsCallError("EBADF", abs);
4535
4696
  }
4536
4697
  const copy2 = yield { op: "fd-dup", fd, min: 3 };
4537
4698
  if (file && o.truncate) {
@@ -4883,11 +5044,18 @@ function plain(status2, text) {
4883
5044
  function local2(url) {
4884
5045
  return isKernelLoopbackHost(new URL(url).hostname);
4885
5046
  }
5047
+ function badPort(url) {
5048
+ const port3 = url.port ? Number(url.port) : 0;
5049
+ return port3 !== 0 && BAD_PORTS.has(port3);
5050
+ }
4886
5051
  function rewrite(hop, status2, location) {
4887
5052
  const next2 = new URL(location, hop.url);
4888
5053
  if (next2.protocol !== "http:" && next2.protocol !== "https:") {
4889
5054
  throw failed(new JsCallError("EPROTONOSUPPORT", next2.protocol));
4890
5055
  }
5056
+ if (badPort(next2)) {
5057
+ throw failed(new JsCallError("EACCES", `bad port: ${next2.href}`));
5058
+ }
4891
5059
  if (local2(next2.href) && !local2(hop.url)) {
4892
5060
  const from = new URL(hop.url).origin;
4893
5061
  throw failed(
@@ -5173,6 +5341,9 @@ function fetchOp(kernel) {
5173
5341
  if (protocol !== "http:" && protocol !== "https:") {
5174
5342
  throw failed(new JsCallError("EPROTONOSUPPORT", protocol));
5175
5343
  }
5344
+ if (badPort(new URL(request.url))) {
5345
+ throw failed(new JsCallError("EACCES", `bad port: ${request.url}`));
5346
+ }
5176
5347
  let known = await traitsAt(request.url);
5177
5348
  if (!known.manualRedirects && request.redirect !== "follow") {
5178
5349
  throw failed(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
@@ -5203,7 +5374,7 @@ function fetchOp(kernel) {
5203
5374
  }
5204
5375
  };
5205
5376
  }
5206
- var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
5377
+ var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, BAD_PORTS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
5207
5378
  var init_js_fetch = __esm({
5208
5379
  "src/process/js/js-fetch.ts"() {
5209
5380
  "use strict";
@@ -5222,6 +5393,89 @@ var init_js_fetch = __esm({
5222
5393
  ]);
5223
5394
  DECODED = /* @__PURE__ */ new Set(["gzip", "x-gzip", "deflate"]);
5224
5395
  CREDENTIALS = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2"]);
5396
+ BAD_PORTS = /* @__PURE__ */ new Set([
5397
+ 1,
5398
+ 7,
5399
+ 9,
5400
+ 11,
5401
+ 13,
5402
+ 15,
5403
+ 17,
5404
+ 19,
5405
+ 20,
5406
+ 21,
5407
+ 22,
5408
+ 23,
5409
+ 25,
5410
+ 37,
5411
+ 42,
5412
+ 43,
5413
+ 53,
5414
+ 69,
5415
+ 77,
5416
+ 79,
5417
+ 87,
5418
+ 95,
5419
+ 101,
5420
+ 102,
5421
+ 103,
5422
+ 104,
5423
+ 109,
5424
+ 110,
5425
+ 111,
5426
+ 113,
5427
+ 115,
5428
+ 117,
5429
+ 119,
5430
+ 123,
5431
+ 135,
5432
+ 137,
5433
+ 139,
5434
+ 143,
5435
+ 161,
5436
+ 179,
5437
+ 389,
5438
+ 427,
5439
+ 465,
5440
+ 512,
5441
+ 513,
5442
+ 514,
5443
+ 515,
5444
+ 526,
5445
+ 530,
5446
+ 531,
5447
+ 532,
5448
+ 540,
5449
+ 548,
5450
+ 554,
5451
+ 556,
5452
+ 563,
5453
+ 587,
5454
+ 601,
5455
+ 636,
5456
+ 989,
5457
+ 990,
5458
+ 993,
5459
+ 995,
5460
+ 1719,
5461
+ 1720,
5462
+ 1723,
5463
+ 2049,
5464
+ 3659,
5465
+ 4045,
5466
+ 4190,
5467
+ 5060,
5468
+ 5061,
5469
+ 6e3,
5470
+ 6566,
5471
+ 6665,
5472
+ 6666,
5473
+ 6667,
5474
+ 6668,
5475
+ 6669,
5476
+ 6697,
5477
+ 10080
5478
+ ]);
5225
5479
  OVER = /* @__PURE__ */ Symbol("over");
5226
5480
  TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
5227
5481
  QUOTABLE = /^[\t\x20-\x7e\x80-\xff]*$/;
@@ -5348,8 +5602,8 @@ function netOps(kernel, io) {
5348
5602
  const failed5 = await kernel.json({
5349
5603
  op: "sock-getopt",
5350
5604
  fd,
5351
- level: SOL_SOCKET,
5352
- name: SO_ERROR
5605
+ level: SOL_SOCKET2,
5606
+ name: SO_ERROR2
5353
5607
  });
5354
5608
  if (failed5 !== 0) throw new JsCallError(errnoName(failed5), "connect");
5355
5609
  return connection(fd);
@@ -5357,7 +5611,7 @@ function netOps(kernel, io) {
5357
5611
  }
5358
5612
  };
5359
5613
  }
5360
- var SHUT_RD, SHUT_WR, IPV4, NEVER, SOL_SOCKET, SO_ERROR;
5614
+ var SHUT_RD, SHUT_WR, IPV4, NEVER, SOL_SOCKET2, SO_ERROR2;
5361
5615
  var init_js_net = __esm({
5362
5616
  "src/process/js/js-net.ts"() {
5363
5617
  "use strict";
@@ -5367,8 +5621,47 @@ var init_js_net = __esm({
5367
5621
  SHUT_WR = 1;
5368
5622
  IPV4 = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
5369
5623
  NEVER = new AbortController().signal;
5370
- SOL_SOCKET = 1;
5371
- SO_ERROR = 4;
5624
+ SOL_SOCKET2 = 1;
5625
+ SO_ERROR2 = 4;
5626
+ }
5627
+ });
5628
+
5629
+ // src/fs/owners.ts
5630
+ function inGroup(cred, gid) {
5631
+ return cred.egid === gid || cred.groups.includes(gid);
5632
+ }
5633
+ var ROOT_OWNER;
5634
+ var init_owners = __esm({
5635
+ "src/fs/owners.ts"() {
5636
+ "use strict";
5637
+ init_types();
5638
+ ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
5639
+ }
5640
+ });
5641
+
5642
+ // src/fs/walk.ts
5643
+ var init_walk = __esm({
5644
+ "src/fs/walk.ts"() {
5645
+ "use strict";
5646
+ init_types();
5647
+ }
5648
+ });
5649
+
5650
+ // src/fs/access.ts
5651
+ function permits(cred, perm, want, directory = true) {
5652
+ const mode = perm.mode ?? (directory ? 493 : 420);
5653
+ if (cred.euid === 0) return (want & X_OK) === 0 || directory || (mode & 73) !== 0;
5654
+ const shift = cred.euid === perm.uid ? 6 : inGroup(cred, perm.gid) ? 3 : 0;
5655
+ return (mode >> shift & want) === want;
5656
+ }
5657
+ var X_OK;
5658
+ var init_access = __esm({
5659
+ "src/fs/access.ts"() {
5660
+ "use strict";
5661
+ init_owners();
5662
+ init_types();
5663
+ init_walk();
5664
+ X_OK = 1;
5372
5665
  }
5373
5666
  });
5374
5667
 
@@ -5580,12 +5873,21 @@ function createSyncFsSabBridge(transport, opts = {}) {
5580
5873
  lutimes: (path, atimeMs, mtimeMs, now) => {
5581
5874
  run({ op: "lutimes", path, atimeMs, mtimeMs, ...now ? { now } : {} }, path);
5582
5875
  },
5583
- create: (path, mode) => {
5584
- run({ op: "create", path, ...mode !== void 0 ? { mode } : {} }, path);
5876
+ create: (path, mode, opening2) => {
5877
+ const flags = { ...mode !== void 0 ? { mode } : {}, ...opening2 ? { opening: opening2 } : {} };
5878
+ run({ op: "create", path, ...flags }, path);
5585
5879
  },
5586
- chown: (path, uid, gid, follow2) => {
5880
+ chown: (path, uid, gid, follow2, handle) => {
5587
5881
  const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
5588
- changing({ op: follow2 ? "chown" : "lchown", path, ...ids }, path);
5882
+ changing(
5883
+ {
5884
+ op: follow2 ? "chown" : "lchown",
5885
+ path,
5886
+ ...ids,
5887
+ ...handle !== void 0 ? { handle } : {}
5888
+ },
5889
+ path
5890
+ );
5589
5891
  },
5590
5892
  ...opts.owners ? { owners: true } : {},
5591
5893
  ...opts.links ? { links: true } : {},
@@ -5646,6 +5948,7 @@ function toMs(v) {
5646
5948
  return v instanceof Date ? v.getTime() : v;
5647
5949
  }
5648
5950
  function wantOf2(flags) {
5951
+ if (flags & O_PATH) return 0;
5649
5952
  const mode = flags & O_ACCMODE;
5650
5953
  const read2 = mode === 1 ? 0 : HOLD_READ;
5651
5954
  const write2 = mode !== 0 || (flags & O_TRUNC) !== 0 ? HOLD_WRITE : 0;
@@ -5661,15 +5964,36 @@ function refusal(err) {
5661
5964
  function cachedStat(s, dir) {
5662
5965
  return s.stat !== void 0 && (!dir || s.statAt === syncCallCount());
5663
5966
  }
5967
+ function searchParents(Fs, node, bridge, call2) {
5968
+ const cred = Fs.sliccCred;
5969
+ if (!cred) return;
5970
+ let cur = node.parent;
5971
+ while (cur) {
5972
+ const st = cur.live.stat;
5973
+ if (st && st.uid !== void 0 && st.mode !== void 0) {
5974
+ const perm = { uid: st.uid, gid: st.gid ?? 0, mode: st.mode & 4095 };
5975
+ if (!permits(cred, perm, X_OK, true)) {
5976
+ call2(() => bridge.access?.(liveNodePath(cur), X_OK, "eaccess"));
5977
+ cur.live.stat = void 0;
5978
+ return;
5979
+ }
5980
+ } else {
5981
+ call2(() => bridge.access?.(liveNodePath(cur), X_OK, "eaccess"));
5982
+ return;
5983
+ }
5984
+ if (cur === cur.parent) break;
5985
+ cur = cur.parent;
5986
+ }
5987
+ }
5664
5988
  function linkedStates(bridgeOf) {
5665
5989
  const opens = /* @__PURE__ */ new Map();
5666
5990
  const byId = /* @__PURE__ */ new Map();
5667
- const idOf3 = (st) => st?.ino === void 0 || (st.nlink ?? 1) < 2 ? void 0 : `${st.dev}:${st.ino}`;
5991
+ const idOf4 = (st) => st?.ino === void 0 || (st.nlink ?? 1) < 2 ? void 0 : `${st.dev}:${st.ino}`;
5668
5992
  function know(s, id) {
5669
5993
  s.id = id;
5670
5994
  if (!byId.has(id)) byId.set(id, s);
5671
5995
  }
5672
- function opening(node, on) {
5996
+ function opening2(node, on) {
5673
5997
  const s = node.live;
5674
5998
  if (!on) {
5675
5999
  opens.delete(s);
@@ -5678,14 +6002,14 @@ function linkedStates(bridgeOf) {
5678
6002
  return;
5679
6003
  }
5680
6004
  opens.set(s, node);
5681
- const id = idOf3(s.stat);
6005
+ const id = idOf4(s.stat);
5682
6006
  if (id !== void 0) know(s, id);
5683
6007
  }
5684
6008
  function sharedWith(node) {
5685
6009
  const st = node.live.stat;
5686
6010
  if (st?.ino === void 0) return void 0;
5687
6011
  const id = `${st.dev}:${st.ino}`;
5688
- if (!byId.has(id) && idOf3(st) !== void 0) {
6012
+ if (!byId.has(id) && idOf4(st) !== void 0) {
5689
6013
  for (const [s2, other] of opens) {
5690
6014
  if (s2.id !== void 0 || s2.orphan) continue;
5691
6015
  let st2;
@@ -5693,7 +6017,7 @@ function linkedStates(bridgeOf) {
5693
6017
  st2 = bridgeOf(other).lstat(liveNodePath(other));
5694
6018
  } catch {
5695
6019
  }
5696
- const known = idOf3(st2);
6020
+ const known = idOf4(st2);
5697
6021
  if (known !== void 0) know(s2, known);
5698
6022
  }
5699
6023
  }
@@ -5701,7 +6025,7 @@ function linkedStates(bridgeOf) {
5701
6025
  return s && s !== node.live && !stale(s) ? s : void 0;
5702
6026
  }
5703
6027
  const holder = (node) => opens.get(node.live) ?? node;
5704
- return { opening, sharedWith, know, idOf: idOf3, holder };
6028
+ return { opening: opening2, sharedWith, know, idOf: idOf4, holder };
5705
6029
  }
5706
6030
  function createHelpers(Fs, ops) {
5707
6031
  const bridgeOf = (node) => node.mount.opts.bridge;
@@ -5923,7 +6247,9 @@ function createNodeOps(h) {
5923
6247
  const owned = bridgeOf(node).owners === true;
5924
6248
  if (owned && Fs.isLink(node.mode) && statOf(node).uid === void 0)
5925
6249
  node.live.stat = void 0;
6250
+ const cached = owned && cachedStat(node.live, Fs.isDir(node.mode));
5926
6251
  const st = statOf(node);
6252
+ if (cached) searchParents(Fs, node, bridgeOf(node), call2);
5927
6253
  const s = node.live;
5928
6254
  const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
5929
6255
  const mtime = new Date(st.mtimeMs ?? 0);
@@ -5986,7 +6312,7 @@ function createNodeOps(h) {
5986
6312
  if (masked !== DEFAULT_DIR_PERM) metadataCall(() => bridge.chmod(path, masked));
5987
6313
  } else if (Fs.isFile(mode)) {
5988
6314
  call2(
5989
- () => bridge.create ? bridge.create(path, perm) : bridge.writeFile(path, new Uint8Array(0))
6315
+ () => bridge.create ? bridge.create(path, perm, opening.get(h.Fs) > 0) : bridge.writeFile(path, new Uint8Array(0))
5990
6316
  );
5991
6317
  } else {
5992
6318
  throw new Fs.ErrnoError(wasiErrno("EPERM"));
@@ -6232,10 +6558,24 @@ function createStreamOps(h) {
6232
6558
  }
6233
6559
  };
6234
6560
  }
6561
+ function countOpens(Fs) {
6562
+ const { open } = Fs;
6563
+ if (typeof open !== "function" || opening.has(Fs)) return;
6564
+ opening.set(Fs, 0);
6565
+ Fs.open = function(...args) {
6566
+ opening.set(Fs, (opening.get(Fs) ?? 0) + 1);
6567
+ try {
6568
+ return open.apply(this, args);
6569
+ } finally {
6570
+ opening.set(Fs, (opening.get(Fs) ?? 1) - 1);
6571
+ }
6572
+ };
6573
+ }
6235
6574
  function createLiveVfsPlugin(Fs) {
6236
6575
  const mounts = /* @__PURE__ */ new Set();
6237
6576
  const ops = {};
6238
6577
  const h = createHelpers(Fs, ops);
6578
+ countOpens(Fs);
6239
6579
  const nodeOps = createNodeOps(h);
6240
6580
  const streamOps = createStreamOps(h);
6241
6581
  ops.node = nodeOps;
@@ -6368,12 +6708,12 @@ function liveRoot(Fs, bridge) {
6368
6708
  };
6369
6709
  }
6370
6710
  function crosses(Fs, from, to) {
6371
- const parentOf = (path) => Fs.lookupPath?.(path, { parent: true }).node;
6711
+ const parentOf2 = (path) => Fs.lookupPath?.(path, { parent: true }).node;
6372
6712
  const name2 = from.replace(/\/+$/, "").split("/").pop() ?? "";
6373
6713
  try {
6374
- const fromDir = parentOf(from);
6714
+ const fromDir = parentOf2(from);
6375
6715
  const node = fromDir && Fs.lookupNode?.(fromDir, name2);
6376
- const dir = parentOf(to);
6716
+ const dir = parentOf2(to);
6377
6717
  return !!node && !!dir && !!node.live !== !!dir.live;
6378
6718
  } catch {
6379
6719
  return false;
@@ -6437,6 +6777,25 @@ function guardRenames(Fs) {
6437
6777
  function idOf2(value2) {
6438
6778
  return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
6439
6779
  }
6780
+ function chownHeld(Fs, node, s, uid, gid) {
6781
+ const bridge = node.mount.opts.bridge;
6782
+ const handle = s.handle;
6783
+ try {
6784
+ bridge.chown?.(liveNodePath(node), idOf2(uid), idOf2(gid), false, handle);
6785
+ } catch (err) {
6786
+ throw toErrno(Fs, err);
6787
+ }
6788
+ if (node.parent?.live) node.parent.live.listed = void 0;
6789
+ if (!s.orphan) {
6790
+ s.stat = void 0;
6791
+ return;
6792
+ }
6793
+ try {
6794
+ const st = bridge.keptStat?.(handle);
6795
+ if (st && s.stat) s.stat = { ...s.stat, uid: st.uid, gid: st.gid, mode: st.mode };
6796
+ } catch {
6797
+ }
6798
+ }
6440
6799
  function useLiveChown(Fs) {
6441
6800
  const chown = Fs.chown?.bind(Fs);
6442
6801
  if (!chown) return;
@@ -6455,8 +6814,10 @@ function useLiveChown(Fs) {
6455
6814
  if (!Fs.fchown || !getStreamChecked) return;
6456
6815
  Fs.fchown = (fd, uid, gid) => {
6457
6816
  const stream = getStreamChecked.call(Fs, fd);
6458
- const live = stream.node.live !== void 0;
6459
- const target = live || stream.path === void 0 ? stream.node : stream.path;
6817
+ const node = stream.node;
6818
+ const s = node.live;
6819
+ if (s?.handle !== void 0 && (!s.orphan || s.kept)) return chownHeld(Fs, node, s, uid, gid);
6820
+ const target = s !== void 0 || stream.path === void 0 ? stream.node : stream.path;
6460
6821
  Fs.chown(target, uid, gid);
6461
6822
  };
6462
6823
  }
@@ -6517,10 +6878,11 @@ function readingLinks(Fs) {
6517
6878
  }
6518
6879
  };
6519
6880
  }
6520
- 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;
6881
+ 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;
6521
6882
  var init_live_vfs_fs = __esm({
6522
6883
  "src/realm/live-vfs-fs.ts"() {
6523
6884
  "use strict";
6885
+ init_access();
6524
6886
  init_ranged();
6525
6887
  init_types();
6526
6888
  init_wasi_errno();
@@ -6539,6 +6901,7 @@ var init_live_vfs_fs = __esm({
6539
6901
  O_TRUNC = 512;
6540
6902
  O_PATH = 2097152;
6541
6903
  stale = (s) => !!s.orphan && !s.kept;
6904
+ opening = /* @__PURE__ */ new WeakMap();
6542
6905
  }
6543
6906
  });
6544
6907
 
@@ -6977,14 +7340,17 @@ function wasmMemory(instance, imports) {
6977
7340
  }
6978
7341
  return void 0;
6979
7342
  }
6980
- function fdOfPath(path, cwd) {
7343
+ function absoluteOf(path, cwd) {
6981
7344
  const parts = [];
6982
7345
  for (const part of `${path.startsWith("/") ? "" : cwd}/${path}`.split("/")) {
6983
7346
  if (part === "" || part === ".") continue;
6984
7347
  if (part === "..") parts.pop();
6985
7348
  else parts.push(part);
6986
7349
  }
6987
- const abs = `/${parts.join("/")}`;
7350
+ return `/${parts.join("/")}`;
7351
+ }
7352
+ function fdOfPath(path, cwd) {
7353
+ const abs = absoluteOf(path, cwd);
6988
7354
  const std = ["/dev/stdin", "/dev/stdout", "/dev/stderr"].indexOf(abs);
6989
7355
  if (std >= 0) return std;
6990
7356
  const m = /^\/(?:dev|proc\/self)\/fd\/(\d+)$/.exec(abs);
@@ -7056,6 +7422,18 @@ function useZeroDevices(Fs) {
7056
7422
  mkdev.call(Fs, path, CHAR_DEVICE, dev);
7057
7423
  }
7058
7424
  }
7425
+ function useDevRemoval(Fs) {
7426
+ const fs = Fs;
7427
+ for (const name2 of ["unlink", "rmdir"]) {
7428
+ const remove = fs[name2];
7429
+ if (typeof remove !== "function") continue;
7430
+ fs[name2] = (path) => {
7431
+ const refused2 = devRemoval(absoluteOf(path, Fs.cwd()), fs.sliccCred);
7432
+ if (refused2) throw new Fs.ErrnoError(wasiErrno(refused2));
7433
+ remove.call(Fs, path);
7434
+ };
7435
+ }
7436
+ }
7059
7437
  function linkStdio(Fs) {
7060
7438
  const { unlink, symlink } = Fs;
7061
7439
  if (!unlink || !symlink) return;
@@ -7271,6 +7649,7 @@ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC,
7271
7649
  var init_process_fds = __esm({
7272
7650
  "src/process/process-fds.ts"() {
7273
7651
  "use strict";
7652
+ init_dev_removal();
7274
7653
  init_loopback_names();
7275
7654
  init_live_vfs_fs();
7276
7655
  init_process_pty();
@@ -7949,7 +8328,7 @@ function procfsBridge(fs, tree) {
7949
8328
  }
7950
8329
  const { chown } = fs;
7951
8330
  if (chown) {
7952
- over.chown = (p, uid, gid, follow2) => readOnly2([[p, follow2 === true]], () => chown.call(fs, p, uid, gid, follow2));
8331
+ over.chown = (p, ...rest2) => readOnly2([[p, rest2[2] === true]], () => chown.call(fs, p, ...rest2));
7953
8332
  }
7954
8333
  return new Proxy(fs, {
7955
8334
  get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
@@ -8310,6 +8689,24 @@ function laneOf(lane) {
8310
8689
  }
8311
8690
  function syncOps(kernel, shared) {
8312
8691
  const { infos, handles, resolve } = shared;
8692
+ const tryDevSync = (abs) => {
8693
+ try {
8694
+ const resolved2 = physicalPath(
8695
+ {
8696
+ lstat(p) {
8697
+ return parseSyncFsStat(kernel.json({ op: "lstat", path: p })) ?? {};
8698
+ },
8699
+ readlink(p) {
8700
+ return String(kernel.json({ op: "readlink", path: p }));
8701
+ }
8702
+ },
8703
+ abs
8704
+ );
8705
+ return resolved2 !== abs && inDev(resolved2) ? resolved2 : void 0;
8706
+ } catch {
8707
+ return void 0;
8708
+ }
8709
+ };
8313
8710
  const info = (fd) => {
8314
8711
  const known = infos.get(fd);
8315
8712
  if (known) return known;
@@ -8342,10 +8739,17 @@ function syncOps(kernel, shared) {
8342
8739
  const statOf = (op, path) => {
8343
8740
  const abs = resolve(path);
8344
8741
  if (inDev(abs)) return devSync(kernel, devStat(abs, op === "stat"));
8345
- kernel.call({ op: "fd-path-flush", path: abs });
8346
- const s = parseSyncFsStat(kernel.json({ op, path: abs }));
8347
- if (!s) throw new JsCallError("EIO", op);
8348
- return s;
8742
+ try {
8743
+ kernel.call({ op: "fd-path-flush", path: abs });
8744
+ const s = parseSyncFsStat(kernel.json({ op, path: abs }));
8745
+ if (!s) throw new JsCallError("EIO", op);
8746
+ return s;
8747
+ } catch (err) {
8748
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
8749
+ const devPath = tryDevSync(abs);
8750
+ if (!devPath) throw err;
8751
+ return devSync(kernel, devStat(devPath, op === "stat"));
8752
+ }
8349
8753
  };
8350
8754
  const openDev2 = (abs, options) => {
8351
8755
  const { fd, file, ...access } = devSync(kernel, devOpen(abs, options));
@@ -8365,27 +8769,34 @@ function syncOps(kernel, shared) {
8365
8769
  const open = (path, options = {}) => {
8366
8770
  const abs = resolve(path);
8367
8771
  if (inDev(abs)) return openDev2(abs, options);
8368
- let existing;
8369
8772
  try {
8370
- existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
8371
- } catch (err) {
8372
- existing = absent(err);
8373
- }
8374
- checkOpen(abs, options, existing);
8375
- const fd = kernel.json(openRequest(abs, options));
8376
- try {
8377
- kernel.call({ op: "fd-vfs-stat", fd });
8773
+ let existing;
8774
+ try {
8775
+ existing = statOf(isExclusive(options) ? "lstat" : "stat", abs);
8776
+ } catch (err) {
8777
+ existing = absent(err);
8778
+ }
8779
+ checkOpen(abs, options, existing);
8780
+ const fd = kernel.json(openRequest(abs, options));
8781
+ try {
8782
+ kernel.call({ op: "fd-vfs-stat", fd });
8783
+ } catch (err) {
8784
+ kernel.raw({ op: "fd-close", fd });
8785
+ throw err;
8786
+ }
8787
+ infos.set(fd, { kind: "file" });
8788
+ const handle = syncFile(kernel, fd, abs, options.append === true, () => {
8789
+ infos.delete(fd);
8790
+ handles.delete(fd);
8791
+ });
8792
+ handles.set(fd, handle.invalidate);
8793
+ return handle.file;
8378
8794
  } catch (err) {
8379
- kernel.raw({ op: "fd-close", fd });
8380
- throw err;
8795
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
8796
+ const devPath = tryDevSync(abs);
8797
+ if (!devPath) throw err;
8798
+ return openDev2(devPath, options);
8381
8799
  }
8382
- infos.set(fd, { kind: "file" });
8383
- const handle = syncFile(kernel, fd, abs, options.append === true, () => {
8384
- infos.delete(fd);
8385
- handles.delete(fd);
8386
- });
8387
- handles.set(fd, handle.invalidate);
8388
- return handle.file;
8389
8800
  };
8390
8801
  return {
8391
8802
  read: read2,
@@ -8397,7 +8808,7 @@ function syncOps(kernel, shared) {
8397
8808
  kernel.call({ op: "fd-close", fd });
8398
8809
  },
8399
8810
  open: procOpenSync(open, kernel, { resolve, pid: shared.pid }),
8400
- fs: procFsSync(syncPathOps(kernel, resolve, statOf, open), kernel, {
8811
+ fs: procFsSync(syncPathOps(kernel, resolve, statOf, open, tryDevSync), kernel, {
8401
8812
  resolve,
8402
8813
  pid: shared.pid
8403
8814
  })
@@ -8467,14 +8878,16 @@ function syncFile(kernel, fd, path, append, forget) {
8467
8878
  }
8468
8879
  };
8469
8880
  }
8470
- function syncPathOps(kernel, resolve, statOf, open) {
8881
+ function syncPathOps(kernel, resolve, statOf, open, tryDev) {
8471
8882
  return {
8472
8883
  stat: (path) => statOf("stat", path),
8473
8884
  lstat: (path) => statOf("lstat", path),
8474
8885
  exists(path) {
8475
8886
  const abs = resolve(path);
8476
8887
  if (inDev(abs)) return devSync(kernel, devExists(abs));
8477
- return kernel.json({ op: "exists", path: abs }) === true;
8888
+ if (kernel.json({ op: "exists", path: abs }) === true) return true;
8889
+ const devPath = tryDev(abs);
8890
+ return devPath ? devSync(kernel, devExists(devPath)) : false;
8478
8891
  },
8479
8892
  readdir(path) {
8480
8893
  const abs = resolve(path);
@@ -8484,7 +8897,8 @@ function syncPathOps(kernel, resolve, statOf, open) {
8484
8897
  mkdir: (path, options) => void kernel.call({
8485
8898
  op: "mkdir",
8486
8899
  path: resolve(path),
8487
- ...options?.recursive === false ? { exclusive: true } : {}
8900
+ ...options?.recursive === false ? { exclusive: true } : {},
8901
+ mode: options?.mode === void 0 ? 511 : modeOf(options.mode)
8488
8902
  }),
8489
8903
  rm: (path) => void kernel.call({ op: "rm", path: resolve(path) }),
8490
8904
  unlink: (path) => void kernel.call({ op: "unlink", path: resolve(path) }),
@@ -8498,18 +8912,38 @@ function syncPathOps(kernel, resolve, statOf, open) {
8498
8912
  return String(kernel.json({ op: "readlink", path: abs }));
8499
8913
  },
8500
8914
  statfs(path) {
8501
- const abs = resolve(path);
8915
+ let abs = resolve(path);
8916
+ if (inDev(abs)) {
8917
+ try {
8918
+ const target = devSync(kernel, devResolveTarget(abs));
8919
+ if (target?.startsWith("/")) abs = target;
8920
+ } catch {
8921
+ }
8922
+ }
8502
8923
  statOf("stat", abs);
8503
8924
  return statFsOf(kernel.json({ op: "statfs", path: abs }));
8504
8925
  },
8505
8926
  readFile(path) {
8506
8927
  const abs = resolve(path);
8507
8928
  if (inDev(abs)) return readWholeSync(open(abs));
8508
- kernel.call({ op: "fd-path-flush", path: abs });
8509
- return kernel.bytes({ op: "read", path: abs });
8510
- },
8511
- writeFile(path, data) {
8512
- const file = open(path, { write: true, create: true, truncate: true });
8929
+ try {
8930
+ kernel.call({ op: "fd-path-flush", path: abs });
8931
+ return kernel.bytes({ op: "read", path: abs });
8932
+ } catch (err) {
8933
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
8934
+ const devPath = tryDev(abs);
8935
+ if (!devPath) throw err;
8936
+ return readWholeSync(open(devPath));
8937
+ }
8938
+ },
8939
+ writeFile(path, data, options) {
8940
+ const mode = options?.mode;
8941
+ const file = open(path, {
8942
+ write: true,
8943
+ create: true,
8944
+ truncate: true,
8945
+ ...mode !== void 0 ? { mode } : {}
8946
+ });
8513
8947
  try {
8514
8948
  file.write(0, typeof data === "string" ? encoder3.encode(data) : data);
8515
8949
  } finally {
@@ -8522,6 +8956,7 @@ var encoder3, noLane, JsSyncKernel;
8522
8956
  var init_js_sync = __esm({
8523
8957
  "src/process/js/js-sync.ts"() {
8524
8958
  "use strict";
8959
+ init_physical_path();
8525
8960
  init_signals();
8526
8961
  init_sync_fs_wire();
8527
8962
  init_sync_sab_bridge();
@@ -8918,6 +9353,55 @@ function readable2(read2) {
8918
9353
  { highWaterMark: 0 }
8919
9354
  );
8920
9355
  }
9356
+ async function resolveDevAsync(kernel, abs) {
9357
+ try {
9358
+ const resolved2 = await physicalPathAsync(
9359
+ {
9360
+ async lstat(p) {
9361
+ return parseSyncFsStat(await kernel.json({ op: "lstat", path: p })) ?? {};
9362
+ },
9363
+ async readlink(p) {
9364
+ return String(await kernel.json({ op: "readlink", path: p }));
9365
+ }
9366
+ },
9367
+ abs
9368
+ );
9369
+ return resolved2 !== abs && inDev(resolved2) ? resolved2 : void 0;
9370
+ } catch {
9371
+ return void 0;
9372
+ }
9373
+ }
9374
+ async function vfsStat(kernel, abs, op, tryDev) {
9375
+ try {
9376
+ await kernel.call({ op: "fd-path-flush", path: abs });
9377
+ const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
9378
+ if (!s) throw new JsCallError("EIO", op);
9379
+ return s;
9380
+ } catch (err) {
9381
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
9382
+ const devPath = await tryDev(abs);
9383
+ if (!devPath) throw err;
9384
+ return devAsync(kernel, devStat(devPath, op === "stat"));
9385
+ }
9386
+ }
9387
+ async function vfsOpen(kernel, abs, options, statOf, infos, handles) {
9388
+ const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
9389
+ checkOpen(abs, options, existing);
9390
+ const fd = await kernel.json(openRequest(abs, options));
9391
+ try {
9392
+ await kernel.call({ op: "fd-vfs-stat", fd });
9393
+ } catch (err) {
9394
+ await kernel.raw({ op: "fd-close", fd });
9395
+ throw err;
9396
+ }
9397
+ infos.set(fd, { kind: "file" });
9398
+ const handle = fileHandle(kernel, fd, abs, options.append === true, () => {
9399
+ infos.delete(fd);
9400
+ handles.delete(fd);
9401
+ });
9402
+ handles.set(fd, handle.invalidate);
9403
+ return handle.file;
9404
+ }
8921
9405
  function createContext(o) {
8922
9406
  const { kernel } = o;
8923
9407
  const infos = /* @__PURE__ */ new Map();
@@ -8925,6 +9409,7 @@ function createContext(o) {
8925
9409
  const pending = /* @__PURE__ */ new Set();
8926
9410
  const random = o.random ?? ((bytes) => void crypto.getRandomValues(bytes));
8927
9411
  const resolve = (path) => resolvePath(o.cwd, path);
9412
+ const tryDev = (abs) => resolveDevAsync(kernel, abs);
8928
9413
  let exiting;
8929
9414
  const exit = (code2 = 0) => {
8930
9415
  exiting ??= code2;
@@ -8967,32 +9452,25 @@ function createContext(o) {
8967
9452
  const statOf = async (op, path) => {
8968
9453
  const abs = resolve(path);
8969
9454
  if (inDev(abs)) return devAsync(kernel, devStat(abs, op === "stat"));
8970
- await kernel.call({ op: "fd-path-flush", path: abs });
8971
- const s = parseSyncFsStat(await kernel.json({ op, path: abs }));
8972
- if (!s) throw new JsCallError("EIO", op);
8973
- return s;
9455
+ return vfsStat(kernel, abs, op, tryDev);
8974
9456
  };
9457
+ const devIo = { infos, handles, read: read2, write: writeAll };
8975
9458
  const open = async (path, options = {}) => {
8976
9459
  const abs = resolve(path);
8977
- if (inDev(abs)) return openDev(kernel, abs, options, { infos, handles, read: read2, write: writeAll });
8978
- const existing = await statOf(isExclusive(options) ? "lstat" : "stat", abs).catch(absent);
8979
- checkOpen(abs, options, existing);
8980
- const fd = await kernel.json(openRequest(abs, options));
9460
+ if (inDev(abs)) return openDev(kernel, abs, options, devIo);
8981
9461
  try {
8982
- await kernel.call({ op: "fd-vfs-stat", fd });
9462
+ return await vfsOpen(kernel, abs, options, statOf, infos, handles);
8983
9463
  } catch (err) {
8984
- await kernel.raw({ op: "fd-close", fd });
8985
- throw err;
9464
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
9465
+ const devPath = await tryDev(abs);
9466
+ if (!devPath) throw err;
9467
+ return openDev(kernel, devPath, options, devIo);
8986
9468
  }
8987
- infos.set(fd, { kind: "file" });
8988
- const handle = fileHandle(kernel, fd, abs, options.append === true, () => {
8989
- infos.delete(fd);
8990
- handles.delete(fd);
8991
- });
8992
- handles.set(fd, handle.invalidate);
8993
- return handle.file;
8994
9469
  };
8995
- const fs = procFsAsync(pathOps(kernel, resolve, statOf, open), kernel, { resolve, pid: o.pid });
9470
+ const fs = procFsAsync(pathOps(kernel, resolve, statOf, open, tryDev), kernel, {
9471
+ resolve,
9472
+ pid: o.pid
9473
+ });
8996
9474
  const lane = o.lane ?? laneOf(void 0);
8997
9475
  if (o.lane && o.lane !== noLane) kernel.syncLane = o.lane;
8998
9476
  const syncKernel = new JsSyncKernel(lane, kernel, unwind);
@@ -9008,6 +9486,7 @@ function createContext(o) {
9008
9486
  },
9009
9487
  kill: killer({ self: o.pid, kernel, syncKernel, lane, writes, modes: terminal.modes }),
9010
9488
  cred: () => syncKernel.json({ op: "proc-cred" }),
9489
+ umask: (mask) => syncKernel.json(umaskRequest(mask)),
9011
9490
  setcred(change) {
9012
9491
  if (typeof change !== "object" || change === null || Array.isArray(change)) {
9013
9492
  throw new JsCallError("EINVAL", "setcred");
@@ -9054,6 +9533,7 @@ function createContext(o) {
9054
9533
  },
9055
9534
  sync,
9056
9535
  fetch: fetchOp(kernel),
9536
+ umask: async (mask) => await kernel.json(umaskRequest(mask)),
9057
9537
  sudo: async (args) => await kernel.json({
9058
9538
  op: "proc-sudo",
9059
9539
  args: [...args],
@@ -9186,14 +9666,16 @@ async function sendSome(kernel, fd, body, signal) {
9186
9666
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
9187
9667
  }
9188
9668
  }
9189
- function pathOps(kernel, resolve, statOf, open) {
9669
+ function pathOps(kernel, resolve, statOf, open, tryDev) {
9190
9670
  return {
9191
9671
  stat: (path) => statOf("stat", path),
9192
9672
  lstat: (path) => statOf("lstat", path),
9193
9673
  async exists(path) {
9194
9674
  const abs = resolve(path);
9195
9675
  if (inDev(abs)) return devAsync(kernel, devExists(abs));
9196
- return await kernel.json({ op: "exists", path: abs }) === true;
9676
+ if (await kernel.json({ op: "exists", path: abs }) === true) return true;
9677
+ const devPath = await tryDev(abs);
9678
+ return devPath ? devAsync(kernel, devExists(devPath)) : false;
9197
9679
  },
9198
9680
  async readdir(path) {
9199
9681
  const abs = resolve(path);
@@ -9203,7 +9685,8 @@ function pathOps(kernel, resolve, statOf, open) {
9203
9685
  mkdir: async (path, options) => void await kernel.call({
9204
9686
  op: "mkdir",
9205
9687
  path: resolve(path),
9206
- ...options?.recursive === false ? { exclusive: true } : {}
9688
+ ...options?.recursive === false ? { exclusive: true } : {},
9689
+ mode: options?.mode === void 0 ? 511 : modeOf(options.mode)
9207
9690
  }),
9208
9691
  rm: async (path) => void await kernel.call({ op: "rm", path: resolve(path) }),
9209
9692
  unlink: async (path) => void await kernel.call({ op: "unlink", path: resolve(path) }),
@@ -9217,18 +9700,35 @@ function pathOps(kernel, resolve, statOf, open) {
9217
9700
  return String(await kernel.json({ op: "readlink", path: abs }));
9218
9701
  },
9219
9702
  async statfs(path) {
9220
- const abs = resolve(path);
9703
+ let abs = resolve(path);
9704
+ if (inDev(abs)) {
9705
+ const target = await devAsync(kernel, devResolveTarget(abs)).catch(() => void 0);
9706
+ if (target?.startsWith("/")) abs = target;
9707
+ }
9221
9708
  await statOf("stat", abs);
9222
9709
  return statFsOf(await kernel.json({ op: "statfs", path: abs }));
9223
9710
  },
9224
9711
  async readFile(path) {
9225
9712
  const abs = resolve(path);
9226
9713
  if (inDev(abs)) return readWhole(await open(abs));
9227
- await kernel.call({ op: "fd-path-flush", path: abs });
9228
- return kernel.bytes({ op: "read", path: abs });
9229
- },
9230
- async writeFile(path, data) {
9231
- const file = await open(path, { write: true, create: true, truncate: true });
9714
+ try {
9715
+ await kernel.call({ op: "fd-path-flush", path: abs });
9716
+ return await kernel.bytes({ op: "read", path: abs });
9717
+ } catch (err) {
9718
+ if (!(err instanceof JsCallError) || err.code !== "ENOENT") throw err;
9719
+ const devPath = await tryDev(abs);
9720
+ if (!devPath) throw err;
9721
+ return readWhole(await open(devPath));
9722
+ }
9723
+ },
9724
+ async writeFile(path, data, options) {
9725
+ const mode = options?.mode;
9726
+ const file = await open(path, {
9727
+ write: true,
9728
+ create: true,
9729
+ truncate: true,
9730
+ ...mode !== void 0 ? { mode } : {}
9731
+ });
9232
9732
  try {
9233
9733
  await file.write(0, typeof data === "string" ? encoder4.encode(data) : data);
9234
9734
  } finally {
@@ -9241,6 +9741,7 @@ var KERNEL_INFO, JsExit, encoder4;
9241
9741
  var init_js_context = __esm({
9242
9742
  "src/process/js/js-context.ts"() {
9243
9743
  "use strict";
9744
+ init_physical_path();
9244
9745
  init_signals();
9245
9746
  init_sync_fs_wire();
9246
9747
  init_version();
@@ -9411,6 +9912,22 @@ function topLevelDirs(bridge, warn) {
9411
9912
  }
9412
9913
  return dirs;
9413
9914
  }
9915
+ function linuxRmdir(Fs) {
9916
+ const raw = Fs;
9917
+ const { mayDelete, lookupNode } = raw;
9918
+ if (!mayDelete || !lookupNode) return;
9919
+ raw.mayDelete = (dir, name2, isdir) => {
9920
+ const code2 = mayDelete.call(raw, dir, name2, isdir);
9921
+ if (code2 !== 10 || !isdir) return code2;
9922
+ try {
9923
+ const node = lookupNode.call(raw, dir, name2);
9924
+ if (node === node.parent) return 10;
9925
+ } catch {
9926
+ return code2;
9927
+ }
9928
+ return 0;
9929
+ };
9930
+ }
9414
9931
  function mountVfsIntoEmscripten(Fs, deps) {
9415
9932
  const { bridge, warn } = deps;
9416
9933
  const dirs = topLevelDirs(bridge, warn);
@@ -9418,6 +9935,8 @@ function mountVfsIntoEmscripten(Fs, deps) {
9418
9935
  if (dirs) liveRoot(Fs, bridge);
9419
9936
  if (bridge.owners && Fs.lookupPath) useLiveChown(Fs);
9420
9937
  if (bridge.links && Fs.lookupPath) readingLinks(Fs);
9938
+ linuxRmdir(Fs);
9939
+ if (deps.cred) Fs.sliccCred = deps.cred;
9421
9940
  try {
9422
9941
  Fs.chdir(deps.cwd);
9423
9942
  } catch (err) {
@@ -9440,6 +9959,81 @@ var init_emscripten_vfs_hook = __esm({
9440
9959
  }
9441
9960
  });
9442
9961
 
9962
+ // src/process/fd-metadata.ts
9963
+ function idOf3(value2) {
9964
+ return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
9965
+ }
9966
+ function timeOf(value2) {
9967
+ return typeof value2 === "number" && Number.isFinite(value2) ? value2 : null;
9968
+ }
9969
+ function useKernelFdMetadata(Fs, sys, call2) {
9970
+ const { fdChown, fdChmod, fdUtimes } = sys;
9971
+ const meta = Fs;
9972
+ const kernelFd = (stream) => stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
9973
+ const find = (match) => {
9974
+ for (const s of Fs.streams) {
9975
+ const kfd = s && match(s) ? kernelFd(s) : void 0;
9976
+ if (kfd !== void 0) return kfd;
9977
+ }
9978
+ return void 0;
9979
+ };
9980
+ const ofPath = (path, follow2) => {
9981
+ if (typeof path !== "string") return find((s) => s.node === path);
9982
+ const fd = follow2 ? fdOfPath(path, Fs.cwd()) : void 0;
9983
+ if (fd !== void 0) return kernelFd(Fs.getStream(fd));
9984
+ return find((s) => s.path === path);
9985
+ };
9986
+ const ofFd = (fd) => kernelFd(Fs.getStream(fd));
9987
+ const chownBy = (kfd, uid, gid) => call2(() => fdChown?.call(sys, kfd, idOf3(uid), idOf3(gid)));
9988
+ if (fdChown && meta.chown) {
9989
+ const chown = meta.chown.bind(Fs);
9990
+ meta.chown = (path, uid, gid, dontFollow) => {
9991
+ const kfd = ofPath(path, !dontFollow);
9992
+ if (kfd === void 0) return chown(path, uid, gid, dontFollow);
9993
+ chownBy(kfd, uid, gid);
9994
+ };
9995
+ }
9996
+ if (fdChown && meta.fchown) {
9997
+ const fchown = meta.fchown.bind(Fs);
9998
+ meta.fchown = (fd, uid, gid) => {
9999
+ const kfd = ofFd(fd);
10000
+ if (kfd === void 0) return fchown(fd, uid, gid);
10001
+ chownBy(kfd, uid, gid);
10002
+ };
10003
+ }
10004
+ if (fdChmod && meta.chmod) {
10005
+ const chmod = meta.chmod.bind(Fs);
10006
+ meta.chmod = (path, mode, dontFollow) => {
10007
+ const kfd = ofPath(path, !dontFollow);
10008
+ if (kfd === void 0) return chmod(path, mode, dontFollow);
10009
+ call2(() => fdChmod.call(sys, kfd, mode & 4095));
10010
+ };
10011
+ }
10012
+ if (fdChmod && meta.fchmod) {
10013
+ const fchmod = meta.fchmod.bind(Fs);
10014
+ meta.fchmod = (fd, mode) => {
10015
+ const kfd = ofFd(fd);
10016
+ if (kfd === void 0) return fchmod(fd, mode);
10017
+ call2(() => fdChmod.call(sys, kfd, mode & 4095));
10018
+ };
10019
+ }
10020
+ if (fdUtimes && meta.utime) {
10021
+ const utime = meta.utime.bind(Fs);
10022
+ meta.utime = (path, atime, mtime) => {
10023
+ const kfd = ofPath(path, true);
10024
+ if (kfd === void 0) return utime(path, atime, mtime);
10025
+ const now = meta.sliccTouch === true;
10026
+ call2(() => fdUtimes.call(sys, kfd, timeOf(atime), timeOf(mtime), now));
10027
+ };
10028
+ }
10029
+ }
10030
+ var init_fd_metadata = __esm({
10031
+ "src/process/fd-metadata.ts"() {
10032
+ "use strict";
10033
+ init_process_fds();
10034
+ }
10035
+ });
10036
+
9443
10037
  // src/process/kernel-streams.ts
9444
10038
  function isPtyPath(path) {
9445
10039
  return PTY_PATH.test(path);
@@ -9467,7 +10061,7 @@ function sealedStat(minor = 250) {
9467
10061
  const now = /* @__PURE__ */ new Date();
9468
10062
  return {
9469
10063
  dev: 22,
9470
- ino: 1,
10064
+ ino: minor === 251 ? 2 : 1,
9471
10065
  mode: 8630,
9472
10066
  nlink: 1,
9473
10067
  uid: 0,
@@ -9484,10 +10078,18 @@ function sealedStat(minor = 250) {
9484
10078
  function nonblocking(stream) {
9485
10079
  return (stream.flags & O_NONBLOCK2) !== 0 ? { nonblock: true } : void 0;
9486
10080
  }
9487
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH2, STRERROR, CLIPBOARD_PATH2, O_CREAT2, O_EXCL, O_NOCTTY, O_TRUNC2, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
10081
+ function datesOf(real) {
10082
+ const dates = {};
10083
+ for (const [key, value2] of Object.entries(real ?? {}))
10084
+ if (/^[amc]time$/.test(key) && (typeof value2 === "string" || typeof value2 === "number"))
10085
+ dates[key] = new Date(value2);
10086
+ return dates;
10087
+ }
10088
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, TCSETSF, O_NONBLOCK2, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, SEALED_PATH2, STRERROR, CLIPBOARD_PATH2, O_CREAT2, O_EXCL, O_NOCTTY, O_TRUNC2, O_DIRECTORY, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
9488
10089
  var init_kernel_streams = __esm({
9489
10090
  "src/process/kernel-streams.ts"() {
9490
10091
  "use strict";
10092
+ init_fd_metadata();
9491
10093
  init_wasi_errno();
9492
10094
  POLLIN = 1;
9493
10095
  POLLOUT = 4;
@@ -9516,6 +10118,7 @@ var init_kernel_streams = __esm({
9516
10118
  O_EXCL = 128;
9517
10119
  O_NOCTTY = 256;
9518
10120
  O_TRUNC2 = 512;
10121
+ O_DIRECTORY = 65536;
9519
10122
  KILLED_BY_SIGPIPE = 128 + 13;
9520
10123
  ProcessExit = class extends Error {
9521
10124
  status;
@@ -9736,13 +10339,15 @@ var init_kernel_streams = __esm({
9736
10339
  };
9737
10340
  }
9738
10341
  sizeFromKernel(stream, kfd) {
9739
- const { size } = this.sys;
10342
+ const { size, fdStat: fdStat2 } = this.sys;
9740
10343
  if (!size) return;
9741
10344
  const node = stream.node;
9742
- this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => ({
9743
- ...node.node_ops?.getattr?.(node),
9744
- size: this.call(() => size.call(this.sys, kfd))
9745
- }));
10345
+ this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => {
10346
+ const base = node.node_ops?.getattr?.(node);
10347
+ const live = this.call(() => size.call(this.sys, kfd));
10348
+ const real = fdStat2 && this.call(() => fdStat2.call(this.sys, kfd));
10349
+ return { ...base, ...real, ...datesOf(real), size: live };
10350
+ });
9746
10351
  }
9747
10352
  describe(stream, name2, getattr) {
9748
10353
  if (this.descriptions.size === 0) this.useDescriptions();
@@ -9761,6 +10366,9 @@ var init_kernel_streams = __esm({
9761
10366
  };
9762
10367
  }
9763
10368
  }
10369
+ useKernelFdMetadata() {
10370
+ useKernelFdMetadata(this.Fs, this.sys, this.call.bind(this));
10371
+ }
9764
10372
  useControllingTerminal() {
9765
10373
  if (typeof this.Fs.open !== "function") return;
9766
10374
  this.usePtyPaths();
@@ -9841,10 +10449,17 @@ var init_kernel_streams = __esm({
9841
10449
  openClipboard(open, path, flags, mode) {
9842
10450
  const { openClipboard } = this.sys;
9843
10451
  if (path !== CLIPBOARD_PATH2 || !openClipboard) return void 0;
10452
+ if (flags & O_DIRECTORY) throw new this.Fs.ErrnoError(wasiErrno("ENOTDIR"));
9844
10453
  const kfd = this.call(() => openClipboard.call(this.sys, flags & 3));
9845
- const stream = this.vessel(open, kfd, { path, flags, mode }, false);
9846
- this.reportClose(kfd);
9847
- return stream;
10454
+ try {
10455
+ const stream = this.vessel(open, kfd, { path, flags, mode }, false);
10456
+ this.reportClose(kfd);
10457
+ return stream;
10458
+ } catch (e) {
10459
+ this.sys.clipboardAbort?.(kfd);
10460
+ this.sys.close(kfd);
10461
+ throw e;
10462
+ }
9848
10463
  }
9849
10464
  vessel(open, kfd, at, terminal) {
9850
10465
  let stream;
@@ -10094,7 +10709,8 @@ function kernelEntry2(stream, kernel) {
10094
10709
  }
10095
10710
  const device2 = stream.path === void 0 ? void 0 : NAMED_DEVICES[stream.path];
10096
10711
  const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : device2 ?? "stream";
10097
- return { fd: stream.fd, kernel, kind, ...cloexec };
10712
+ const access = kind === "tty" ? O_RDWR4 : (stream.flags ?? O_RDWR4) & O_ACCMODE3;
10713
+ return { fd: stream.fd, kernel, kind, flags: access, ...cloexec };
10098
10714
  }
10099
10715
  function describeInherited(Fs, sys, streams, livePath, actions = []) {
10100
10716
  const table = /* @__PURE__ */ new Map();
@@ -10141,12 +10757,13 @@ function place(Fs, stream, fd) {
10141
10757
  return moved;
10142
10758
  }
10143
10759
  function placeholder(Fs, streams, entry) {
10144
- if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR4);
10760
+ const access = entry.flags ?? O_RDWR4;
10761
+ if (entry.kind === "socket") return streams.socketStream(access);
10145
10762
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR4);
10146
10763
  if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
10147
- return Fs.open("/dev/null", O_RDWR4);
10764
+ return Fs.open("/dev/null", access);
10148
10765
  Fs.mkdirTree(PLACEHOLDER_DIR);
10149
- return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, O_RDWR4 | O_CREAT3);
10766
+ return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, access | O_CREAT3);
10150
10767
  }
10151
10768
  function asFifo(stream, streams, identity) {
10152
10769
  const inos = streamInos.get(streams) ?? /* @__PURE__ */ new Map();
@@ -10931,6 +11548,20 @@ function kernelSys(transport) {
10931
11548
  size(fd) {
10932
11549
  return json2(call2({ op: "fd-vfs-stat", fd }, `fd-vfs-stat ${fd}`)).size;
10933
11550
  },
11551
+ fdStat(fd) {
11552
+ const r = json2(call2({ op: "fd-vfs-stat", fd, full: true }, `fd-vfs-stat ${fd}`));
11553
+ return r?.stat;
11554
+ },
11555
+ fdChmod(fd, mode) {
11556
+ call2({ op: "fd-chmod", fd, mode }, `fd-chmod ${fd}`);
11557
+ },
11558
+ fdChown(fd, uid, gid) {
11559
+ const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
11560
+ call2({ op: "fd-chown", fd, ...ids }, `fd-chown ${fd}`);
11561
+ },
11562
+ fdUtimes(fd, atimeMs, mtimeMs, now) {
11563
+ call2({ op: "fd-utimes", fd, atimeMs, mtimeMs, now }, `fd-utimes ${fd}`);
11564
+ },
10934
11565
  ttyNames() {
10935
11566
  return json2(call2({ op: "fd-tty-names" }, "fd-tty-names"));
10936
11567
  },
@@ -10962,6 +11593,9 @@ function kernelSys(transport) {
10962
11593
  openClipboard(flags) {
10963
11594
  return json2(call2({ op: "fd-open-clipboard", flags }, "fd-open-clipboard"));
10964
11595
  },
11596
+ clipboardAbort(fd) {
11597
+ call2({ op: "fd-clipboard-abort", fd }, "fd-clipboard-abort");
11598
+ },
10965
11599
  ptyNumbers() {
10966
11600
  return json2(call2({ op: "pty-list" }, "pty-list"));
10967
11601
  },
@@ -11000,7 +11634,7 @@ function openDevice(Fs, fd, meta) {
11000
11634
  return openAt(Fs, fd, `/dev/${meta.device}`, accessMode(meta.access));
11001
11635
  }
11002
11636
  function openHeld(Fs, fd, meta) {
11003
- return "dir" in meta ? openAt(Fs, fd, meta.dir, O_RDONLY | O_DIRECTORY) : openDevice(Fs, fd, meta);
11637
+ return "dir" in meta ? openAt(Fs, fd, meta.dir, O_RDONLY | O_DIRECTORY2) : openDevice(Fs, fd, meta);
11004
11638
  }
11005
11639
  function openAt(Fs, fd, path, flags) {
11006
11640
  let stream;
@@ -11112,6 +11746,17 @@ function kernelWrappers(imports, module, deps) {
11112
11746
  function bridgeFlags(init) {
11113
11747
  return { ...init.owners ? { owners: true } : {}, ...init.links ? { links: true } : {} };
11114
11748
  }
11749
+ function credSyncTransport(gated, early, cred) {
11750
+ return {
11751
+ call: (req, timeoutMs, label) => {
11752
+ if (!FS_OPS.has(req.op)) early();
11753
+ const r = gated.call(req, timeoutMs, label);
11754
+ if (cred && req.op === "proc-setcred" && r.ok && r.kind === "json")
11755
+ Object.assign(cred, r.json);
11756
+ return r;
11757
+ }
11758
+ };
11759
+ }
11115
11760
  async function runWasmProcess(init, port3, deps = {}) {
11116
11761
  const signals = new SignalGate(
11117
11762
  createSyncSabTransport(init.sab, port3, {
@@ -11130,12 +11775,7 @@ async function runWasmProcess(init, port3, deps = {}) {
11130
11775
  const gated = signals.transport();
11131
11776
  let early = () => {
11132
11777
  };
11133
- const transport = {
11134
- call: (req, timeoutMs, label) => {
11135
- if (!FS_OPS.has(req.op)) early();
11136
- return gated.call(req, timeoutMs, label);
11137
- }
11138
- };
11778
+ const transport = credSyncTransport(gated, () => early(), init.cred);
11139
11779
  const sys = kernelSys(transport);
11140
11780
  const encoder5 = new TextEncoder();
11141
11781
  const say = (fd) => (text) => sys.write(fd, encoder5.encode(`${text}
@@ -11218,7 +11858,8 @@ async function runWasmProcess(init, port3, deps = {}) {
11218
11858
  const vfs = mountVfsIntoEmscripten(running.FS, {
11219
11859
  bridge: createSyncFsSabBridge(transport, bridgeFlags(init)),
11220
11860
  cwd: init.cwd,
11221
- warn: deps.warn ?? say(2)
11861
+ warn: deps.warn ?? say(2),
11862
+ cred: init.owners ? init.cred : void 0
11222
11863
  });
11223
11864
  early = () => signals.quiet(() => vfs.flushDirty());
11224
11865
  const sigpipe = () => running.sliccSigpipe?.() === 1;
@@ -11237,6 +11878,7 @@ async function runWasmProcess(init, port3, deps = {}) {
11237
11878
  atExit = () => streams.exiting();
11238
11879
  useMounts(running.FS, init.env, true);
11239
11880
  useZeroDevices(running.FS);
11881
+ useDevRemoval(running.FS);
11240
11882
  useProcfs(running.FS, sys, init.pid);
11241
11883
  if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
11242
11884
  else {
@@ -11246,6 +11888,7 @@ async function runWasmProcess(init, port3, deps = {}) {
11246
11888
  const pipefs = ownValue(running, "PIPEFS");
11247
11889
  if (pipefs) streams.usePipes(pipefs);
11248
11890
  streams.useControllingTerminal();
11891
+ streams.useKernelFdMetadata();
11249
11892
  useDevFd(running.FS);
11250
11893
  useFileMmap(running.FS, {
11251
11894
  sys,
@@ -11257,9 +11900,9 @@ async function runWasmProcess(init, port3, deps = {}) {
11257
11900
  transport,
11258
11901
  Fs: running.FS,
11259
11902
  env: init.env,
11903
+ pid: init.pid,
11260
11904
  beforeSpawn: () => vfs.flush(),
11261
11905
  afterChild: () => vfs.invalidate(),
11262
- pid: init.pid,
11263
11906
  raise: (sig) => running.sliccRaise?.(sig),
11264
11907
  restartable,
11265
11908
  memory: () => memory,
@@ -11279,6 +11922,9 @@ async function runWasmProcess(init, port3, deps = {}) {
11279
11922
  sigpipe,
11280
11923
  restartable
11281
11924
  });
11925
+ return runWithFlush(running, init, streams, vfs);
11926
+ }
11927
+ function runWithFlush(running, init, streams, vfs) {
11282
11928
  try {
11283
11929
  return streams.exitStatus(runMain(running, init));
11284
11930
  } finally {
@@ -11343,7 +11989,7 @@ function runMain(running, init) {
11343
11989
  return status2;
11344
11990
  }
11345
11991
  }
11346
- var FS_OPS, O_RDONLY, O_WRONLY6, O_RDWR6, O_ACCMODE4, O_DIRECTORY, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
11992
+ var FS_OPS, O_RDONLY, O_WRONLY6, O_RDWR6, O_ACCMODE4, O_DIRECTORY2, accessMode, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
11347
11993
  var init_process_runtime = __esm({
11348
11994
  "src/process/process-runtime.ts"() {
11349
11995
  "use strict";
@@ -11369,7 +12015,7 @@ var init_process_runtime = __esm({
11369
12015
  O_WRONLY6 = 1;
11370
12016
  O_RDWR6 = 2;
11371
12017
  O_ACCMODE4 = 3;
11372
- O_DIRECTORY = 65536;
12018
+ O_DIRECTORY2 = 65536;
11373
12019
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY6 : O_RDWR6;
11374
12020
  PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard", "sealed"]);
11375
12021
  GLUE_TRAILER = [
@@ -11550,7 +12196,7 @@ var init_wasi_sigmask = __esm({
11550
12196
  };
11551
12197
  WasiSigmask = class {
11552
12198
  lo;
11553
- hi = 0;
12199
+ hi;
11554
12200
  header;
11555
12201
  deliver;
11556
12202
  process;
@@ -11559,9 +12205,10 @@ var init_wasi_sigmask = __esm({
11559
12205
  this.deliver = deliver;
11560
12206
  this.process = process;
11561
12207
  this.lo = libcBits(Atomics.load(header, SAB_I_BLOCKED));
12208
+ this.hi = Atomics.load(header, SAB_I_BLOCKED_HI);
11562
12209
  }
11563
12210
  static unsupported(header) {
11564
- Atomics.store(header, SAB_I_BLOCKED, 0);
12211
+ storeBlocked(header, [0, 0]);
11565
12212
  }
11566
12213
  set(how, setLo, setHi, old) {
11567
12214
  if (how !== SIG_BLOCK && how !== SIG_UNBLOCK && how !== SIG_SETMASK) return E.INVAL;
@@ -11569,7 +12216,7 @@ var init_wasi_sigmask = __esm({
11569
12216
  this.lo = apply(how, this.lo, setLo | 0) & ~LIBC_UNBLOCKABLE;
11570
12217
  this.hi = apply(how, this.hi, setHi | 0);
11571
12218
  const now = kernelBits(this.lo);
11572
- Atomics.store(this.header, SAB_I_BLOCKED, now);
12219
+ storeBlocked(this.header, [now, this.hi]);
11573
12220
  if ((Atomics.load(this.header, SAB_I_SIGNALS) & ~now) !== 0) this.deliver();
11574
12221
  return E.SUCCESS;
11575
12222
  }
@@ -11577,7 +12224,7 @@ var init_wasi_sigmask = __esm({
11577
12224
  const old = [this.lo, this.hi];
11578
12225
  this.lo = setLo & ~LIBC_UNBLOCKABLE;
11579
12226
  this.hi = setHi | 0;
11580
- Atomics.store(this.header, SAB_I_BLOCKED, kernelBits(this.lo));
12227
+ storeBlocked(this.header, [kernelBits(this.lo), this.hi]);
11581
12228
  return old;
11582
12229
  }
11583
12230
  deliverUnblocked() {
@@ -11590,6 +12237,9 @@ var init_wasi_sigmask = __esm({
11590
12237
  this.set(SIG_SETMASK, lo, hi, () => {
11591
12238
  });
11592
12239
  }
12240
+ inherited() {
12241
+ return [kernelBits(this.lo), this.hi];
12242
+ }
11593
12243
  discard(sig) {
11594
12244
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
11595
12245
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
@@ -12869,7 +13519,7 @@ function readAddr(view, ptr) {
12869
13519
  function ipv6Host(bytes) {
12870
13520
  const zeros = (n) => bytes.subarray(0, n).every((b) => b === 0);
12871
13521
  if (zeros(16)) return "0.0.0.0";
12872
- if (zeros(15) && bytes[15] === 1) return LOOPBACK;
13522
+ if (zeros(15) && bytes[15] === 1) return LOOPBACK2;
12873
13523
  if (zeros(10) && bytes[10] === 255 && bytes[11] === 255) return bytes.subarray(12).join(".");
12874
13524
  const groups = [0, 2, 4, 6, 8, 10, 12, 14].map(
12875
13525
  (i) => (bytes[i] << 8 | bytes[i + 1]).toString(16)
@@ -13026,7 +13676,7 @@ function wasixSocketImports(host, preview1) {
13026
13676
  }
13027
13677
  };
13028
13678
  }
13029
- var INET4, INET6, UNIX, STREAM, ADDR_IP_SIZE, LOOPBACK, OPTIONS;
13679
+ var INET4, INET6, UNIX, STREAM, ADDR_IP_SIZE, LOOPBACK2, OPTIONS;
13030
13680
  var init_wasix_sockets = __esm({
13031
13681
  "src/process/wasi/wasix-sockets.ts"() {
13032
13682
  "use strict";
@@ -13038,7 +13688,7 @@ var init_wasix_sockets = __esm({
13038
13688
  UNIX = 3;
13039
13689
  STREAM = 1;
13040
13690
  ADDR_IP_SIZE = 18;
13041
- LOOPBACK = "127.0.0.1";
13691
+ LOOPBACK2 = "127.0.0.1";
13042
13692
  OPTIONS = {
13043
13693
  1: [1, 15],
13044
13694
  2: [1, 2],
@@ -13567,6 +14217,7 @@ __export(wasi_runtime_exports, {
13567
14217
  runWasiProcess: () => runWasiProcess,
13568
14218
  runWasiThread: () => runWasiThread,
13569
14219
  sigmaskOf: () => sigmaskOf,
14220
+ takeThreadDefault: () => takeThreadDefault,
13570
14221
  trapMessage: () => trapMessage,
13571
14222
  unsupportedImport: () => unsupportedImport,
13572
14223
  wireSignals: () => wireSignals
@@ -13610,7 +14261,7 @@ function sigmaskOf(module, sab, gate, threads, process) {
13610
14261
  WasiSigmask.unsupported(header);
13611
14262
  return void 0;
13612
14263
  }
13613
- if (threads) threads.blocked = () => Atomics.load(header, SAB_I_BLOCKED);
14264
+ if (threads) threads.blocked = () => loadBlocked(header);
13614
14265
  const shared = process && new Int32Array(process, 0, SAB_HEADER_I32);
13615
14266
  return new WasiSigmask(header, () => gate.deliver(), shared);
13616
14267
  }
@@ -14004,7 +14655,7 @@ async function runWasiThread(init, port3) {
14004
14655
  masks: () => null,
14005
14656
  raise: (sig) => signals.raise(sig)
14006
14657
  });
14007
- const signals = new WasiSignals(takeDefault(call2, init.pid));
14658
+ const signals = new WasiSignals(takeThreadDefault(call2, init.pid));
14008
14659
  const threads = new WasiThreads(port3, thread.memory, threadCap(init.env), thread.tid, thread.ids);
14009
14660
  threads.received = thread.modules;
14010
14661
  const id = identify(transport, init);
@@ -14058,7 +14709,7 @@ async function runWasiThread(init, port3) {
14058
14709
  throw e;
14059
14710
  }
14060
14711
  }
14061
- 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;
14712
+ 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;
14062
14713
  var init_wasi_runtime = __esm({
14063
14714
  "src/process/wasi/wasi-runtime.ts"() {
14064
14715
  "use strict";
@@ -14093,6 +14744,17 @@ var init_wasi_runtime = __esm({
14093
14744
  call2({ op: "proc-kill", pid, sig });
14094
14745
  if (defaultAction(sig) === "terminate") throw new WasiExit(128 + sig);
14095
14746
  };
14747
+ takeThreadDefault = (call2, pid) => (sig) => {
14748
+ if (defaultAction(sig) !== "terminate") {
14749
+ call2({ op: "proc-kill", pid, sig });
14750
+ return;
14751
+ }
14752
+ try {
14753
+ call2({ op: "proc-kill-self", sig });
14754
+ } catch {
14755
+ }
14756
+ throw new WasiExit(128 + sig);
14757
+ };
14096
14758
  SLICC_FS = "slicc_fs";
14097
14759
  SLICC_TTY = "slicc_tty";
14098
14760
  RESERVED2 = RESERVED_NAMESPACES;
@@ -14238,7 +14900,11 @@ function refuseModules() {
14238
14900
  }
14239
14901
  });
14240
14902
  }
14903
+ var locked = /* @__PURE__ */ new WeakSet();
14904
+ var nodeProcess = typeof globalThis.process === "object" && globalThis.process !== null ? globalThis.process : void 0;
14241
14905
  function nodeLockdown(scope2 = globalThis) {
14906
+ if (locked.has(scope2)) return;
14907
+ locked.add(scope2);
14242
14908
  zeroedBuffers(Buffer);
14243
14909
  lockdown(scope2);
14244
14910
  hide(scope2, NODE_GLOBALS);
@@ -14304,14 +14970,22 @@ function processEntry(port3, run = runWasmProcess, wasi = loadWasi, js = loadJs,
14304
14970
  }
14305
14971
 
14306
14972
  // src/node-process-worker.ts
14973
+ init_wasi_runtime();
14307
14974
  var scope = globalThis;
14308
14975
  scope.require ??= createRequire(import.meta.url);
14309
14976
  scope.__filename ??= new URL(import.meta.url).pathname;
14310
14977
  scope.__dirname ??= new URL(".", import.meta.url).pathname;
14311
14978
  var port2 = parentPort;
14312
14979
  var post = { postMessage: (message2) => port2.postMessage(message2) };
14313
- var onMessage = processEntry(post, void 0, void 0, async () => ({
14314
- runJsProcess: (init, at) => runJsProcess(init, at, { lockdown: () => nodeLockdown() })
14315
- }));
14980
+ var strayScope = nodeProcess ? { process: nodeProcess } : {};
14981
+ var onMessage = processEntry(
14982
+ post,
14983
+ void 0,
14984
+ async () => wasi_runtime_exports,
14985
+ async () => ({
14986
+ runJsProcess: (init, at) => runJsProcess(init, at, { lockdown: () => nodeLockdown(), scope: strayScope })
14987
+ }),
14988
+ () => nodeLockdown()
14989
+ );
14316
14990
  port2.on("message", onMessage);
14317
14991
  //# sourceMappingURL=node-process-worker.js.map