@ai-ecoverse/slicc-kernel 1.88.1 → 1.90.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.
@@ -1070,6 +1070,7 @@ function createSyncFsSabBridge(transport, opts = {}) {
1070
1070
  changing({ op: follow2 ? "chown" : "lchown", path, ...ids }, path);
1071
1071
  },
1072
1072
  ...opts.owners ? { owners: true } : {},
1073
+ ...opts.links ? { links: true } : {},
1073
1074
  access: (path, mode, kind = "access", nofollow) => {
1074
1075
  run({ op: "access", path, mode, arg2: kind, ...nofollow ? { nofollow } : {} }, path);
1075
1076
  },
@@ -1540,7 +1541,12 @@ function createNodeOps(h) {
1540
1541
  },
1541
1542
  readlink(node) {
1542
1543
  if (!Fs.isLink(node.mode)) throw new Fs.ErrnoError(wasiErrno("EINVAL"));
1543
- return call2(() => bridgeOf(node).readlink(liveNodePath(node)));
1544
+ const bridge = bridgeOf(node);
1545
+ const path = liveNodePath(node);
1546
+ if (bridge.links && Fs.sliccReading !== node) {
1547
+ call2(() => bridge.access?.(path, 0, "follow", true));
1548
+ }
1549
+ return call2(() => bridge.readlink(path));
1544
1550
  }
1545
1551
  };
1546
1552
  }
@@ -1936,6 +1942,63 @@ function useLiveChown(Fs) {
1936
1942
  Fs.chown(target, uid, gid);
1937
1943
  };
1938
1944
  }
1945
+ function flushOne(Fs, node) {
1946
+ const s = node.live;
1947
+ if (!s.dirty || s.orphan || !(s.data || s.ranged)) return;
1948
+ try {
1949
+ if (s.ranged) s.ranged.flush();
1950
+ else {
1951
+ const bytes = s.data.slice(0, s.len);
1952
+ pinnedIo(node.mount.opts.bridge, s.handle).writeFile(liveNodePath(node), bytes, true);
1953
+ }
1954
+ } catch (err) {
1955
+ throw toErrno(Fs, err);
1956
+ }
1957
+ s.dirty = false;
1958
+ s.stat = void 0;
1959
+ }
1960
+ function linkable(bridge, path) {
1961
+ try {
1962
+ return bridge.lstat(path).linkable === true;
1963
+ } catch {
1964
+ return false;
1965
+ }
1966
+ }
1967
+ function linkLive(Fs, from, to, follow2) {
1968
+ const target = to.replace(/\/+$/, "");
1969
+ const slash = target.lastIndexOf("/");
1970
+ const name2 = target.slice(slash + 1);
1971
+ const source = Fs.lookupPath(from, { follow: follow2 }).node;
1972
+ const parent = Fs.lookupPath(target.slice(0, slash) || "/", { follow: true }).node;
1973
+ if (!source.live || !parent.live) return false;
1974
+ flushOne(Fs, source);
1975
+ const base = liveNodePath(parent);
1976
+ const bridge = source.mount.opts.bridge;
1977
+ const path = liveNodePath(source);
1978
+ try {
1979
+ bridge.link(path, base === "/" ? `/${name2}` : `${base}/${name2}`);
1980
+ } catch (err) {
1981
+ const refused = toErrno(Fs, err);
1982
+ if (refused.errno !== wasiErrno("EPERM") || linkable(bridge, path)) throw refused;
1983
+ throw new Fs.ErrnoError(wasiErrno("EMLINK"));
1984
+ }
1985
+ source.live.stat = void 0;
1986
+ parent.live.listed = void 0;
1987
+ return true;
1988
+ }
1989
+ function readingLinks(Fs) {
1990
+ const readlink = Fs.readlink?.bind(Fs);
1991
+ if (!readlink) return;
1992
+ Fs.readlink = (path) => {
1993
+ const was = Fs.sliccReading;
1994
+ Fs.sliccReading = Fs.lookupPath(path).node;
1995
+ try {
1996
+ return readlink(path);
1997
+ } finally {
1998
+ Fs.sliccReading = was;
1999
+ }
2000
+ };
2001
+ }
1939
2002
  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;
1940
2003
  var init_live_vfs_fs = __esm({
1941
2004
  "src/realm/live-vfs-fs.ts"() {
@@ -1987,6 +2050,7 @@ function mountVfsIntoEmscripten(Fs, deps) {
1987
2050
  const { plugin, mounted } = mountLiveVfsDirs(Fs, bridge, dirs ?? [], warn);
1988
2051
  if (dirs) liveRoot(Fs, bridge);
1989
2052
  if (bridge.owners && Fs.lookupPath) useLiveChown(Fs);
2053
+ if (bridge.links && Fs.lookupPath) readingLinks(Fs);
1990
2054
  try {
1991
2055
  Fs.chdir(deps.cwd);
1992
2056
  } catch (err) {
@@ -2154,21 +2218,46 @@ var init_kernel_streams = __esm({
2154
2218
  if (typeof this.Fs.stat !== "function") return;
2155
2219
  stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name2) ?? {} };
2156
2220
  }
2221
+ nameDevice(stream, kind) {
2222
+ this.nameStream(stream, kind === "sealed" ? SEALED_PATH : CLIPBOARD_PATH);
2223
+ }
2157
2224
  listSealed() {
2158
- const { analyzePath, mkdev, makedev } = this.Fs;
2225
+ const fs = this.Fs;
2226
+ const { analyzePath, mkdev, makedev, registerDevice } = fs;
2159
2227
  if (!analyzePath || !mkdev || !makedev) return;
2160
2228
  const nodes = [
2161
2229
  [SEALED_PATH, 250, this.sys.openSealed],
2162
2230
  [CLIPBOARD_PATH, 251, this.sys.openClipboard]
2163
2231
  ];
2164
- for (const [path, minor, present] of nodes) {
2165
- if (!present || analyzePath.call(this.Fs, path).exists) continue;
2232
+ for (const [path, minor, opener] of nodes) {
2233
+ if (!opener) continue;
2234
+ const dev = makedev.call(fs, 10, minor);
2235
+ registerDevice?.call(fs, dev, {
2236
+ open: (stream) => this.openNode(stream, path, opener)
2237
+ });
2238
+ if (analyzePath.call(fs, path).exists) continue;
2166
2239
  try {
2167
- mkdev.call(this.Fs, path, makedev.call(this.Fs, 10, minor));
2240
+ const node = mkdev.call(fs, path, dev);
2241
+ if (typeof node === "object" && node !== null) {
2242
+ const made = node;
2243
+ made.node_ops = { ...made.node_ops, getattr: () => sealedStat(minor) };
2244
+ }
2168
2245
  } catch {
2169
2246
  }
2170
2247
  }
2171
2248
  }
2249
+ openNode(stream, path, opener) {
2250
+ let kfd;
2251
+ try {
2252
+ kfd = this.call(() => opener.call(this.sys, stream.flags & 3));
2253
+ } catch (e) {
2254
+ this.Fs.closeStream(stream.fd);
2255
+ throw e;
2256
+ }
2257
+ this.attach(stream, kfd, false);
2258
+ this.nameStream(stream, path);
2259
+ if (path === CLIPBOARD_PATH) this.reportClose(kfd);
2260
+ }
2172
2261
  reporting = /* @__PURE__ */ new Set();
2173
2262
  reportClose(kfd) {
2174
2263
  this.reporting.add(kfd);
@@ -3223,8 +3312,9 @@ function readonlyRefusal(Fs, memory, call2) {
3223
3312
  follow: follow2
3224
3313
  });
3225
3314
  const bridge = node.live ? node.mount.opts.bridge : void 0;
3226
- const stat = bridge?.stat;
3227
- return stat?.(liveNodePath(node)).readonly ? -wasiErrno("EROFS") : 0;
3315
+ const stats = bridge;
3316
+ const stat = follow2 ? stats?.stat : stats?.lstat;
3317
+ return stat?.call(stats, liveNodePath(node)).readonly ? -wasiErrno("EROFS") : 0;
3228
3318
  } catch {
3229
3319
  return 0;
3230
3320
  }
@@ -3256,6 +3346,32 @@ function kernelAccess(imports, fs, memory, glue) {
3256
3346
  }
3257
3347
  });
3258
3348
  }
3349
+ function kernelLink(imports, fs, memory, glue) {
3350
+ wrapImport(
3351
+ imports,
3352
+ "linkat",
3353
+ glue,
3354
+ (own) => (olddirfd, oldpath, newdirfd, newpath, flags) => {
3355
+ const Fs = fs();
3356
+ const heap = memory();
3357
+ if (!Fs?.lookupPath || !heap) return own(olddirfd, oldpath, newdirfd, newpath, flags);
3358
+ const at = (dirfd, ptr) => {
3359
+ const name2 = cString(heap, ptr);
3360
+ return name2.startsWith("/") ? name2 : `${baseOf(Fs, dirfd)}/${name2}`;
3361
+ };
3362
+ try {
3363
+ const from = at(olddirfd, oldpath);
3364
+ const to = at(newdirfd, newpath);
3365
+ const follow2 = (flags & AT_SYMLINK_FOLLOW) !== 0;
3366
+ if (linkLive(Fs, from, to, follow2)) return 0;
3367
+ } catch (err) {
3368
+ return -errnoOf(err);
3369
+ }
3370
+ return own(olddirfd, oldpath, newdirfd, newpath, flags);
3371
+ },
3372
+ true
3373
+ );
3374
+ }
3259
3375
  function kernelChdir(Fs) {
3260
3376
  const { chdir, lookupPath, ErrnoError } = Fs;
3261
3377
  if (!chdir || !lookupPath || !ErrnoError) return;
@@ -3283,7 +3399,7 @@ function linuxDevices(Fs) {
3283
3399
  }
3284
3400
  }
3285
3401
  }
3286
- 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, DEVICE_MODES;
3402
+ 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;
3287
3403
  var init_process_fds = __esm({
3288
3404
  "src/process/process-fds.ts"() {
3289
3405
  "use strict";
@@ -3318,6 +3434,7 @@ var init_process_fds = __esm({
3318
3434
  mknodat: "__syscall_mknodat",
3319
3435
  umask: "__syscall_umask",
3320
3436
  faccessat: "__syscall_faccessat",
3437
+ linkat: "__syscall_linkat",
3321
3438
  utimensat: "__syscall_utimensat",
3322
3439
  getppid: "slicc_getppid_js",
3323
3440
  resizeHeap: "emscripten_resize_heap",
@@ -3344,6 +3461,7 @@ var init_process_fds = __esm({
3344
3461
  AT_EACCESS = 512;
3345
3462
  W_ACCESS = 2;
3346
3463
  X_ACCESS = 1;
3464
+ AT_SYMLINK_FOLLOW = 1024;
3347
3465
  DEVICE_MODES = [
3348
3466
  ["/", 493],
3349
3467
  ["/dev", 493],
@@ -3412,7 +3530,8 @@ function kernelEntry(stream, kernel) {
3412
3530
  if (stream.sliccKernelSocket) {
3413
3531
  return { fd: stream.fd, kernel, kind: "socket", flags: stream.flags, ...cloexec };
3414
3532
  }
3415
- const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : "stream";
3533
+ const device2 = stream.path === void 0 ? void 0 : NAMED_DEVICES[stream.path];
3534
+ const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : device2 ?? "stream";
3416
3535
  return { fd: stream.fd, kernel, kind, ...cloexec };
3417
3536
  }
3418
3537
  function describeInherited(Fs, sys, streams, livePath, actions = []) {
@@ -3462,7 +3581,8 @@ function place(Fs, stream, fd) {
3462
3581
  function placeholder(Fs, streams, entry) {
3463
3582
  if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR);
3464
3583
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
3465
- if (entry.kind === "stream" || entry.kind === "clipboard") return Fs.open("/dev/null", O_RDWR);
3584
+ if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
3585
+ return Fs.open("/dev/null", O_RDWR);
3466
3586
  Fs.mkdirTree(PLACEHOLDER_DIR);
3467
3587
  return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, O_RDWR | O_CREAT3);
3468
3588
  }
@@ -3487,6 +3607,7 @@ function placeKernelStream(Fs, streams, entry) {
3487
3607
  } else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
3488
3608
  else streams.attach(stream, entry.kernel, entry.kind === "tty");
3489
3609
  if (entry.kind === "clipboard") streams.reportClose(entry.kernel);
3610
+ if (entry.kind === "sealed" || entry.kind === "clipboard") streams.nameDevice(stream, entry.kind);
3490
3611
  if (entry.kind === "tty") streams.nameTerminal(stream);
3491
3612
  if (entry.kind === "stream") {
3492
3613
  asFifo(stream, streams, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
@@ -3512,7 +3633,7 @@ function restoreForkedStreams(Fs, streams, table) {
3512
3633
  }
3513
3634
  }
3514
3635
  }
3515
- var O_RDWR, O_ACCMODE3, O_CREAT3, O_EXCL2, O_TRUNC3, PLACEHOLDER_DIR, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3636
+ var O_RDWR, O_ACCMODE3, O_CREAT3, O_EXCL2, O_TRUNC3, PLACEHOLDER_DIR, NAMED_DEVICES, ACCESS, DEVICES, FIFO_MODE, nextStreamIno, streamInos;
3516
3637
  var init_process_fork = __esm({
3517
3638
  "src/process/process-fork.ts"() {
3518
3639
  "use strict";
@@ -3523,6 +3644,10 @@ var init_process_fork = __esm({
3523
3644
  O_EXCL2 = 128;
3524
3645
  O_TRUNC3 = 512;
3525
3646
  PLACEHOLDER_DIR = "/dev/slicc-fd";
3647
+ NAMED_DEVICES = {
3648
+ "/dev/sealed": "sealed",
3649
+ "/dev/clipboard": "clipboard"
3650
+ };
3526
3651
  ACCESS = { 0: "read", 1: "write" };
3527
3652
  DEVICES = {
3528
3653
  "/dev/null": "null",
@@ -4160,7 +4285,7 @@ var KERNEL_VERSION, OS_RELEASE;
4160
4285
  var init_version = __esm({
4161
4286
  "src/version.ts"() {
4162
4287
  "use strict";
4163
- KERNEL_VERSION = true ? "1.88.1" : "0.0.0-dev";
4288
+ KERNEL_VERSION = true ? "1.90.0" : "0.0.0-dev";
4164
4289
  OS_RELEASE = "6.0.0-slicc";
4165
4290
  }
4166
4291
  });
@@ -4440,9 +4565,9 @@ function useProcfs(Fs, sys, pid, memory = memorySource()) {
4440
4565
  }
4441
4566
  return found;
4442
4567
  };
4443
- const procOps = proc.node_ops;
4444
- const lookup2 = procOps.lookup?.bind(procOps);
4445
- const readdir = procOps.readdir?.bind(procOps);
4568
+ const procOps2 = proc.node_ops;
4569
+ const lookup2 = procOps2.lookup?.bind(procOps2);
4570
+ const readdir = procOps2.readdir?.bind(procOps2);
4446
4571
  const listAll = (node) => {
4447
4572
  const names = new Set(readdir ? readdir(node) : [".", ".."]);
4448
4573
  for (const name2 of [...SYSTEM_FILES, "mounts", "sys"]) names.add(name2);
@@ -4450,7 +4575,7 @@ function useProcfs(Fs, sys, pid, memory = memorySource()) {
4450
4575
  return [...names];
4451
4576
  };
4452
4577
  proc.node_ops = {
4453
- ...procOps,
4578
+ ...procOps2,
4454
4579
  lookup: (parent, name2) => {
4455
4580
  if (/^[1-9]\d*$/.test(name2)) {
4456
4581
  if (!infoOf(Number(name2)) && !listed(Number(name2))) throw error();
@@ -4831,6 +4956,7 @@ function kernelWrappers(imports, module, deps) {
4831
4956
  const fsOf = () => ownValue(module, "FS");
4832
4957
  noFollowUtimes(imports, fsOf, kernelGlue?.utimensat ?? utimensatOf(module), memory);
4833
4958
  kernelAccess(imports, fsOf, memory, kernelGlue);
4959
+ kernelLink(imports, fsOf, memory, kernelGlue);
4834
4960
  const glue = ownValue(module, "sliccFdImports");
4835
4961
  syncFsync(imports, fsOf, glue);
4836
4962
  positionalIo(imports, { glue, fs: fsOf, sys, memory });
@@ -4838,6 +4964,9 @@ function kernelWrappers(imports, module, deps) {
4838
4964
  reportGrowth(imports, grown, kernelGlue);
4839
4965
  holdWhileStopped(imports, new Int32Array(init.sab, 0, SAB_HEADER_I32), kernelGlue, deps.poll);
4840
4966
  }
4967
+ function bridgeFlags(init) {
4968
+ return { ...init.owners ? { owners: true } : {}, ...init.links ? { links: true } : {} };
4969
+ }
4841
4970
  async function runWasmProcess(init, port2, deps = {}) {
4842
4971
  const signals = new SignalGate(
4843
4972
  createSyncSabTransport(init.sab, port2, {
@@ -4942,7 +5071,7 @@ async function runWasmProcess(init, port2, deps = {}) {
4942
5071
  if (!hasStreams(running)) return runStdioOnly(running, init);
4943
5072
  if (init.owners) linuxDevices(running.FS);
4944
5073
  const vfs = mountVfsIntoEmscripten(running.FS, {
4945
- bridge: createSyncFsSabBridge(transport, init.owners ? { owners: true } : {}),
5074
+ bridge: createSyncFsSabBridge(transport, bridgeFlags(init)),
4946
5075
  cwd: init.cwd,
4947
5076
  warn: deps.warn ?? say(2)
4948
5077
  });
@@ -5097,7 +5226,7 @@ var init_process_runtime = __esm({
5097
5226
  O_ACCMODE4 = 3;
5098
5227
  O_DIRECTORY = 65536;
5099
5228
  accessMode = (access) => access === "read" ? O_RDONLY : access === "write" ? O_WRONLY3 : O_RDWR3;
5100
- PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard"]);
5229
+ PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket", "clipboard", "sealed"]);
5101
5230
  GLUE_TRAILER = [
5102
5231
  "if (typeof ENV !== 'undefined') Object.assign(ENV, Module.sliccEnv);",
5103
5232
  "if (typeof thisProgram !== 'undefined' && Module.thisProgram === '') thisProgram = '';",
@@ -5126,6 +5255,7 @@ var init_process_runtime = __esm({
5126
5255
  " mknodat: typeof ___syscall_mknodat === 'function' ? ___syscall_mknodat : undefined,",
5127
5256
  " umask: typeof ___syscall_umask === 'function' ? ___syscall_umask : undefined,",
5128
5257
  " faccessat: typeof ___syscall_faccessat === 'function' ? ___syscall_faccessat : undefined,",
5258
+ " linkat: typeof ___syscall_linkat === 'function' ? ___syscall_linkat : undefined,",
5129
5259
  " utimensat: typeof ___syscall_utimensat === 'function' ? ___syscall_utimensat : undefined,",
5130
5260
  " getppid: typeof _slicc_getppid_js === 'function' ? _slicc_getppid_js : undefined,",
5131
5261
  " resizeHeap: typeof _emscripten_resize_heap === 'function' ? _emscripten_resize_heap : undefined,",
@@ -5314,6 +5444,7 @@ function physical(fs, path) {
5314
5444
  const st = fs.lstat(at);
5315
5445
  if (st.isSymbolicLink) {
5316
5446
  if (++hops > MAX_LINKS) throw new WasiError("ELOOP");
5447
+ if (fs.links) fs.access?.(at, 0, "follow", true);
5317
5448
  const target = fs.readlink(at);
5318
5449
  if (target.startsWith("/")) done = [];
5319
5450
  todo = [...target.split("/").filter((p) => p !== "" && p !== "."), ...todo];
@@ -5453,6 +5584,7 @@ function cachingBridge(bridge, now = () => performance.now(), shared) {
5453
5584
  truncate: (p, size) => rewriting(p, () => bridge.truncate?.(p, size))
5454
5585
  } : {},
5455
5586
  ...bridge.owners ? { owners: true } : {},
5587
+ ...bridge.links ? { links: true } : {},
5456
5588
  invalidate,
5457
5589
  touched,
5458
5590
  threaded
@@ -7129,6 +7261,7 @@ var init_wasi_host = __esm({
7129
7261
  view.setUint32(old, oldLo, true);
7130
7262
  view.setUint32(old + 4, oldHi, true);
7131
7263
  }) : E.NOSYS,
7264
+ sigmask_poll: (lo, hi, inPtr, outPtr, n, nevents) => this.sigmask ? this.maskedPoll(this.sigmask, [lo, hi], [inPtr, outPtr, n, nevents]) : E.NOSYS,
7132
7265
  sigpending_get: (out) => {
7133
7266
  if (!this.sigmask) return E.NOSYS;
7134
7267
  mem.view().setBigUint64(out, BigInt(this.sigmask.pending()), true);
@@ -7136,6 +7269,47 @@ var init_wasi_host = __esm({
7136
7269
  }
7137
7270
  });
7138
7271
  }
7272
+ poll(inPtr, outPtr, n, nevents) {
7273
+ try {
7274
+ return pollOneoff(
7275
+ {
7276
+ mem: this.mem,
7277
+ fds: this.fds,
7278
+ kernel: this.o.kernel,
7279
+ now: (id) => this.now(id),
7280
+ interruptWakes: this.interruptWakes
7281
+ },
7282
+ inPtr,
7283
+ outPtr,
7284
+ n,
7285
+ nevents
7286
+ );
7287
+ } finally {
7288
+ this.o.fs.invalidate?.();
7289
+ }
7290
+ }
7291
+ maskedPoll(mask, set, [inPtr, outPtr, n, nevents]) {
7292
+ const old = mask.swap(set[0], set[1]);
7293
+ try {
7294
+ this.mem.view().setUint32(nevents, 0, true);
7295
+ if (mask.deliverUnblocked()) return E.INTR;
7296
+ if (n > 0) return this.poll(inPtr, outPtr, n, nevents);
7297
+ return this.suspend();
7298
+ } finally {
7299
+ mask.deliverUnblocked();
7300
+ mask.restore(old);
7301
+ }
7302
+ }
7303
+ suspend() {
7304
+ for (; ; ) {
7305
+ try {
7306
+ this.o.kernel.call({ op: "fd-select", read: [], write: [], timeoutMs: -1 });
7307
+ } catch (e) {
7308
+ if (e.code === "EINTR") return E.INTR;
7309
+ throw e;
7310
+ }
7311
+ }
7312
+ }
7139
7313
  imports() {
7140
7314
  this.cache ??= wrap({
7141
7315
  ...this.processImports(),
@@ -7143,25 +7317,7 @@ var init_wasi_host = __esm({
7143
7317
  ...this.statImports(),
7144
7318
  ...this.pathImports(),
7145
7319
  ...this.socketImports(),
7146
- poll_oneoff: (inPtr, outPtr, n, nevents) => {
7147
- try {
7148
- return pollOneoff(
7149
- {
7150
- mem: this.mem,
7151
- fds: this.fds,
7152
- kernel: this.o.kernel,
7153
- now: (id) => this.now(id),
7154
- interruptWakes: this.interruptWakes
7155
- },
7156
- inPtr,
7157
- outPtr,
7158
- n,
7159
- nevents
7160
- );
7161
- } finally {
7162
- this.o.fs.invalidate?.();
7163
- }
7164
- }
7320
+ poll_oneoff: (inPtr, outPtr, n, nevents) => this.poll(inPtr, outPtr, n, nevents)
7165
7321
  });
7166
7322
  return this.cache;
7167
7323
  }
@@ -8253,15 +8409,15 @@ function procPath(fs, path, follow2) {
8253
8409
  return result;
8254
8410
  }
8255
8411
  function frozen(bytes) {
8256
- const refuse = () => {
8412
+ const refuse2 = () => {
8257
8413
  throw syncError("EROFS", "/proc");
8258
8414
  };
8259
8415
  return {
8260
8416
  readFile: () => bytes,
8261
8417
  pread: (_p, at, n) => bytes.subarray(at, at + n),
8262
- writeFile: refuse,
8263
- pwrite: refuse,
8264
- truncate: refuse
8418
+ writeFile: refuse2,
8419
+ pwrite: refuse2,
8420
+ truncate: refuse2
8265
8421
  };
8266
8422
  }
8267
8423
  function procfsBridge(fs, tree) {
@@ -8287,7 +8443,7 @@ function procfsBridge(fs, tree) {
8287
8443
  return proc(real);
8288
8444
  }
8289
8445
  };
8290
- const readOnly = (paths, run) => {
8446
+ const readOnly2 = (paths, run) => {
8291
8447
  const physical2 = shadowing();
8292
8448
  for (const [p, follow2] of paths) {
8293
8449
  if (inProc(p) || physical2 && toProc(p, follow2) !== void 0) throw syncError("EROFS", p);
@@ -8367,15 +8523,15 @@ function procfsBridge(fs, tree) {
8367
8523
  return [...listed, ["proc", tree.stat("/proc")]];
8368
8524
  }
8369
8525
  ),
8370
- rename: (from, to) => readOnly(
8526
+ rename: (from, to) => readOnly2(
8371
8527
  [
8372
8528
  [from, false],
8373
8529
  [to, false]
8374
8530
  ],
8375
8531
  () => fs.rename(from, to)
8376
8532
  ),
8377
- symlink: (target, link) => readOnly([[link, false]], () => fs.symlink(target, link)),
8378
- link: (from, to, follow2) => readOnly(
8533
+ symlink: (target, link) => readOnly2([[link, false]], () => fs.symlink(target, link)),
8534
+ link: (from, to, follow2) => readOnly2(
8379
8535
  [
8380
8536
  [from, follow2 === true],
8381
8537
  [to, false]
@@ -8407,12 +8563,12 @@ function procfsBridge(fs, tree) {
8407
8563
  for (const name2 of names) {
8408
8564
  const fn = fs[name2];
8409
8565
  if (!fn) continue;
8410
- over[name2] = (p, ...rest2) => readOnly([[p, follow2]], () => fn.call(fs, p, ...rest2));
8566
+ over[name2] = (p, ...rest2) => readOnly2([[p, follow2]], () => fn.call(fs, p, ...rest2));
8411
8567
  }
8412
8568
  }
8413
8569
  const { chown } = fs;
8414
8570
  if (chown) {
8415
- over.chown = (p, uid, gid, follow2) => readOnly([[p, follow2 === true]], () => chown.call(fs, p, uid, gid, follow2));
8571
+ over.chown = (p, uid, gid, follow2) => readOnly2([[p, follow2 === true]], () => chown.call(fs, p, uid, gid, follow2));
8416
8572
  }
8417
8573
  return new Proxy(fs, {
8418
8574
  get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
@@ -8593,6 +8749,23 @@ var init_wasi_sigmask = __esm({
8593
8749
  if ((Atomics.load(this.header, SAB_I_SIGNALS) & ~now) !== 0) this.deliver();
8594
8750
  return E.SUCCESS;
8595
8751
  }
8752
+ swap(setLo, setHi) {
8753
+ const old = [this.lo, this.hi];
8754
+ this.lo = setLo & ~LIBC_UNBLOCKABLE;
8755
+ this.hi = setHi | 0;
8756
+ Atomics.store(this.header, SAB_I_BLOCKED, kernelBits(this.lo));
8757
+ return old;
8758
+ }
8759
+ deliverUnblocked() {
8760
+ const now = Atomics.load(this.header, SAB_I_BLOCKED);
8761
+ if ((Atomics.load(this.header, SAB_I_SIGNALS) & ~now) === 0) return false;
8762
+ this.deliver();
8763
+ return true;
8764
+ }
8765
+ restore([lo, hi]) {
8766
+ this.set(SIG_SETMASK, lo, hi, () => {
8767
+ });
8768
+ }
8596
8769
  discard(sig) {
8597
8770
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
8598
8771
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
@@ -10878,7 +11051,7 @@ function descriptors(init, fork, threads) {
10878
11051
  return { inherited: init.fds ?? [], ...init.program.preopenRoot ? { preopenRoot: true } : {} };
10879
11052
  }
10880
11053
  function ownersOf(init) {
10881
- return init.owners ? { owners: true } : {};
11054
+ return { ...init.owners ? { owners: true } : {}, ...init.links ? { links: true } : {} };
10882
11055
  }
10883
11056
  async function runWasiProcess(init, port2) {
10884
11057
  captureBacktraces(init.env);
@@ -12685,6 +12858,153 @@ var init_js_net = __esm({
12685
12858
  }
12686
12859
  });
12687
12860
 
12861
+ // src/process/js/js-proc.ts
12862
+ function* procStep(abs, pid, run) {
12863
+ const listing = yield { op: "proc-list" };
12864
+ const mounts = abs === "/proc/mounts" ? yield { op: "mount-list" } : [];
12865
+ const tree = new ProcTree(
12866
+ { procList: () => listing, mountList: () => mounts },
12867
+ pid,
12868
+ memorySource()
12869
+ );
12870
+ try {
12871
+ return run(tree);
12872
+ } catch (err) {
12873
+ throw new JsCallError(err.code ?? "EIO", abs);
12874
+ }
12875
+ }
12876
+ function readOnly(path) {
12877
+ throw new JsCallError("EROFS", path);
12878
+ }
12879
+ function procWrites(options) {
12880
+ return !!(options?.write || options?.append || options?.create || options?.truncate || options?.exclusive);
12881
+ }
12882
+ function snapshotFile(path, bytes) {
12883
+ let closed = false;
12884
+ const live = () => {
12885
+ if (closed) throw new JsCallError("EBADF", path);
12886
+ };
12887
+ return {
12888
+ fd: -1,
12889
+ path,
12890
+ size: () => {
12891
+ live();
12892
+ return bytes.length;
12893
+ },
12894
+ read: (position, length) => {
12895
+ live();
12896
+ index2(position, "read");
12897
+ index2(length, "read");
12898
+ return bytes.slice(position, position + length);
12899
+ },
12900
+ write: () => {
12901
+ throw new JsCallError("EBADF", path);
12902
+ },
12903
+ truncate: () => {
12904
+ throw new JsCallError("EBADF", path);
12905
+ },
12906
+ sync: () => live(),
12907
+ close: () => {
12908
+ live();
12909
+ closed = true;
12910
+ }
12911
+ };
12912
+ }
12913
+ function promised(file) {
12914
+ const out = { ...file };
12915
+ for (const [name2, value2] of Object.entries(file)) {
12916
+ if (typeof value2 === "function") {
12917
+ out[name2] = (...args) => new Promise((resolve) => resolve(value2(...args)));
12918
+ }
12919
+ }
12920
+ return out;
12921
+ }
12922
+ function procOps(paths, run) {
12923
+ const at = (path) => {
12924
+ const abs = paths.resolve(path);
12925
+ return inProc(abs) ? abs : void 0;
12926
+ };
12927
+ const step = (abs, op) => run(procStep(abs, paths.pid, op));
12928
+ return { at, step };
12929
+ }
12930
+ function withProc(fs, paths, run) {
12931
+ const { at, step } = procOps(paths, run);
12932
+ const out = { ...fs };
12933
+ const pass = fs;
12934
+ const reads = {
12935
+ stat: (tree, abs) => tree.stat(abs, true),
12936
+ lstat: (tree, abs) => tree.stat(abs, false),
12937
+ exists: (tree, abs) => tree.exists(abs),
12938
+ readdir: (tree, abs) => tree.readdir(abs),
12939
+ readlink: (tree, abs) => tree.readlink(abs),
12940
+ readFile: (tree, abs) => tree.read(abs)
12941
+ };
12942
+ for (const [name2, read2] of Object.entries(reads)) {
12943
+ out[name2] = (path, ...rest2) => {
12944
+ const abs = at(path);
12945
+ return abs ? step(abs, (tree) => read2(tree, abs)) : pass[name2]?.(path, ...rest2);
12946
+ };
12947
+ }
12948
+ for (const name2 of WRITES) {
12949
+ out[name2] = (path, ...rest2) => {
12950
+ const abs = at(path);
12951
+ return abs ? run(refuse(abs)) : pass[name2]?.(path, ...rest2);
12952
+ };
12953
+ }
12954
+ for (const name2 of TWO) {
12955
+ out[name2] = (from, to) => {
12956
+ const abs = at(from) ?? at(to);
12957
+ return abs ? run(refuse(abs)) : pass[name2]?.(from, to);
12958
+ };
12959
+ }
12960
+ out.symlink = (target, path) => {
12961
+ const abs = at(path);
12962
+ return abs ? run(refuse(abs)) : pass.symlink?.(target, path);
12963
+ };
12964
+ return out;
12965
+ }
12966
+ function* refuse(abs) {
12967
+ yield* [];
12968
+ return readOnly(abs);
12969
+ }
12970
+ function procOpen(open, paths, run, async = false) {
12971
+ const { at, step } = procOps(paths, run);
12972
+ return (path, options) => {
12973
+ const abs = at(path);
12974
+ if (!abs) return open(path, options);
12975
+ if (procWrites(options)) return run(refuse(abs));
12976
+ return step(abs, (tree) => {
12977
+ const file = snapshotFile(abs, tree.read(abs));
12978
+ return async ? promised(file) : file;
12979
+ });
12980
+ };
12981
+ }
12982
+ function procFsAsync(fs, kernel, paths) {
12983
+ return withProc(fs, paths, (step) => devAsync(kernel, step));
12984
+ }
12985
+ function procFsSync(fs, kernel, paths) {
12986
+ return withProc(fs, paths, (step) => devSync(kernel, step));
12987
+ }
12988
+ function procOpenAsync(open, kernel, paths) {
12989
+ return procOpen(open, paths, (step) => devAsync(kernel, step), true);
12990
+ }
12991
+ function procOpenSync(open, kernel, paths) {
12992
+ return procOpen(open, paths, (step) => devSync(kernel, step));
12993
+ }
12994
+ var WRITES, TWO;
12995
+ var init_js_proc = __esm({
12996
+ "src/process/js/js-proc.ts"() {
12997
+ "use strict";
12998
+ init_procfs();
12999
+ init_wasi_procfs();
13000
+ init_js_dev();
13001
+ init_js_io();
13002
+ init_js_kernel();
13003
+ WRITES = ["mkdir", "rm", "unlink", "chmod", "writeFile"];
13004
+ TWO = ["rename", "link"];
13005
+ }
13006
+ });
13007
+
12688
13008
  // src/process/js/js-run.ts
12689
13009
  function stdioOf(how) {
12690
13010
  if (how === void 0) return "pipe";
@@ -12849,8 +13169,11 @@ function syncOps(kernel, shared) {
12849
13169
  infos.delete(fd);
12850
13170
  kernel.call({ op: "fd-close", fd });
12851
13171
  },
12852
- open,
12853
- fs: syncPathOps(kernel, resolve, statOf, open)
13172
+ open: procOpenSync(open, kernel, { resolve, pid: shared.pid }),
13173
+ fs: procFsSync(syncPathOps(kernel, resolve, statOf, open), kernel, {
13174
+ resolve,
13175
+ pid: shared.pid
13176
+ })
12854
13177
  };
12855
13178
  }
12856
13179
  function syncFile(kernel, fd, path, append, forget) {
@@ -12978,6 +13301,7 @@ var init_js_sync = __esm({
12978
13301
  init_js_dev();
12979
13302
  init_js_io();
12980
13303
  init_js_kernel();
13304
+ init_js_proc();
12981
13305
  encoder3 = new TextEncoder();
12982
13306
  noLane = () => ({ ok: false, errno: "ENOSYS", message: "no sync lane" });
12983
13307
  JsSyncKernel = class {
@@ -13441,7 +13765,7 @@ function createContext(o) {
13441
13765
  handles.set(fd, handle.invalidate);
13442
13766
  return handle.file;
13443
13767
  };
13444
- const fs = pathOps(kernel, resolve, statOf, open);
13768
+ const fs = procFsAsync(pathOps(kernel, resolve, statOf, open), kernel, { resolve, pid: o.pid });
13445
13769
  const lane = o.lane ?? laneOf(void 0);
13446
13770
  if (o.lane && o.lane !== noLane) kernel.syncLane = o.lane;
13447
13771
  const syncKernel = new JsSyncKernel(lane, kernel, unwind);
@@ -13493,7 +13817,7 @@ function createContext(o) {
13493
13817
  return { type, tty: type === "tty", seekable: type === "file" };
13494
13818
  },
13495
13819
  isatty: async (fd) => typeOf(await info(fd)) === "tty",
13496
- open,
13820
+ open: procOpenAsync(open, kernel, { resolve, pid: o.pid }),
13497
13821
  resolve,
13498
13822
  fs,
13499
13823
  signals: {
@@ -13700,6 +14024,7 @@ var init_js_context = __esm({
13700
14024
  init_js_io();
13701
14025
  init_js_kernel();
13702
14026
  init_js_net();
14027
+ init_js_proc();
13703
14028
  init_js_run();
13704
14029
  init_js_sync();
13705
14030
  init_js_tty();