@ai-ecoverse/slicc-kernel 1.34.0 → 1.35.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.
@@ -594,6 +594,26 @@ function toMs(v) {
594
594
  }
595
595
  function createHelpers(Fs, ops) {
596
596
  const bridgeOf = (node) => node.mount.opts.bridge;
597
+ const dirty = /* @__PURE__ */ new Set();
598
+ function markDirty(node) {
599
+ node.live.dirty = true;
600
+ dirty.add(node);
601
+ }
602
+ function flushDirty() {
603
+ for (const node of [...dirty]) {
604
+ const s = node.live;
605
+ if (!s.dirty || s.orphan) {
606
+ dirty.delete(node);
607
+ continue;
608
+ }
609
+ if (!s.ranged && s.len > EARLY_WHOLE_FILE) continue;
610
+ try {
611
+ flushNode(node);
612
+ dirty.delete(node);
613
+ } catch {
614
+ }
615
+ }
616
+ }
597
617
  function call2(fn) {
598
618
  try {
599
619
  return fn();
@@ -688,7 +708,7 @@ function createHelpers(Fs, ops) {
688
708
  const ranged = s.openCount > 0 ? rangedOf(node) : void 0;
689
709
  if (ranged) {
690
710
  ranged.truncate(size);
691
- s.dirty = true;
711
+ markDirty(node);
692
712
  return;
693
713
  }
694
714
  if (s.openCount > 0) {
@@ -697,7 +717,7 @@ function createHelpers(Fs, ops) {
697
717
  const buf = ensureCapacity(node, size);
698
718
  if (size > s.len) buf.fill(0, s.len, size);
699
719
  s.len = size;
700
- s.dirty = true;
720
+ markDirty(node);
701
721
  return;
702
722
  }
703
723
  const path = liveNodePath(node);
@@ -727,6 +747,8 @@ function createHelpers(Fs, ops) {
727
747
  ensureCapacity,
728
748
  rangedOf,
729
749
  flushNode,
750
+ markDirty,
751
+ flushDirty,
730
752
  truncate
731
753
  };
732
754
  }
@@ -971,7 +993,7 @@ function createStreamOps(h) {
971
993
  if (ranged) {
972
994
  const bytes = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, length);
973
995
  h.call(() => ranged.write(position, bytes));
974
- s.dirty = true;
996
+ h.markDirty(node);
975
997
  return length;
976
998
  }
977
999
  ensureLoaded(node);
@@ -979,7 +1001,7 @@ function createStreamOps(h) {
979
1001
  if (position > s.len) buf.fill(0, s.len, position);
980
1002
  buf.set(new Uint8Array(buffer.buffer, buffer.byteOffset + offset, length), position);
981
1003
  s.len = Math.max(s.len, end);
982
- s.dirty = true;
1004
+ h.markDirty(node);
983
1005
  return length;
984
1006
  },
985
1007
  llseek(stream, offset, whence) {
@@ -1009,6 +1031,7 @@ function createLiveVfsPlugin(Fs) {
1009
1031
  mounts,
1010
1032
  node_ops: nodeOps,
1011
1033
  stream_ops: streamOps,
1034
+ flushDirty: () => h.flushDirty(),
1012
1035
  mount(mount) {
1013
1036
  const st = h.call(() => mount.opts.bridge.stat(mount.opts.root));
1014
1037
  if (!st.isDirectory) throw new Fs.ErrnoError(wasiErrno("ENOTDIR"));
@@ -1173,7 +1196,7 @@ function guardRenames(Fs) {
1173
1196
  rename(from, to);
1174
1197
  };
1175
1198
  }
1176
- var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END;
1199
+ var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE;
1177
1200
  var init_live_vfs_fs = __esm({
1178
1201
  "src/realm/live-vfs-fs.ts"() {
1179
1202
  "use strict";
@@ -1188,6 +1211,7 @@ var init_live_vfs_fs = __esm({
1188
1211
  UMASK = 18;
1189
1212
  SEEK_CUR = 1;
1190
1213
  SEEK_END = 2;
1214
+ EARLY_WHOLE_FILE = 64 * 1024;
1191
1215
  }
1192
1216
  });
1193
1217
 
@@ -1224,6 +1248,7 @@ function mountVfsIntoEmscripten(Fs, deps) {
1224
1248
  return {
1225
1249
  mounted,
1226
1250
  flush: () => flushLiveVfs(Fs, plugin),
1251
+ flushDirty: () => plugin.flushDirty(),
1227
1252
  invalidate: () => invalidateLiveVfs(Fs, plugin)
1228
1253
  };
1229
1254
  }
@@ -1268,10 +1293,34 @@ function parseSyncFsStat(json) {
1268
1293
  ...typeof s.version === "string" ? { version: s.version } : {}
1269
1294
  };
1270
1295
  }
1271
- var SYNC_FS_REQUEST_TIMEOUT_MS;
1296
+ var SYNC_FS_OPS, SYNC_FS_REQUEST_TIMEOUT_MS;
1272
1297
  var init_sync_fs_wire = __esm({
1273
1298
  "src/realm/sync-fs-wire.ts"() {
1274
1299
  "use strict";
1300
+ SYNC_FS_OPS = [
1301
+ "read",
1302
+ "write",
1303
+ "exists",
1304
+ "stat",
1305
+ "lstat",
1306
+ "readdir",
1307
+ "readdir-stat",
1308
+ "mkdir",
1309
+ "rm",
1310
+ "rename",
1311
+ "unlink",
1312
+ "rmdir",
1313
+ "symlink",
1314
+ "readlink",
1315
+ "chmod",
1316
+ "utimes",
1317
+ "lutimes",
1318
+ "statfs",
1319
+ "hold",
1320
+ "pread",
1321
+ "pwrite",
1322
+ "truncate"
1323
+ ];
1275
1324
  SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
1276
1325
  }
1277
1326
  });
@@ -1558,7 +1607,7 @@ function ptyStat(path) {
1558
1607
  function nonblocking(stream) {
1559
1608
  return (stream.flags & O_NONBLOCK) !== 0 ? { nonblock: true } : void 0;
1560
1609
  }
1561
- var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
1610
+ var POLLIN, POLLOUT, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, O_NONBLOCK, SOCKET_MODE, PTY_PATH, TTY_PATH, TTY_NAME, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, KILLED_BY_SIGPIPE, ProcessExit, SyscallError, KernelStreams;
1562
1611
  var init_kernel_streams = __esm({
1563
1612
  "src/process/kernel-streams.ts"() {
1564
1613
  "use strict";
@@ -1573,6 +1622,7 @@ var init_kernel_streams = __esm({
1573
1622
  SOCKET_MODE = 49663;
1574
1623
  PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
1575
1624
  TTY_PATH = /^\/dev\/tty\d+$/;
1625
+ TTY_NAME = /^tty\d+$/;
1576
1626
  O_CREAT = 64;
1577
1627
  O_EXCL = 128;
1578
1628
  O_NOCTTY = 256;
@@ -1646,6 +1696,36 @@ var init_kernel_streams = __esm({
1646
1696
  if (typeof this.Fs.stat !== "function") return;
1647
1697
  stream.stream_ops = { ...stream.stream_ops, getattr: () => this.Fs.stat?.(name) ?? {} };
1648
1698
  }
1699
+ creatingTerminal = false;
1700
+ useTerminalNodes() {
1701
+ const fs = this.Fs;
1702
+ const { lookupNode, readdir, getPath, mkdev, makedev } = fs;
1703
+ const ttyNames = this.sys.ttyNames?.bind(this.sys);
1704
+ if (!lookupNode || !readdir || !getPath || !mkdev || !makedev || !ttyNames) return;
1705
+ fs.lookupNode = (parent, name) => {
1706
+ try {
1707
+ return lookupNode.call(fs, parent, name);
1708
+ } catch (e) {
1709
+ const path = `/dev/${name}`;
1710
+ if (this.creatingTerminal || !TTY_NAME.test(name) || getPath.call(fs, parent) !== "/dev")
1711
+ throw e;
1712
+ if (!ttyNames().includes(path)) throw e;
1713
+ this.creatingTerminal = true;
1714
+ try {
1715
+ mkdev.call(fs, path, makedev.call(fs, 6, 0));
1716
+ } finally {
1717
+ this.creatingTerminal = false;
1718
+ }
1719
+ return lookupNode.call(fs, parent, name);
1720
+ }
1721
+ };
1722
+ fs.readdir = (path) => {
1723
+ const names = readdir.call(fs, path);
1724
+ if (path.replace(/\/+$/, "") !== "/dev") return names;
1725
+ const missing = ttyNames().map((tty) => tty.slice("/dev/".length)).filter((name) => TTY_NAME.test(name) && !names.includes(name));
1726
+ return [...names, ...missing];
1727
+ };
1728
+ }
1649
1729
  ttyNode(name) {
1650
1730
  const { analyzePath, mkdev, makedev } = this.Fs;
1651
1731
  if (!TTY_PATH.test(name) || !analyzePath || !mkdev || !makedev) return;
@@ -1707,8 +1787,13 @@ var init_kernel_streams = __esm({
1707
1787
  useControllingTerminal() {
1708
1788
  if (typeof this.Fs.open !== "function") return;
1709
1789
  this.usePtyPaths();
1790
+ this.useTerminalNodes();
1710
1791
  const open = this.Fs.open.bind(this.Fs);
1711
1792
  this.Fs.open = (path, flags, mode) => {
1793
+ const device = typeof path === "string" ? this.devicePath(path) : void 0;
1794
+ if (device !== void 0 && TTY_PATH.test(device) && !this.terminalExists(device)) {
1795
+ throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
1796
+ }
1712
1797
  const pty = this.openPty(open, path, flags, mode);
1713
1798
  if (pty) return pty;
1714
1799
  const stream = open(path, flags, mode);
@@ -1781,6 +1866,23 @@ var init_kernel_streams = __esm({
1781
1866
  const exists = n === void 0 ? this.sys.openPty !== void 0 : this.sys.ptyNumbers?.().includes(Number(n)) ?? false;
1782
1867
  if (!exists) throw new this.Fs.ErrnoError(wasiErrno("ENOENT"));
1783
1868
  }
1869
+ devicePath(path) {
1870
+ const name = path.slice(path.lastIndexOf("/") + 1);
1871
+ if (!TTY_NAME.test(name)) return void 0;
1872
+ const { lookupPath, cwd } = this.Fs;
1873
+ const absolute = path.startsWith("/") ? path : `${cwd?.call(this.Fs) ?? "/"}/${path}`;
1874
+ const dir = absolute.slice(0, absolute.lastIndexOf("/")) || "/";
1875
+ try {
1876
+ const real = lookupPath?.call(this.Fs, dir, { follow: true }).path ?? dir;
1877
+ return `${real === "/" ? "" : real}/${name}`;
1878
+ } catch {
1879
+ return absolute;
1880
+ }
1881
+ }
1882
+ terminalExists(path) {
1883
+ const { analyzePath } = this.Fs;
1884
+ return analyzePath?.call(this.Fs, path).exists ?? true;
1885
+ }
1784
1886
  openNamedTerminal(path) {
1785
1887
  const { openTty } = this.sys;
1786
1888
  if (!openTty) return void 0;
@@ -2095,6 +2197,37 @@ function pathOpensLinks(Fs) {
2095
2197
  if (!mayOpen || !isLink) return;
2096
2198
  fs.mayOpen = (node, flags) => flags & O_PATH && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2097
2199
  }
2200
+ function kernelUmask(imports, deps) {
2201
+ let umask = deps.initial & 511;
2202
+ for (const ns of namespaces(imports)) {
2203
+ const { __syscall_openat: openat, __syscall_mkdirat: mkdirat } = ns;
2204
+ const { __syscall_mknodat: mknodat, __syscall_umask: own } = ns;
2205
+ if (typeof openat === "function") {
2206
+ ns.__syscall_openat = (dirfd, path, flags, varargs) => {
2207
+ const memory = deps.memory();
2208
+ if (flags & O_CREAT2 && varargs && memory)
2209
+ new Int32Array(memory.buffer)[varargs >> 2] &= ~umask;
2210
+ return openat(dirfd, path, flags, varargs);
2211
+ };
2212
+ }
2213
+ if (typeof mkdirat === "function") {
2214
+ ns.__syscall_mkdirat = (dirfd, path, mode) => mkdirat(dirfd, path, mode & ~umask);
2215
+ }
2216
+ if (typeof mknodat === "function") {
2217
+ ns.__syscall_mknodat = (dirfd, path, mode, dev) => mknodat(dirfd, path, mode & ~umask, dev);
2218
+ }
2219
+ if (typeof own === "function") {
2220
+ own(umask);
2221
+ ns.__syscall_umask = (mask) => {
2222
+ const old = umask;
2223
+ umask = mask & 511;
2224
+ own(umask);
2225
+ deps.set(umask);
2226
+ return old;
2227
+ };
2228
+ }
2229
+ }
2230
+ }
2098
2231
  function noFollowUtimes(imports, fs, glue) {
2099
2232
  for (const namespace of namespaces(imports)) {
2100
2233
  const key = Object.keys(namespace).find(
@@ -2760,7 +2893,6 @@ function createProcessKernel(deps) {
2760
2893
  if (!stream) return { none: true };
2761
2894
  promote?.(stream);
2762
2895
  if (stream.sliccKernelFd !== void 0) return { fd: stream.sliccKernelFd };
2763
- if (stream.path === "/dev/null") return { none: true };
2764
2896
  const device = deviceOfStream(stream);
2765
2897
  if (device) return device;
2766
2898
  return n === 0 ? { input: drain(Fs, stream) } : { capture: true };
@@ -2975,6 +3107,7 @@ var init_process_signals = __esm({
2975
3107
  depth = 0;
2976
3108
  reporting = false;
2977
3109
  unwinding = false;
3110
+ quieted = 0;
2978
3111
  raw;
2979
3112
  header;
2980
3113
  hooks;
@@ -3019,7 +3152,16 @@ var init_process_signals = __esm({
3019
3152
  this.reported = { caught, ignored };
3020
3153
  this.raw.call({ op: "sig-mask", caught, ignored }, Number.POSITIVE_INFINITY, "sig-mask");
3021
3154
  }
3155
+ quiet(fn) {
3156
+ this.quieted++;
3157
+ try {
3158
+ return fn();
3159
+ } finally {
3160
+ this.quieted--;
3161
+ }
3162
+ }
3022
3163
  deliver() {
3164
+ if (this.quieted > 0) return;
3023
3165
  const killed = Atomics.load(this.header, SAB_I_KILLED);
3024
3166
  if (killed !== 0 && !this.unwinding && this.hooks.killed) {
3025
3167
  this.unwinding = true;
@@ -3265,7 +3407,7 @@ function pidStatus(info) {
3265
3407
  const ids = `${UID} ${UID} ${UID} ${UID}`;
3266
3408
  return [
3267
3409
  `Name: ${commOf(info)}`,
3268
- "Umask: 0022",
3410
+ `Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
3269
3411
  `State: ${state}`,
3270
3412
  `Tgid: ${info.pid}`,
3271
3413
  "Ngid: 0",
@@ -3608,9 +3750,15 @@ function kernelSys(transport) {
3608
3750
  kind(fd) {
3609
3751
  return json(call2({ op: "fd-info", fd }, `fd-info ${fd}`))?.kind;
3610
3752
  },
3753
+ device(fd) {
3754
+ return json(call2({ op: "fd-info", fd }, `fd-info ${fd}`)).meta;
3755
+ },
3611
3756
  size(fd) {
3612
3757
  return json(call2({ op: "fd-vfs-stat", fd }, `fd-vfs-stat ${fd}`)).size;
3613
3758
  },
3759
+ ttyNames() {
3760
+ return json(call2({ op: "fd-tty-names" }, "fd-tty-names"));
3761
+ },
3614
3762
  openTty(name) {
3615
3763
  const req = name === void 0 ? { op: "fd-open-tty" } : { op: "fd-open-tty", name };
3616
3764
  return json(call2(req, `fd-open-tty ${name ?? ""}`));
@@ -3683,6 +3831,8 @@ function wireKernelStdio(Fs, streams, sys) {
3683
3831
  const stream = Fs.getStream(fd);
3684
3832
  if (!stream) continue;
3685
3833
  const kind = sys?.kind?.(fd);
3834
+ const device = kind === "device" ? sys?.device?.(fd) : void 0;
3835
+ if (device && openDevice(Fs, fd, device)) continue;
3686
3836
  if (kind && PLACED.has(kind)) {
3687
3837
  const { flags } = stream;
3688
3838
  Fs.closeStream(fd);
@@ -3741,7 +3891,15 @@ async function runWasmProcess(init, port2, deps = {}) {
3741
3891
  }
3742
3892
  }
3743
3893
  );
3744
- const transport = signals.transport();
3894
+ const gated = signals.transport();
3895
+ let early = () => {
3896
+ };
3897
+ const transport = {
3898
+ call: (req, timeoutMs, label) => {
3899
+ if (!FS_OPS.has(req.op)) early();
3900
+ return gated.call(req, timeoutMs, label);
3901
+ }
3902
+ };
3745
3903
  const sys = kernelSys(transport);
3746
3904
  const encoder3 = new TextEncoder();
3747
3905
  const say = (fd) => (text) => sys.write(fd, encoder3.encode(`${text}
@@ -3780,6 +3938,11 @@ async function runWasmProcess(init, port2, deps = {}) {
3780
3938
  }
3781
3939
  });
3782
3940
  liveParent(imports, () => identify(transport, init).ppid);
3941
+ kernelUmask(imports, {
3942
+ initial: init.umask ?? 18,
3943
+ memory: () => memory,
3944
+ set: (mask) => void transport.call({ op: "proc-umask", mask }, Number.POSITIVE_INFINITY, "umask")
3945
+ });
3783
3946
  noFollowUtimes(
3784
3947
  imports,
3785
3948
  () => ownValue(module, "FS"),
@@ -3827,6 +3990,7 @@ async function runWasmProcess(init, port2, deps = {}) {
3827
3990
  cwd: init.cwd,
3828
3991
  warn: deps.warn ?? say(2)
3829
3992
  });
3993
+ early = () => signals.quiet(() => vfs.flushDirty());
3830
3994
  const sigpipe = () => running.sliccSigpipe?.() === 1;
3831
3995
  const restartable = () => signals.restartable();
3832
3996
  const streams = new KernelStreams(running.FS, sys, { sigpipe, restartable });
@@ -3920,7 +4084,7 @@ function runMain(running, init) {
3920
4084
  return status2;
3921
4085
  }
3922
4086
  }
3923
- var O_RDONLY, O_WRONLY3, O_RDWR3, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
4087
+ var FS_OPS, O_RDONLY, O_WRONLY3, O_RDWR3, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
3924
4088
  var init_process_runtime = __esm({
3925
4089
  "src/process/process-runtime.ts"() {
3926
4090
  "use strict";
@@ -3928,6 +4092,7 @@ var init_process_runtime = __esm({
3928
4092
  init_signals();
3929
4093
  init_emscripten_vfs_hook();
3930
4094
  init_live_vfs_fs();
4095
+ init_sync_fs_wire();
3931
4096
  init_sync_sab_bridge();
3932
4097
  init_sync_sab_wire();
3933
4098
  init_kernel_streams();
@@ -3940,6 +4105,7 @@ var init_process_runtime = __esm({
3940
4105
  init_procfs();
3941
4106
  init_realm_user();
3942
4107
  init_kernel_streams();
4108
+ FS_OPS = new Set(SYNC_FS_OPS);
3943
4109
  O_RDONLY = 0;
3944
4110
  O_WRONLY3 = 1;
3945
4111
  O_RDWR3 = 2;
@@ -5077,8 +5243,9 @@ function filestatOf(path, s) {
5077
5243
  function kernelFiletype(kind) {
5078
5244
  switch (kind) {
5079
5245
  case "tty":
5080
- case "device":
5081
5246
  return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: false };
5247
+ case "device":
5248
+ return { filetype: FILETYPE.CHARACTER_DEVICE, seeks: true };
5082
5249
  case "socket":
5083
5250
  return { filetype: FILETYPE.SOCKET_STREAM, seeks: false };
5084
5251
  case "file":
@@ -5116,7 +5283,7 @@ function wrap(table) {
5116
5283
  }
5117
5284
  return out;
5118
5285
  }
5119
- var WasiExit, NS_PER_MS, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
5286
+ var WasiExit, NS_PER_MS, AT_SYMLINK_NOFOLLOW2, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, WasiHost;
5120
5287
  var init_wasi_host = __esm({
5121
5288
  "src/process/wasi/wasi-host.ts"() {
5122
5289
  "use strict";
@@ -5133,6 +5300,8 @@ var init_wasi_host = __esm({
5133
5300
  }
5134
5301
  };
5135
5302
  NS_PER_MS = 1000000n;
5303
+ AT_SYMLINK_NOFOLLOW2 = 1;
5304
+ DEFAULT_UMASK = 18;
5136
5305
  MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS;
5137
5306
  MAX_READ = 1024 * 1024;
5138
5307
  SIGPIPE_EXIT = 141;
@@ -5173,6 +5342,43 @@ var init_wasi_host = __esm({
5173
5342
  get cwd() {
5174
5343
  return this.fds.cwd() ?? this.startCwd;
5175
5344
  }
5345
+ created(path, mode) {
5346
+ const umask = this.o.kernel.call({ op: "proc-umask" });
5347
+ if (umask !== DEFAULT_UMASK) this.o.fs.chmod(path, mode & ~umask);
5348
+ }
5349
+ sliccFsImports() {
5350
+ const { mem, fds } = this;
5351
+ const at = (dirfd, p, l) => fds.resolve(dirfd, mem.string(p, l));
5352
+ const pathOf = (fd) => {
5353
+ const e = fds.get(fd);
5354
+ if (e.type === "dir") return e.path;
5355
+ if (e.type === "file") return e.file.path;
5356
+ const path = e.type === "kernel" && fds.kind(fd, e) === "file" ? this.kernelStat(fd).path : void 0;
5357
+ if (path === void 0) throw new WasiError("EBADF");
5358
+ return path;
5359
+ };
5360
+ const target = (path, flags) => {
5361
+ if (flags & AT_SYMLINK_NOFOLLOW2 && this.o.fs.lstat(path).isSymbolicLink) {
5362
+ throw new WasiError("ENOTSUP");
5363
+ }
5364
+ return path;
5365
+ };
5366
+ const modeOf = (st) => (st.mode ?? 0) & 4095;
5367
+ return wrap({
5368
+ fd_chmod: (fd, mode) => void this.o.fs.chmod(pathOf(fd), mode & 4095),
5369
+ path_chmod: (dirfd, p, l, mode, flags) => void this.o.fs.chmod(target(at(dirfd, p, l), flags), mode & 4095),
5370
+ umask: (mask, out) => {
5371
+ const old = this.o.kernel.call({ op: "proc-umask", mask });
5372
+ mem.view().setUint32(out, old, true);
5373
+ },
5374
+ fd_mode: (fd, out) => void mem.view().setUint32(out, modeOf(this.o.fs.stat(pathOf(fd))), true),
5375
+ path_mode: (dirfd, p, l, flags, out) => {
5376
+ const path = at(dirfd, p, l);
5377
+ const st = flags & AT_SYMLINK_NOFOLLOW2 ? this.o.fs.lstat(path) : this.o.fs.stat(path);
5378
+ mem.view().setUint32(out, modeOf(st), true);
5379
+ }
5380
+ });
5381
+ }
5176
5382
  sliccImports() {
5177
5383
  const { mem } = this;
5178
5384
  const path = (p, l) => {
@@ -5322,7 +5528,12 @@ var init_wasi_host = __esm({
5322
5528
  const { mem, fds, o } = this;
5323
5529
  const at = (dirfd, p, l) => fds.resolve(dirfd, mem.string(p, l));
5324
5530
  return {
5325
- path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => void mem.view().setUint32(out, fds.open(at(dirfd, p, l), oflags, rights, fdflags), true),
5531
+ path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
5532
+ const path = at(dirfd, p, l);
5533
+ const fresh = (oflags & OFLAGS.CREAT) !== 0 && !o.fs.exists(path);
5534
+ mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
5535
+ if (fresh) this.created(path, 438);
5536
+ },
5326
5537
  path_filestat_get: (dirfd, lookup, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup)),
5327
5538
  path_filestat_set_times: (dirfd, lookup, p, l, atim, mtim, flags) => {
5328
5539
  const path = at(dirfd, p, l);
@@ -5333,6 +5544,7 @@ var init_wasi_host = __esm({
5333
5544
  const path = at(dirfd, p, l);
5334
5545
  if (o.fs.exists(path)) throw new WasiError("EEXIST");
5335
5546
  o.fs.mkdir(path);
5547
+ this.created(path, 511);
5336
5548
  },
5337
5549
  path_remove_directory: (dirfd, p, l) => void o.fs.rmdir(at(dirfd, p, l)),
5338
5550
  path_unlink_file: (dirfd, p, l) => {
@@ -5482,7 +5694,9 @@ var init_wasi_host = __esm({
5482
5694
  seek(fd, offset, whence) {
5483
5695
  const e = this.fds.get(fd);
5484
5696
  if (e.type === "kernel") {
5485
- if (this.fds.kind(fd, e) !== "file") throw new WasiError("ESPIPE");
5697
+ const kind = this.fds.kind(fd, e);
5698
+ if (kind === "device") return 0;
5699
+ if (kind !== "file") throw new WasiError("ESPIPE");
5486
5700
  return this.o.kernel.sys.seek(fd, offset, whence);
5487
5701
  }
5488
5702
  if (e.type === "device") return 0;
@@ -7426,14 +7640,15 @@ function unsupportedImport(module, memory, extended = false, foreign = {}) {
7426
7640
  }
7427
7641
  return void 0;
7428
7642
  }
7429
- function linkImports(module, preview1, wasix, memory, threads, program = {}, foreign, slicc = {}) {
7643
+ function linkImports(module, preview1, wasix, memory, threads, program = {}, foreign, slicc = {}, sliccFs = {}) {
7430
7644
  for (const ns of Object.keys(program)) {
7431
- if (RESERVED2.has(ns) || ns === SLICC)
7645
+ if (RESERVED2.has(ns) || ns === SLICC || ns === SLICC_FS)
7432
7646
  throw new Error(`the imports module may not define ${ns}`);
7433
7647
  }
7434
7648
  const imports = {
7435
7649
  ...program,
7436
7650
  [SLICC]: { ...slicc },
7651
+ [SLICC_FS]: { ...sliccFs },
7437
7652
  [PREVIEW1]: preview1,
7438
7653
  ...wasix ? { [WASIX]: { ...wasix } } : {},
7439
7654
  ...threads ? { wasi: { "thread-spawn": (arg) => threads.spawn(arg) } } : {}
@@ -7560,7 +7775,18 @@ async function instantiate(host, module, memory, threads, {
7560
7775
  () => instance
7561
7776
  );
7562
7777
  const slicc = traced(stats, "slicc", host.sliccImports());
7563
- const hostImports = linkImports(module, preview1, wasix, memory, threads, extra, foreign, slicc);
7778
+ const sliccFs = traced(stats, "slicc_fs", host.sliccFsImports());
7779
+ const hostImports = linkImports(
7780
+ module,
7781
+ preview1,
7782
+ wasix,
7783
+ memory,
7784
+ threads,
7785
+ extra,
7786
+ foreign,
7787
+ slicc,
7788
+ sliccFs
7789
+ );
7564
7790
  const imports = sync ? merge(hostImports, sync.linker.mainImports(module)) : hostImports;
7565
7791
  instance = await WebAssembly.instantiate(module, imports);
7566
7792
  stats?.phase("instantiate");
@@ -7750,7 +7976,7 @@ async function runWasiThread(init, port2) {
7750
7976
  throw e;
7751
7977
  }
7752
7978
  }
7753
- var TRAPPED, PREVIEW1, WASIX, SLICC, RESERVED2, noErrno, FALLBACK_MAXIMUM_PAGES, LinkSync, DL_GEN, BACKTRACE_FRAMES;
7979
+ var TRAPPED, PREVIEW1, WASIX, SLICC, SLICC_FS, RESERVED2, noErrno, FALLBACK_MAXIMUM_PAGES, LinkSync, DL_GEN, BACKTRACE_FRAMES;
7754
7980
  var init_wasi_runtime = __esm({
7755
7981
  "src/process/wasi/wasi-runtime.ts"() {
7756
7982
  "use strict";
@@ -7776,6 +8002,7 @@ var init_wasi_runtime = __esm({
7776
8002
  PREVIEW1 = "wasi_snapshot_preview1";
7777
8003
  WASIX = "wasix_32v1";
7778
8004
  SLICC = "slicc";
8005
+ SLICC_FS = "slicc_fs";
7779
8006
  RESERVED2 = RESERVED_NAMESPACES;
7780
8007
  noErrno = (key) => `imports ${key}: its result cannot carry ENOSYS, and this host does not provide it`;
7781
8008
  FALLBACK_MAXIMUM_PAGES = 32768;