@ai-ecoverse/slicc-kernel 1.29.1 → 1.30.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.
@@ -694,6 +694,22 @@ function createHelpers(Fs, ops) {
694
694
  function createNodeOps(h) {
695
695
  const { Fs, bridgeOf, call: call2, metadataCall, makeNode, statOf, childPath, flushNode, truncate } = h;
696
696
  const { ensureLoaded } = h;
697
+ const setTimes = (node, path, atime, mtime) => {
698
+ if (Fs.isLink(node.mode)) {
699
+ metadataCall(() => bridgeOf(node).lutimes(path, atime, mtime));
700
+ return;
701
+ }
702
+ flushNode(node);
703
+ metadataCall(() => bridgeOf(node).utimes(path, atime, mtime));
704
+ };
705
+ const timesOf = (node, attr2) => {
706
+ const mtime = toMs(attr2.mtime) ?? attr2.timestamp;
707
+ const atime = toMs(attr2.atime);
708
+ if (mtime !== void 0 && attr2.atime !== null) return [atime ?? mtime, mtime];
709
+ if (atime === void 0 && mtime === void 0) return void 0;
710
+ const st = statOf(node);
711
+ return [atime ?? st.atimeMs ?? st.mtimeMs ?? 0, mtime ?? st.mtimeMs ?? 0];
712
+ };
697
713
  return {
698
714
  getattr(node) {
699
715
  const st = statOf(node);
@@ -735,12 +751,8 @@ function createNodeOps(h) {
735
751
  if (attr2.size !== void 0 && attr2.size !== null && Fs.isFile(node.mode)) {
736
752
  truncate(node, attr2.size);
737
753
  }
738
- const mtime = toMs(attr2.mtime) ?? attr2.timestamp;
739
- if (mtime !== void 0) {
740
- const atime = toMs(attr2.atime) ?? mtime;
741
- flushNode(node);
742
- metadataCall(() => bridgeOf(node).utimes(path, atime, mtime));
743
- }
754
+ const times = timesOf(node, attr2);
755
+ if (times) setTimes(node, path, ...times);
744
756
  node.live.stat = void 0;
745
757
  },
746
758
  lookup(parent, name) {
@@ -1451,6 +1463,9 @@ function createSyncFsSabBridge(transport, opts = {}) {
1451
1463
  utimes: (path, atimeMs, mtimeMs) => {
1452
1464
  run({ op: "utimes", path, atimeMs, mtimeMs }, path);
1453
1465
  },
1466
+ lutimes: (path, atimeMs, mtimeMs) => {
1467
+ run({ op: "lutimes", path, atimeMs, mtimeMs }, path);
1468
+ },
1454
1469
  hold: (path, held) => {
1455
1470
  run({ op: "hold", path, mode: held ? 1 : 0 }, path);
1456
1471
  },
@@ -2267,6 +2282,32 @@ function wrapCloexecSyscalls(imports, glue, deps) {
2267
2282
  }
2268
2283
  }
2269
2284
  }
2285
+ function noFollowUtimes(imports, fs, glue) {
2286
+ for (const namespace of namespaces(imports)) {
2287
+ const key = Object.keys(namespace).find(
2288
+ (name) => glue !== void 0 && namespace[name] === glue || name === "__syscall_utimensat"
2289
+ );
2290
+ const utimensat = key === void 0 ? void 0 : namespace[key];
2291
+ if (key === void 0 || typeof utimensat !== "function") continue;
2292
+ namespace[key] = (dirfd, path, times, flags) => {
2293
+ const Fs = fs();
2294
+ const { utime, lookupPath, ErrnoError } = Fs ?? {};
2295
+ if (!Fs || !(flags & AT_SYMLINK_NOFOLLOW) || !utime || !lookupPath || !ErrnoError) {
2296
+ return utimensat(dirfd, path, times, flags);
2297
+ }
2298
+ Fs.utime = (at, atime, mtime) => {
2299
+ const { node } = lookupPath.call(Fs, at, { follow: false });
2300
+ if (!node.node_ops.setattr) throw new ErrnoError(EMSCRIPTEN_EPERM);
2301
+ node.node_ops.setattr(node, { atime, mtime });
2302
+ };
2303
+ try {
2304
+ return utimensat(dirfd, path, times, flags);
2305
+ } finally {
2306
+ Fs.utime = utime;
2307
+ }
2308
+ };
2309
+ }
2310
+ }
2270
2311
  function errnoOf(err) {
2271
2312
  const { errno: errno2, code: code2 } = err ?? {};
2272
2313
  if (typeof errno2 === "number") return errno2;
@@ -2515,7 +2556,7 @@ function useMounts(Fs, env = {}, live = false) {
2515
2556
  }
2516
2557
  };
2517
2558
  }
2518
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, DIR_MODE, LINK_MODE, O_ACCMODE, O_CREAT2, field, NAME;
2559
+ 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, DIR_MODE, LINK_MODE, O_ACCMODE, O_CREAT2, field, NAME;
2519
2560
  var init_process_fds = __esm({
2520
2561
  "src/process/process-fds.ts"() {
2521
2562
  "use strict";
@@ -2540,6 +2581,8 @@ var init_process_fds = __esm({
2540
2581
  setitimer: "_setitimer_js"
2541
2582
  };
2542
2583
  EBADF = 8;
2584
+ AT_SYMLINK_NOFOLLOW = 256;
2585
+ EMSCRIPTEN_EPERM = 63;
2543
2586
  DIR_MODE = 16749;
2544
2587
  LINK_MODE = 41408;
2545
2588
  O_ACCMODE = 3;
@@ -3554,6 +3597,11 @@ async function runWasmProcess(init, port, deps = {}) {
3554
3597
  }
3555
3598
  });
3556
3599
  liveParent(imports, () => identify(transport, init).ppid);
3600
+ noFollowUtimes(
3601
+ imports,
3602
+ () => ownValue(module, "FS"),
3603
+ ownValue(module, "sliccSyscalls")?.utimensat
3604
+ );
3557
3605
  const glue = ownValue(module, "sliccFdImports");
3558
3606
  syncFsync(imports, () => ownValue(module, "FS"), glue);
3559
3607
  positionalIo(imports, {
@@ -3902,6 +3950,7 @@ function cachingBridge(bridge, now = () => performance.now()) {
3902
3950
  symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
3903
3951
  chmod: (p, mode) => mutating(() => bridge.chmod(p, mode)),
3904
3952
  utimes: (p, a, m) => mutating(() => bridge.utimes(p, a, m)),
3953
+ lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m)),
3905
3954
  ...bridge.pread && bridge.pwrite && bridge.truncate ? {
3906
3955
  pread: bridge.pread.bind(bridge),
3907
3956
  pwrite: (p, at, bytes, transfer) => mutating(() => bridge.pwrite?.(p, at, bytes, transfer)),
@@ -4107,18 +4156,20 @@ function kernelEntry2() {
4107
4156
  function deviceEntry(meta) {
4108
4157
  return { type: "device", device: meta.device, ...meta.access ? { access: meta.access } : {} };
4109
4158
  }
4159
+ function preopenOf(e) {
4160
+ return {
4161
+ ...e.preopen ? { preopen: e.preopen } : {},
4162
+ ...e.twin !== void 0 ? { twin: e.twin } : {}
4163
+ };
4164
+ }
4110
4165
  function metaOf(e) {
4111
- if (e.type === "dir") return { dir: e.path, ...e.preopen ? { preopen: e.preopen } : {} };
4166
+ if (e.type === "dir") return { dir: e.path, ...preopenOf(e) };
4112
4167
  if (e.type === "device") return { device: e.device, ...e.access ? { access: e.access } : {} };
4113
4168
  return void 0;
4114
4169
  }
4115
4170
  function entryOf(info) {
4116
4171
  if (info.meta && "dir" in info.meta) {
4117
- return {
4118
- type: "dir",
4119
- path: info.meta.dir,
4120
- ...info.meta.preopen ? { preopen: info.meta.preopen } : {}
4121
- };
4172
+ return { type: "dir", path: info.meta.dir, ...preopenOf(info.meta) };
4122
4173
  }
4123
4174
  if (info.meta && "device" in info.meta) return deviceEntry(info.meta);
4124
4175
  if (info.kind === "held") return void 0;
@@ -4178,9 +4229,9 @@ var init_wasi_fds = __esm({
4178
4229
  this.kernel = kernel;
4179
4230
  this.fs = fs;
4180
4231
  }
4181
- setup(cwd, inherited) {
4232
+ setup(cwd, inherited, root = false) {
4182
4233
  for (const fd of [0, 1, 2]) this.table.set(fd, kernelEntry2());
4183
- const preopens = this.preopens(cwd);
4234
+ const preopens = this.preopens(cwd, root);
4184
4235
  const top = 3 + preopens.length;
4185
4236
  for (const { fd, kind, flags, device } of inherited) {
4186
4237
  let at = fd;
@@ -4200,8 +4251,10 @@ var init_wasi_fds = __esm({
4200
4251
  this.table.set(3 + i, entry);
4201
4252
  });
4202
4253
  }
4203
- preopens(cwd) {
4204
- const out = [{ type: "dir", path: normalize(cwd), preopen: "." }];
4254
+ preopens(cwd, root) {
4255
+ const here = normalize(cwd);
4256
+ const dot = { type: "dir", path: here, preopen: "." };
4257
+ const out = [dot];
4205
4258
  let names = [];
4206
4259
  try {
4207
4260
  names = this.fs.readdir("/");
@@ -4219,6 +4272,13 @@ var init_wasi_fds = __esm({
4219
4272
  } catch {
4220
4273
  }
4221
4274
  }
4275
+ if (root) {
4276
+ out.push(
4277
+ { type: "dir", path: "/", preopen: "/" },
4278
+ { type: "dir", path: here, preopen: "./" }
4279
+ );
4280
+ dot.twin = 3 + out.length - 1;
4281
+ }
4222
4282
  return out;
4223
4283
  }
4224
4284
  find(fd) {
@@ -4370,8 +4430,13 @@ var init_wasi_fds = __esm({
4370
4430
  chdir(path) {
4371
4431
  const dot = this.find(3);
4372
4432
  if (dot?.type !== "dir" || dot.preopen !== ".") return;
4373
- dot.path = path;
4374
- this.kernel.call({ op: "fd-meta", fd: 3, meta: { dir: path, preopen: "." } });
4433
+ const moved = [[3, dot]];
4434
+ const twin = dot.twin === void 0 ? void 0 : this.find(dot.twin);
4435
+ if (twin?.type === "dir" && twin.preopen === "./") moved.push([dot.twin, twin]);
4436
+ for (const [fd, e] of moved) {
4437
+ e.path = path;
4438
+ this.kernel.call({ op: "fd-meta", fd, meta: metaOf(e) });
4439
+ }
4375
4440
  this.bump();
4376
4441
  }
4377
4442
  promoteFiles() {
@@ -4399,8 +4464,7 @@ var init_wasi_fds = __esm({
4399
4464
  for (const [fd, e] of this.table) {
4400
4465
  if (e.type === "kernel")
4401
4466
  out.push({ fd, type: "kernel", nonblock: e.nonblock, append: e.append });
4402
- else if (e.type === "dir")
4403
- out.push({ fd, type: "dir", path: e.path, ...e.preopen ? { preopen: e.preopen } : {} });
4467
+ else if (e.type === "dir") out.push({ fd, type: "dir", path: e.path, ...preopenOf(e) });
4404
4468
  else if (e.type === "device") out.push({ fd, ...deviceEntry(e) });
4405
4469
  }
4406
4470
  return out;
@@ -4411,11 +4475,7 @@ var init_wasi_fds = __esm({
4411
4475
  if (f.type === "kernel")
4412
4476
  this.table.set(f.fd, { type: "kernel", nonblock: f.nonblock, append: f.append });
4413
4477
  else if (f.type === "dir")
4414
- this.table.set(f.fd, {
4415
- type: "dir",
4416
- path: f.path,
4417
- ...f.preopen ? { preopen: f.preopen } : {}
4418
- });
4478
+ this.table.set(f.fd, { type: "dir", path: f.path, ...preopenOf(f) });
4419
4479
  else this.table.set(f.fd, deviceEntry(f));
4420
4480
  }
4421
4481
  for (const fd of cloexec) this.cloexec.add(fd);
@@ -4877,7 +4937,7 @@ var init_wasi_host = __esm({
4877
4937
  this.fds = new WasiFds(o.kernel, o.fs);
4878
4938
  if (o.shared) this.fds.share(o.shared, true);
4879
4939
  else if (o.forked) this.fds.restore(o.forked.fds, o.forked.cloexec);
4880
- else this.fds.setup(o.cwd, o.inherited ?? []);
4940
+ else this.fds.setup(o.cwd, o.inherited ?? [], o.preopenRoot === true);
4881
4941
  this.listening = o.shared ? [] : this.fds.sockets();
4882
4942
  }
4883
4943
  get cwd() {
@@ -5034,10 +5094,10 @@ var init_wasi_host = __esm({
5034
5094
  return {
5035
5095
  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),
5036
5096
  path_filestat_get: (dirfd, lookup, p, l, out) => void this.writeFilestat(out, this.pathFilestat(at(dirfd, p, l), lookup)),
5037
- path_filestat_set_times: (dirfd, _lookup, p, l, atim, mtim, flags) => {
5097
+ path_filestat_set_times: (dirfd, lookup, p, l, atim, mtim, flags) => {
5038
5098
  const path = at(dirfd, p, l);
5039
5099
  fds.flushPath(path);
5040
- this.setTimes(path, atim, mtim, flags);
5100
+ this.setTimes(path, atim, mtim, flags, (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0);
5041
5101
  },
5042
5102
  path_create_directory: (dirfd, p, l) => {
5043
5103
  const path = at(dirfd, p, l);
@@ -5270,15 +5330,20 @@ var init_wasi_host = __esm({
5270
5330
  const follow = (lookup & LOOKUP_SYMLINK_FOLLOW) !== 0;
5271
5331
  return filestatOf(path, follow ? this.o.fs.stat(path) : this.o.fs.lstat(path));
5272
5332
  }
5273
- setTimes(path, atim, mtim, flags) {
5333
+ setTimes(path, atim, mtim, flags, follow = true) {
5274
5334
  const now = Date.now();
5275
5335
  let current;
5276
- const kept = () => current ??= this.o.fs.stat(path).mtimeMs ?? now;
5277
- const pick = (set, setNow, value2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS) : kept();
5278
- this.o.fs.utimes(
5336
+ const statOf = follow ? this.o.fs.stat.bind(this.o.fs) : this.o.fs.lstat.bind(this.o.fs);
5337
+ const kept = (field2) => {
5338
+ current ??= statOf(path);
5339
+ return current[field2] ?? current.mtimeMs ?? now;
5340
+ };
5341
+ const pick = (set, setNow, value2, field2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS) : kept(field2);
5342
+ (follow ? this.o.fs.utimes : this.o.fs.lutimes).call(
5343
+ this.o.fs,
5279
5344
  path,
5280
- pick(FSTFLAGS.ATIM, FSTFLAGS.ATIM_NOW, atim),
5281
- pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim)
5345
+ pick(FSTFLAGS.ATIM, FSTFLAGS.ATIM_NOW, atim, "atimeMs"),
5346
+ pick(FSTFLAGS.MTIM, FSTFLAGS.MTIM_NOW, mtim, "mtimeMs")
5282
5347
  );
5283
5348
  }
5284
5349
  readdir(fd, buf, len, cookie, usedPtr) {
@@ -7289,6 +7354,11 @@ function merge(base, extra) {
7289
7354
  for (const [ns, values] of Object.entries(extra)) out[ns] = { ...base[ns], ...values };
7290
7355
  return out;
7291
7356
  }
7357
+ function descriptors(init, fork, threads) {
7358
+ if (fork?.shared && threads) return { shared: threads.ids };
7359
+ if (fork) return { forked: { fds: fork.fds, cloexec: fork.cloexec } };
7360
+ return { inherited: init.fds ?? [], ...init.program.preopenRoot ? { preopenRoot: true } : {} };
7361
+ }
7292
7362
  async function runWasiProcess(init, port) {
7293
7363
  captureBacktraces(init.env);
7294
7364
  const signals = new WasiSignals((sig) => {
@@ -7323,7 +7393,7 @@ async function runWasiProcess(init, port) {
7323
7393
  parent: () => identify(transport, init).ppid,
7324
7394
  kernel: { sys: traced(stats, "kernel", sys), call: call2 },
7325
7395
  fs: cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
7326
- ...fork?.shared && threads ? { shared: threads.ids } : fork ? { forked: { fds: fork.fds, cloexec: fork.cloexec } } : { inherited: init.fds }
7396
+ ...descriptors(init, fork, threads)
7327
7397
  });
7328
7398
  if (threads) {
7329
7399
  threads.beforeSpawn = () => {