@ai-ecoverse/slicc-kernel 1.127.1 → 1.128.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.
package/README.md CHANGED
@@ -335,6 +335,7 @@ A WASI command can name an ES module of its package that provides imports of its
335
335
 
336
336
  - `memory()`, `instance()` (after instantiation), `tid` (1 for the main thread), `argv`, `env`, `cwd()`;
337
337
  - `fs`: the synchronous filesystem the WASI calls use (absolute paths);
338
+ - `fs.copyFile(from, to, { mode, excl })` copies a regular file inside the kernel, as `slicc_fs.path_copy_file` does (below): `mode` (default `0666`) less the umask, `excl` for `O_EXCL`. It throws the kernel's fs errors (`code` `EEXIST`, `ENOENT`, `EXDEV`, …). An older kernel's `ctx.fs` has no `copyFile`, so a module checks `typeof ctx.fs.copyFile === 'function'`;
338
339
  - `fds`: `open(path, { read, write, append, create, exclusive, truncate, directory, nofollow, mode })` returns a WASI descriptor of the program; `mode` is a new file's mode. With `create` and `exclusive` under users `report` or `enforce`, the file is created with it, less the umask, as `open(2)` does, and the name is only checked by the create itself (a symlink there is `EEXIST`). Otherwise the mode is set exactly once the file is open; `close`, `fstat` (`{ kind, path, mode, uid, gid, size, ino, mtimeMs }`; an open file's size is the descriptor's own, so writes not yet flushed count, while the other fields come from a stat of its path, as WASI's `fd_filestat_get` gives them), `fchmod`, and `tryLock(fd, exclusive)` / `unlock(fd)`: advisory locks held by the kernel across processes and threads, keyed by path, released on unlock, on closing the descriptor and at exit (`tryLock` returns 0, or 6 when another process holds the lock);
339
340
  - `syscall(req)`: a kernel syscall, synchronously;
340
341
  - `net.connect({ host, port, nonblock })` connects a TCP socket to the kernel's loopback and returns its kernel descriptor. `host` is `localhost` or `127.x.y.z`; anything else, or a port outside 1–65535, is `EINVAL`. A refused connection throws `ECONNREFUSED`. The connection carries the program's own identity, as any connect from its process does, so a [page facade](#page-facades) such as `SLICC_LINK_URL` sees the program's stamp. With `nonblock` it returns at once, and `net.ready(fd)` answers 0 once a connect is complete, `EINPROGRESS` (26) while it isn't, or the connect's WASI errno (`SO_ERROR`). On the loopback a connect completes at once, so `ready` is 0 straight away. `ready` is meant for a descriptor from `net.connect`. The descriptor is read and written with `fd-read` and `fd-write` and closed with `fd-close`, as below, and `fd-select` (`{ op: 'fd-select', read: [fds], write: [fds], timeoutMs }`, answering `{ read, write }` with the ready ones; `timeoutMs: -1` waits without a limit) waits until it's readable or writable;
@@ -832,6 +833,7 @@ WASI and WASIX have no call for file modes, so the kernel adds the import module
832
833
  | `path_filestat_owner(dirfd, lookupflags, path, path_len, filestat_out, out)` | `path_filestat_get` (with its preview1 lookup flags: `1` follows a symlink) and the owner of the same path, in one call, so a libc's `stat` costs one call either way |
833
834
  | `path_mkfifo(dirfd, path, path_len, mode)` | `mkfifo`/`mkfifoat` and `mknod(S_IFIFO)` (homescoop#878): makes a [FIFO](#filesystem) with `mode & ~umask`, relative to `dirfd` (`AT_FDCWD` is `-2`). It doesn't follow a link in the last component, so an existing name, also a FIFO, a dangling link, a directory or the root, is `EEXIST`, and an empty name is `ENOENT` (#972). A mount without FIFOs answers `EPERM` |
834
835
  | `path_access(dirfd, path, path_len, amode, flags)` | `faccessat`: `amode` is `R_OK` 4, `W_OK` 2, `X_OK` 1 or `F_OK` 0; the check uses the real uid and gid, or the effective ones with `flags & 2` (`AT_EACCESS`), and the link itself with `flags & 1`. With `users: 'off'` it checks only that the path exists, as a libc without it does (see [Permissions](#permissions)) |
836
+ | `path_copy_file(src_dirfd, src, src_len, dst_dirfd, dst, dst_len, mode, flags)` | copies a regular file inside the kernel, with no bytes through the program ([#1017](https://github.com/ai-ecoverse/slicc-kernel/issues/1017)). Paths resolve as in `path_open`; an absolute one ignores its dirfd, and `AT_FDCWD` is `-2`. The source is followed through symlinks; the destination's last component never is. The new file gets `mode & ~umask` and the caller as owner, with the permissions of a create: read on the source, write and search on the destination's directory. `flags & 1` (`COPY_EXCL`) makes it `O_EXCL`, so of two copies racing to one name exactly one succeeds and the other gets `EEXIST`. Without it, an existing file is replaced in place, as with `O_TRUNC`. `flags & 2` (`COPY_MODE`) takes the source's permission bits instead of `mode`; other bits are `EINVAL`. A failure after the create removes the new name. Other processes of the kernel that look at the destination wait until the copy has committed, so they see the old file or none, then the whole copy. Another tab sharing the OPFS root can see it empty until the commit, as with any create followed by a write. A source that isn't a regular file is `EINVAL`, and a copy between two mounts is `EXDEV`, so a program falls back to reading and writing. On the OPFS root a copy is one kernel call and about 5 OPFS lookups |
835
837
 
836
838
  The kernel's device nodes answer the mode and owner an Emscripten program sees for them ([#1028](https://github.com/ai-ecoverse/slicc-kernel/issues/1028)):
837
839
  - `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, `/dev/urandom` and `/dev/tty` are root's character devices with `0666`. `/dev/tty` also stats when the process has no controlling terminal; opening it then is `ENXIO`, as on Linux.