@ai-ecoverse/slicc-kernel 1.54.1 → 1.54.3

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.
@@ -1022,7 +1022,7 @@ function openAccess(existing, oflags, rights) {
1022
1022
  return { readable: (rights & RIGHTS.FD_READ) !== 0n || !writable2, writable: writable2 };
1023
1023
  }
1024
1024
  function promoteRequest(fd, f, handed) {
1025
- const orphan = f.buffer.isOrphan();
1025
+ const orphan = f.buffer.isOrphan() || (f.buffer.handle ?? 0) < 0;
1026
1026
  if (!orphan && f.buffer.isRanged) f.buffer.flush();
1027
1027
  const joins = !orphan && (handed.has(f.buffer) || f.buffer.isRanged);
1028
1028
  return {
@@ -1760,7 +1760,7 @@ function readTermios(mem, ptr) {
1760
1760
  c_cc: Array.from({ length: NCCS }, (_, i) => v.getUint8(ptr + C_CC + i))
1761
1761
  };
1762
1762
  }
1763
- function sliccTty(mem, fds, kernel) {
1763
+ function sliccTty(mem, fds, kernel, interrupted = () => void 0) {
1764
1764
  const { sys } = kernel;
1765
1765
  const terminal = (fd) => {
1766
1766
  const e = fds.find(fd);
@@ -1772,13 +1772,19 @@ function sliccTty(mem, fds, kernel) {
1772
1772
  if (value2 === void 0) throw new WasiError("ENOTTY");
1773
1773
  return value2;
1774
1774
  };
1775
+ const getAttr = (fd, ptr) => {
1776
+ interrupted();
1777
+ writeTermios(mem, ptr, needs(sys.tcgets?.(terminal(fd))));
1778
+ };
1775
1779
  const setAttr = (fd, actions, ptr) => {
1780
+ interrupted();
1776
1781
  if (actions < 0 || actions > TCSAFLUSH) throw new WasiError("EINVAL");
1777
1782
  const at = terminal(fd);
1778
1783
  needs(sys.tcsets);
1779
1784
  sys.tcsets?.(at, readTermios(mem, ptr), actions === TCSAFLUSH);
1780
1785
  };
1781
1786
  const size = (fd, ptr) => {
1787
+ interrupted();
1782
1788
  const [rows, cols] = needs(sys.winsize?.(terminal(fd)));
1783
1789
  mem.bytes(ptr, 8).fill(0);
1784
1790
  const v = mem.view();
@@ -1786,7 +1792,7 @@ function sliccTty(mem, fds, kernel) {
1786
1792
  v.setUint16(ptr + 2, cols, true);
1787
1793
  };
1788
1794
  return {
1789
- tcgetattr: (fd, ptr) => void writeTermios(mem, ptr, needs(sys.tcgets?.(terminal(fd)))),
1795
+ tcgetattr: (fd, ptr) => void getAttr(fd, ptr),
1790
1796
  tcsetattr: (fd, actions, ptr) => void setAttr(fd, actions, ptr),
1791
1797
  winsize: (fd, ptr) => void size(fd, ptr)
1792
1798
  };
@@ -1935,7 +1941,7 @@ var init_wasi_host = __esm({
1935
1941
  if (umask !== DEFAULT_UMASK) this.o.fs.chmod(path, mode & ~umask);
1936
1942
  }
1937
1943
  sliccTtyImports() {
1938
- return wrap(sliccTty(this.mem, this.fds, this.o.kernel));
1944
+ return wrap(sliccTty(this.mem, this.fds, this.o.kernel, () => this.interrupted?.()));
1939
1945
  }
1940
1946
  sliccFsImports() {
1941
1947
  const { mem, fds } = this;
@@ -2156,6 +2162,7 @@ var init_wasi_host = __esm({
2156
2162
  return {
2157
2163
  path_open: (dirfd, _lookup, p, l, oflags, rights, _inheriting, fdflags, out) => {
2158
2164
  const path = at(dirfd, p, l);
2165
+ if (deviceOf(path)) this.interrupted?.();
2159
2166
  const fresh = (oflags & OFLAGS.CREAT) !== 0 && !o.fs.exists(path);
2160
2167
  mem.view().setUint32(out, fds.open(path, oflags, rights, fdflags), true);
2161
2168
  if (fresh) this.created(path, 438);
@@ -2271,7 +2278,9 @@ var init_wasi_host = __esm({
2271
2278
  }
2272
2279
  positional(fd, access) {
2273
2280
  const e = this.fds.get(fd);
2274
- if (e.type !== "kernel" || this.fds.kind(fd, e) !== "file") return this.file(fd, access);
2281
+ const kind = e.type === "kernel" ? this.fds.kind(fd, e) : e.type;
2282
+ if (kind === "device") this.interrupted?.();
2283
+ if (kind !== "file" || e.type !== "kernel") return this.file(fd, access);
2275
2284
  const kernel = this.o.kernel;
2276
2285
  return {
2277
2286
  pread: (max, at) => {
@@ -2299,6 +2308,7 @@ var init_wasi_host = __esm({
2299
2308
  }
2300
2309
  }
2301
2310
  if (e.type === "device") {
2311
+ this.interrupted?.();
2302
2312
  if (e.access === "read") throw new WasiError("EBADF");
2303
2313
  if (e.device === "full" && data.length > 0) throw new WasiError("ENOSPC");
2304
2314
  return data.length;
@@ -2311,6 +2321,7 @@ var init_wasi_host = __esm({
2311
2321
  return this.o.kernel.sys.read(fd, Math.min(max, MAX_READ), { nonblock: e.nonblock });
2312
2322
  }
2313
2323
  if (e.type === "device") {
2324
+ this.interrupted?.();
2314
2325
  if (e.access === "write") throw new WasiError("EBADF");
2315
2326
  if (e.device === "null") return new Uint8Array(0);
2316
2327
  const out = new Uint8Array(Math.min(max, 65536));
@@ -2318,15 +2329,19 @@ var init_wasi_host = __esm({
2318
2329
  }
2319
2330
  return this.file(fd, "read").read(max);
2320
2331
  }
2332
+ local(answer2) {
2333
+ this.interrupted?.();
2334
+ return answer2;
2335
+ }
2321
2336
  seek(fd, offset, whence) {
2322
2337
  const e = this.fds.get(fd);
2323
2338
  if (e.type === "kernel") {
2324
2339
  const kind = this.fds.kind(fd, e);
2325
- if (kind === "device") return 0;
2340
+ if (kind === "device") return this.local(0);
2326
2341
  if (kind !== "file") throw new WasiError("ESPIPE");
2327
2342
  return this.o.kernel.sys.seek(fd, offset, whence);
2328
2343
  }
2329
- if (e.type === "device") return 0;
2344
+ if (e.type === "device") return this.local(0);
2330
2345
  const file = this.file(fd);
2331
2346
  const base = whence === WHENCE.SET ? 0 : whence === WHENCE.CUR ? file.offset : file.size();
2332
2347
  if (whence > WHENCE.END || base + offset < 0) throw new WasiError("EINVAL");
@@ -2336,15 +2351,23 @@ var init_wasi_host = __esm({
2336
2351
  sync(fd) {
2337
2352
  const e = this.fds.get(fd);
2338
2353
  if (e.type === "file") e.file.flush();
2339
- else if (e.type === "kernel" && this.fds.kind(fd, e) === "file") this.o.kernel.sys.flush(fd);
2354
+ else if (e.type === "device") this.interrupted?.();
2355
+ else if (e.type === "kernel") {
2356
+ const kind = this.fds.kind(fd, e);
2357
+ if (kind === "file") this.o.kernel.sys.flush(fd);
2358
+ else if (kind === "device") this.interrupted?.();
2359
+ }
2340
2360
  }
2341
2361
  fdstat(fd, out) {
2342
2362
  const e = this.fds.get(fd);
2363
+ if (e.type === "device") this.interrupted?.();
2343
2364
  let filetype = FILETYPE.CHARACTER_DEVICE;
2344
2365
  let seeks = true;
2345
2366
  let flags = 0;
2346
2367
  if (e.type === "kernel") {
2347
- ({ filetype, seeks } = kernelFiletype(this.fds.kind(fd, e)));
2368
+ const kind = this.fds.kind(fd, e);
2369
+ if (kind === "device") this.interrupted?.();
2370
+ ({ filetype, seeks } = kernelFiletype(kind));
2348
2371
  if (e.nonblock) flags |= FDFLAGS.NONBLOCK;
2349
2372
  if (e.append) flags |= FDFLAGS.APPEND;
2350
2373
  } else if (e.type === "file") {
@@ -2379,7 +2402,7 @@ var init_wasi_host = __esm({
2379
2402
  if (vfs.path) return this.statOrphanable(vfs.path, vfs.size, vfs.orphan);
2380
2403
  }
2381
2404
  const filetype = kind ? kernelFiletype(kind).filetype : FILETYPE.CHARACTER_DEVICE;
2382
- return { filetype, size: 0n, ino: BigInt(fd + 1), mtimeNs: 0n };
2405
+ return this.local({ filetype, size: 0n, ino: BigInt(fd + 1), mtimeNs: 0n });
2383
2406
  }
2384
2407
  statOrphanable(path, size, orphan = false) {
2385
2408
  let s;
@@ -2396,7 +2419,12 @@ var init_wasi_host = __esm({
2396
2419
  }
2397
2420
  pathFilestat(path, lookup) {
2398
2421
  if (deviceOf(path)) {
2399
- return { filetype: FILETYPE.CHARACTER_DEVICE, size: 0n, ino: pathInode(path), mtimeNs: 0n };
2422
+ return this.local({
2423
+ filetype: FILETYPE.CHARACTER_DEVICE,
2424
+ size: 0n,
2425
+ ino: pathInode(path),
2426
+ mtimeNs: 0n
2427
+ });
2400
2428
  }
2401
2429
  this.fds.flushPath(path);
2402
2430
  const follow2 = (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0;
@@ -7560,6 +7588,7 @@ var init_process_signals = __esm({
7560
7588
  }
7561
7589
  }
7562
7590
  interrupt() {
7591
+ this.report();
7563
7592
  const header = this.header;
7564
7593
  const pending = Atomics.load(header, SAB_I_SIGNALS) | Atomics.load(header, SAB_I_TIMERS) | Atomics.load(header, SAB_I_KILLED);
7565
7594
  if (pending === 0) return false;
@@ -8684,60 +8713,201 @@ var init_wasi_module = __esm({
8684
8713
  function inProc(path) {
8685
8714
  return path === "/proc" || path.startsWith("/proc/");
8686
8715
  }
8716
+ function* procWalk(path, follow2) {
8717
+ let done = [];
8718
+ let todo = path.split("/").filter((part) => part !== "");
8719
+ let hops = 0;
8720
+ while (todo.length > 0) {
8721
+ const part = todo.shift();
8722
+ if (part === ".") continue;
8723
+ if (part === "..") {
8724
+ done.pop();
8725
+ continue;
8726
+ }
8727
+ const at = `/${[...done, part].join("/")}`;
8728
+ const whole = normalize(`/${[...done, part, ...todo].join("/")}`);
8729
+ if (inProc(at) && inProc(whole)) return whole;
8730
+ if (!follow2 && todo.length === 0) return void 0;
8731
+ const target = yield at;
8732
+ if (target === null) return void 0;
8733
+ if (target === void 0) done.push(part);
8734
+ else {
8735
+ if (++hops > MAX_HOPS2) return void 0;
8736
+ if (target.startsWith("/")) done = [];
8737
+ todo = [...target.split("/").filter((part2) => part2 !== ""), ...todo];
8738
+ }
8739
+ }
8740
+ return void 0;
8741
+ }
8742
+ function procPath(fs, path, follow2) {
8743
+ const walk = procWalk(path, follow2);
8744
+ let step = walk.next();
8745
+ while (!step.done) {
8746
+ let target;
8747
+ try {
8748
+ target = fs.lstat(step.value).isSymbolicLink ? fs.readlink(step.value) : void 0;
8749
+ } catch {
8750
+ target = null;
8751
+ }
8752
+ step = walk.next(target);
8753
+ }
8754
+ return step.value;
8755
+ }
8756
+ function frozen(bytes) {
8757
+ const refuse = () => {
8758
+ throw syncError("EROFS", "/proc");
8759
+ };
8760
+ return {
8761
+ readFile: () => bytes,
8762
+ pread: (_p, at, n) => bytes.subarray(at, at + n),
8763
+ writeFile: refuse,
8764
+ pwrite: refuse,
8765
+ truncate: refuse
8766
+ };
8767
+ }
8687
8768
  function procfsBridge(fs, tree) {
8769
+ const toProc = (path, follow2) => procPath(fs, path, follow2);
8770
+ const shadowing = () => {
8771
+ try {
8772
+ return fs.exists("/proc");
8773
+ } catch {
8774
+ return false;
8775
+ }
8776
+ };
8777
+ const via = (p, proc, own, follow2 = true) => {
8778
+ if (inProc(p)) return proc(p);
8779
+ if (shadowing()) {
8780
+ const real = toProc(p, follow2);
8781
+ if (real !== void 0) return proc(real);
8782
+ }
8783
+ try {
8784
+ return own();
8785
+ } catch (err) {
8786
+ const real = toProc(p, follow2);
8787
+ if (real === void 0) throw err;
8788
+ return proc(real);
8789
+ }
8790
+ };
8791
+ const readOnly = (paths, run) => {
8792
+ const physical = shadowing();
8793
+ for (const [p, follow2] of paths) {
8794
+ if (inProc(p) || physical && toProc(p, follow2) !== void 0) throw syncError("EROFS", p);
8795
+ }
8796
+ return run();
8797
+ };
8798
+ const snapshots = /* @__PURE__ */ new Map();
8799
+ let lastSnapshot = 0;
8800
+ const snapshot = (q) => {
8801
+ lastSnapshot--;
8802
+ snapshots.set(lastSnapshot, tree.read(q));
8803
+ return lastSnapshot;
8804
+ };
8805
+ const late = (p) => {
8806
+ const q = toProc(p, true);
8807
+ return q === void 0 ? void 0 : snapshot(q);
8808
+ };
8688
8809
  const over = {
8689
- readFile: (p) => inProc(p) ? tree.read(p) : fs.readFile(p),
8690
- stat: (p) => inProc(p) ? tree.stat(p) : fs.stat(p),
8691
- lstat: (p) => inProc(p) ? tree.stat(p, false) : fs.lstat(p),
8692
- readdir: (p) => {
8693
- if (inProc(p)) return tree.readdir(p);
8694
- const names = fs.readdir(p);
8695
- return p === "/" && !names.includes("proc") ? [...names, "proc"] : names;
8696
- },
8697
- exists: (p) => inProc(p) ? tree.exists(p) : fs.exists(p),
8698
- readlink: (p) => inProc(p) ? tree.readlink(p) : fs.readlink(p),
8699
- readdirStat: (p) => {
8700
- if (!inProc(p)) {
8701
- const listed = fs.readdirStat(p);
8702
- if (p !== "/" || listed.some(([name2]) => name2 === "proc")) return listed;
8703
- return [...listed, ["proc", tree.stat("/proc")]];
8810
+ readFile: (p) => via(
8811
+ p,
8812
+ (q) => tree.read(q),
8813
+ () => fs.readFile(p)
8814
+ ),
8815
+ stat: (p) => via(
8816
+ p,
8817
+ (q) => tree.stat(q),
8818
+ () => fs.stat(p)
8819
+ ),
8820
+ lstat: (p) => via(
8821
+ p,
8822
+ (q) => tree.stat(q, false),
8823
+ () => fs.lstat(p),
8824
+ false
8825
+ ),
8826
+ readdir: (p) => via(
8827
+ p,
8828
+ (q) => tree.readdir(q),
8829
+ () => {
8830
+ const names = fs.readdir(p);
8831
+ return p === "/" && !names.includes("proc") ? [...names, "proc"] : names;
8704
8832
  }
8705
- return tree.readdir(p).map((name2) => {
8833
+ ),
8834
+ exists: (p) => {
8835
+ if (inProc(p)) return tree.exists(p);
8836
+ const real = shadowing() ? toProc(p, true) : void 0;
8837
+ if (real !== void 0) return tree.exists(real);
8838
+ if (fs.exists(p)) return true;
8839
+ const late2 = toProc(p, true);
8840
+ return late2 !== void 0 && tree.exists(late2);
8841
+ },
8842
+ readlink: (p) => via(
8843
+ p,
8844
+ (q) => tree.readlink(q),
8845
+ () => fs.readlink(p),
8846
+ false
8847
+ ),
8848
+ readdirStat: (p) => via(
8849
+ p,
8850
+ (q) => tree.readdir(q).map((name2) => {
8706
8851
  try {
8707
- return [name2, tree.stat(`${p}/${name2}`, false)];
8852
+ return [name2, tree.stat(`${q}/${name2}`, false)];
8708
8853
  } catch {
8709
8854
  return [name2, null];
8710
8855
  }
8711
- });
8856
+ }),
8857
+ () => {
8858
+ const listed = fs.readdirStat(p);
8859
+ if (p !== "/" || listed.some(([name2]) => name2 === "proc")) return listed;
8860
+ return [...listed, ["proc", tree.stat("/proc")]];
8861
+ }
8862
+ ),
8863
+ rename: (from, to) => readOnly(
8864
+ [
8865
+ [from, false],
8866
+ [to, false]
8867
+ ],
8868
+ () => fs.rename(from, to)
8869
+ ),
8870
+ symlink: (target, link) => readOnly([[link, false]], () => fs.symlink(target, link)),
8871
+ hold: (p, held, open, handle) => {
8872
+ if (handle !== void 0 && snapshots.delete(handle)) return void 0;
8873
+ if (!held) return fs.hold?.(p, held, open, handle);
8874
+ return via(p, snapshot, () => fs.hold?.(p, held, open) ?? late(p));
8712
8875
  },
8713
- rename: (from, to) => {
8714
- if (inProc(from) || inProc(to)) throw syncError("EROFS", from);
8715
- fs.rename(from, to);
8876
+ kept: (handle) => snapshots.has(handle) || fs.kept?.(handle) === true,
8877
+ pinned: (handle) => {
8878
+ const bytes = snapshots.get(handle);
8879
+ return bytes ? frozen(bytes) : fs.pinned?.(handle) ?? fs;
8716
8880
  },
8717
- hold: (p, ...rest2) => inProc(p) ? void 0 : fs.hold?.(p, ...rest2),
8718
8881
  ...fs.pread ? {
8719
- pread: (p, at, n, version) => inProc(p) ? tree.read(p).subarray(at, at + n) : fs.pread(p, at, n, version)
8882
+ pread: (p, at, n, version) => via(
8883
+ p,
8884
+ (q) => tree.read(q).subarray(at, at + n),
8885
+ () => fs.pread(p, at, n, version)
8886
+ )
8720
8887
  } : {}
8721
8888
  };
8722
- for (const name2 of READ_ONLY) {
8723
- const fn = fs[name2];
8724
- if (!fn) continue;
8725
- over[name2] = (p, ...rest2) => {
8726
- if (inProc(p)) throw syncError("EROFS", p);
8727
- return fn.call(fs, p, ...rest2);
8728
- };
8889
+ for (const [names, follow2] of [
8890
+ [FOLLOWING, true],
8891
+ [NOT_FOLLOWING, false]
8892
+ ]) {
8893
+ for (const name2 of names) {
8894
+ const fn = fs[name2];
8895
+ if (!fn) continue;
8896
+ over[name2] = (p, ...rest2) => readOnly([[p, follow2]], () => fn.call(fs, p, ...rest2));
8897
+ }
8729
8898
  }
8730
8899
  return new Proxy(fs, {
8731
8900
  get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
8732
8901
  });
8733
8902
  }
8734
- var DIR_MODE3, FILE_MODE2, LINK_MODE3, PID_NAMES, SYSTEM_NAMES, ProcTree, READ_ONLY;
8903
+ var DIR_MODE3, FILE_MODE2, LINK_MODE3, PID_NAMES, SYSTEM_NAMES, ProcTree, FOLLOWING, NOT_FOLLOWING, MAX_HOPS2;
8735
8904
  var init_wasi_procfs = __esm({
8736
8905
  "src/process/wasi/wasi-procfs.ts"() {
8737
8906
  "use strict";
8738
8907
  init_sync_fs_wire();
8739
8908
  init_process_fds();
8740
8909
  init_procfs();
8910
+ init_wasi_files();
8741
8911
  DIR_MODE3 = 16749;
8742
8912
  FILE_MODE2 = 33060;
8743
8913
  LINK_MODE3 = 41471;
@@ -8848,20 +9018,9 @@ var init_wasi_procfs = __esm({
8848
9018
  }
8849
9019
  }
8850
9020
  };
8851
- READ_ONLY = [
8852
- "writeFile",
8853
- "mkdir",
8854
- "rm",
8855
- "unlink",
8856
- "rmdir",
8857
- "symlink",
8858
- "chmod",
8859
- "utimes",
8860
- "lutimes",
8861
- "create",
8862
- "pwrite",
8863
- "truncate"
8864
- ];
9021
+ FOLLOWING = ["writeFile", "chmod", "utimes", "pwrite", "truncate"];
9022
+ NOT_FOLLOWING = ["mkdir", "rm", "unlink", "rmdir", "lutimes", "create"];
9023
+ MAX_HOPS2 = 40;
8865
9024
  }
8866
9025
  });
8867
9026
 
@@ -10675,6 +10834,7 @@ var init_wasix_host = __esm({
10675
10834
  }
10676
10835
  ttyGet(ptr) {
10677
10836
  const { host, mem } = this;
10837
+ host.interrupted?.();
10678
10838
  const v = mem.view();
10679
10839
  mem.bytes(ptr, 24).fill(0);
10680
10840
  const fd = this.ttyFd();
@@ -10694,6 +10854,7 @@ var init_wasix_host = __esm({
10694
10854
  v.setUint8(ptr + 20, termios && termios.c_lflag & ICANON2 ? 1 : 0);
10695
10855
  }
10696
10856
  ttySet(ptr) {
10857
+ this.host.interrupted?.();
10697
10858
  const fd = this.ttyFd();
10698
10859
  if (fd === void 0) throw new WasiError("ENOTTY");
10699
10860
  const { sys } = this.host.o.kernel;