@ai-ecoverse/slicc-kernel 1.140.1 → 1.140.2
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 +1 -1
- package/dist/kernel-worker.js +81 -26
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +33 -7
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +81 -26
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +33 -7
- package/dist/process-worker.js.map +2 -2
- package/dist/types/process/wasi/wasi-fds.d.ts +1 -0
- package/dist/types/process/wasi/wasi-procfs.d.ts +1 -0
- package/dist/types/realm/sync-fs-wire.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1121,7 +1121,7 @@ A character device (`0666`), there in every `users` mode, through which programs
|
|
|
1121
1121
|
|
|
1122
1122
|
### `/proc`
|
|
1123
1123
|
|
|
1124
|
-
Every process of the kernel has `/proc/<pid>/` with `cmdline`, `comm`, `stat`, `statm` and `status`, in the formats procps reads, and `exe`, a link to the file the process was started from: the glue or `.wasm` that ran, as resolved (a copy run by its own path names the copy, a symlink its target) (#1264). As on Linux without ptrace access, reading another process's `exe` link is `EACCES` unless the reader is root or its uid and gid match all of the target's real, effective and saved ids; `cmdline` and `status` stay readable, and `/proc/self` is a link to the `/proc/<pid>` of the process that reads it, as on Linux (`readlink /proc/self` is its pid, the one it was exec'd under included). They come from the kernel's process table when they are opened, so a terminal sees the processes of every client. A process that exits while a program reads the `/proc` directory doesn't fail or cut short the listing: its pid is still listed, and opening its files fails with `ENOENT`, which `ps`, `pgrep` and `pidof` skip, as on Linux; an exec'd program shows under the pid its parent knows. `/proc/uptime`, `/proc/loadavg`, `/proc/stat` and `/proc/meminfo` are there too, and `/proc/mounts`. `/proc/version` names the kernel, Linux-shaped, with the slicc-kernel version that built it: `Linux version 6.0.0-slicc (slicc-kernel <version>) #1 SMP PREEMPT_DYNAMIC`. `/proc/sys/kernel/osrelease` is `6.0.0-slicc` and `/proc/sys/kernel/ostype` is `Linux`. The version is the one npm publishes, set when the package is built (`0.0.0-dev` when run from the sources). A JS program reads it as `ctx.kernel.version`. A process with no parent in the kernel (one a page, a client or the Node entry started) has parent 1, as children of init do, in `getppid()`, `/proc/<pid>/stat` and `ps` alike, and so does a process whose parent has ended, waited for or not (`getppid()` asks the kernel each time; a shell's `$PPID` keeps the value it started with, as on Linux). Pids, parents, process groups, sessions, command lines, terminals, start and boot times are real, and so are the credentials in `status` (`Uid:`, `Gid:`, `Groups:`; a process with a tag, see `kernel.run`, also has `Tag:\t<tag>` after `Gid:`, shown to root and to the same uid only, with newlines, tabs and carriage returns written `\n`, `\t` and `\r`) and each process's memory: the size of its wasm memory (`VSZ` and `RSS` alike, as wasm has no paging), which `/proc/meminfo` counts as used. CPU times are measured per process, its threads and the images it exec'd included: time a worker spends waiting for the kernel's answer is system time (at most 20 ms of each call; the rest of a longer one, such as a write into a full pipe, counts as blocked), time it spends blocked (a read, a `poll` or `select` that waits, a sleep, `wait`, a futex, while stopped) is neither, from the moment the call actually starts to wait (a call that could wait but answers at once, such as a `select` with a zero timeout or a ready descriptor, a `waitpid` with `WNOHANG`, or a futex wait whose value has already changed, is system time), and the rest is user time; a process's times stop when it ends, a call still in flight then adds nothing, so a loop that never calls the kernel shows as user time while it runs; they show in `/proc/<pid>/stat`, `ps` and `ps()`, and the times of the children a process has waited for (theirs and their own waited-for children's, as POSIX counts them) show as its `cutime` and `cstime` in `/proc/<pid>/stat`; a stopped process is `T` there, in `/proc/<pid>/status` (`T (stopped)`) and in `ps()`; a WASI or WASIX program's `CLOCK_PROCESS_CPUTIME_ID` and `CLOCK_THREAD_CPUTIME_ID` (`clock_time_get`) count only the time its thread runs, its own waits and blocked kernel calls left out (a sleep is not CPU time), per thread for now, so a threaded program's process clock is its calling thread's; and `/proc/stat` counts every process of the kernel, the reaped ones included, and `/proc/loadavg` averages the processes not blocked, sampled every 5 seconds. A JS program's time isn't measured yet. `MemTotal` (from `navigator.deviceMemory`, else 4 GiB) is a placeholder. A process that isn't root sees only its own user's processes (see [Users](#users)). WASI and WASIX programs see the same `/proc`, read-only (opening a file in it for writing, or linking one of its files elsewhere, fails with `EROFS`), from every thread, also through a symlink that points into it (where every change, `mkdir`, `rename`, `unlink`, `chmod`, a hard link from it or into it, and so on, fails too: with `EROFS` when the root file system has a physical `/proc`, which stays hidden and untouched, and otherwise with the `ENOENT` of the missing directory, since that check is only paid for when a physical `/proc` exists; with one, a symlink whose target passes `..` after a file or a missing name, such as `/f/../proc`, fails with `ENOTDIR` or `ENOENT`, as on Linux), and `/` lists it, so a WASI program gets a preopen for it; `/proc/self` is the program's own pid there too (the pid an exec'd program took over). WASI and WASIX programs also have `/proc/<pid>/task/<tid>/stat` for each of a process's threads (the main thread is tid 1), whose state is `S` while the thread is blocked in the kernel (a `sem_wait`, a blocking read, a sleep, a futex) and `R` otherwise (`T` and `Z` as for the process). JS programs read the same `/proc` through `ctx.fs` and `ctx.open` (see [JS programs](#js-programs)). Neither has `/proc/<pid>/fd` yet.
|
|
1124
|
+
Every process of the kernel has `/proc/<pid>/` with `cmdline`, `comm`, `stat`, `statm` and `status`, in the formats procps reads, and `exe`, a link to the file the process was started from: the glue or `.wasm` that ran, as resolved (a copy run by its own path names the copy, a symlink its target) (#1264). For WASI and WASIX programs, as for Emscripten ones, `stat`, `open` and reading `/proc/self/exe` act on the program file, while `lstat` and `readlink` show the link (#1273). As on Linux without ptrace access, reading another process's `exe` link is `EACCES` unless the reader is root or its uid and gid match all of the target's real, effective and saved ids; `cmdline` and `status` stay readable, and `/proc/self` is a link to the `/proc/<pid>` of the process that reads it, as on Linux (`readlink /proc/self` is its pid, the one it was exec'd under included). They come from the kernel's process table when they are opened, so a terminal sees the processes of every client. A process that exits while a program reads the `/proc` directory doesn't fail or cut short the listing: its pid is still listed, and opening its files fails with `ENOENT`, which `ps`, `pgrep` and `pidof` skip, as on Linux; an exec'd program shows under the pid its parent knows. `/proc/uptime`, `/proc/loadavg`, `/proc/stat` and `/proc/meminfo` are there too, and `/proc/mounts`. `/proc/version` names the kernel, Linux-shaped, with the slicc-kernel version that built it: `Linux version 6.0.0-slicc (slicc-kernel <version>) #1 SMP PREEMPT_DYNAMIC`. `/proc/sys/kernel/osrelease` is `6.0.0-slicc` and `/proc/sys/kernel/ostype` is `Linux`. The version is the one npm publishes, set when the package is built (`0.0.0-dev` when run from the sources). A JS program reads it as `ctx.kernel.version`. A process with no parent in the kernel (one a page, a client or the Node entry started) has parent 1, as children of init do, in `getppid()`, `/proc/<pid>/stat` and `ps` alike, and so does a process whose parent has ended, waited for or not (`getppid()` asks the kernel each time; a shell's `$PPID` keeps the value it started with, as on Linux). Pids, parents, process groups, sessions, command lines, terminals, start and boot times are real, and so are the credentials in `status` (`Uid:`, `Gid:`, `Groups:`; a process with a tag, see `kernel.run`, also has `Tag:\t<tag>` after `Gid:`, shown to root and to the same uid only, with newlines, tabs and carriage returns written `\n`, `\t` and `\r`) and each process's memory: the size of its wasm memory (`VSZ` and `RSS` alike, as wasm has no paging), which `/proc/meminfo` counts as used. CPU times are measured per process, its threads and the images it exec'd included: time a worker spends waiting for the kernel's answer is system time (at most 20 ms of each call; the rest of a longer one, such as a write into a full pipe, counts as blocked), time it spends blocked (a read, a `poll` or `select` that waits, a sleep, `wait`, a futex, while stopped) is neither, from the moment the call actually starts to wait (a call that could wait but answers at once, such as a `select` with a zero timeout or a ready descriptor, a `waitpid` with `WNOHANG`, or a futex wait whose value has already changed, is system time), and the rest is user time; a process's times stop when it ends, a call still in flight then adds nothing, so a loop that never calls the kernel shows as user time while it runs; they show in `/proc/<pid>/stat`, `ps` and `ps()`, and the times of the children a process has waited for (theirs and their own waited-for children's, as POSIX counts them) show as its `cutime` and `cstime` in `/proc/<pid>/stat`; a stopped process is `T` there, in `/proc/<pid>/status` (`T (stopped)`) and in `ps()`; a WASI or WASIX program's `CLOCK_PROCESS_CPUTIME_ID` and `CLOCK_THREAD_CPUTIME_ID` (`clock_time_get`) count only the time its thread runs, its own waits and blocked kernel calls left out (a sleep is not CPU time), per thread for now, so a threaded program's process clock is its calling thread's; and `/proc/stat` counts every process of the kernel, the reaped ones included, and `/proc/loadavg` averages the processes not blocked, sampled every 5 seconds. A JS program's time isn't measured yet. `MemTotal` (from `navigator.deviceMemory`, else 4 GiB) is a placeholder. A process that isn't root sees only its own user's processes (see [Users](#users)). WASI and WASIX programs see the same `/proc`, read-only (opening a file in it for writing, or linking one of its files elsewhere, fails with `EROFS`), from every thread, also through a symlink that points into it (where every change, `mkdir`, `rename`, `unlink`, `chmod`, a hard link from it or into it, and so on, fails too: with `EROFS` when the root file system has a physical `/proc`, which stays hidden and untouched, and otherwise with the `ENOENT` of the missing directory, since that check is only paid for when a physical `/proc` exists; with one, a symlink whose target passes `..` after a file or a missing name, such as `/f/../proc`, fails with `ENOTDIR` or `ENOENT`, as on Linux), and `/` lists it, so a WASI program gets a preopen for it; `/proc/self` is the program's own pid there too (the pid an exec'd program took over). WASI and WASIX programs also have `/proc/<pid>/task/<tid>/stat` for each of a process's threads (the main thread is tid 1), whose state is `S` while the thread is blocked in the kernel (a `sem_wait`, a blocking read, a sleep, a futex) and `R` otherwise (`T` and `Z` as for the process). JS programs read the same `/proc` through `ctx.fs` and `ctx.open` (see [JS programs](#js-programs)). Neither has `/proc/<pid>/fd` yet.
|
|
1125
1125
|
|
|
1126
1126
|
The kernel writes `/etc/passwd` and `/etc/group` when it starts (see [Users](#users)). While the root has none of them, or no `/etc/mtab`, reading them gets per-process ones: root is uid 0 and the realm user, uid 1000, is named after `USER`, or `web_user` (Emscripten's default) without one, so it matches `$USER`, with `HOME` as its home, so `id`, `whoami`, `ls -l` and `ps` show names. Nothing is written to OPFS, and a real file there wins.
|
|
1127
1127
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -7128,7 +7128,7 @@ function satisfies(version, range2) {
|
|
|
7128
7128
|
}
|
|
7129
7129
|
|
|
7130
7130
|
// src/version.ts
|
|
7131
|
-
var KERNEL_VERSION = true ? "1.140.
|
|
7131
|
+
var KERNEL_VERSION = true ? "1.140.2" : "0.0.0-dev";
|
|
7132
7132
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7133
7133
|
function procVersion() {
|
|
7134
7134
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9811,6 +9811,9 @@ function devCreation(path, cred) {
|
|
|
9811
9811
|
// src/fs/etc-files.ts
|
|
9812
9812
|
var HOSTNAME_PATH = "/etc/hostname";
|
|
9813
9813
|
var S_IFREG3 = 32768;
|
|
9814
|
+
var MAX_HOPS2 = 40;
|
|
9815
|
+
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
9816
|
+
var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
9814
9817
|
function missing4(err) {
|
|
9815
9818
|
return err?.code === "ENOENT";
|
|
9816
9819
|
}
|
|
@@ -9831,21 +9834,53 @@ function statOf(path, bytes) {
|
|
|
9831
9834
|
gid: 0
|
|
9832
9835
|
};
|
|
9833
9836
|
}
|
|
9837
|
+
function linkFollower(fs, files) {
|
|
9838
|
+
const bases = new Set([...files.keys()].map(baseOf2));
|
|
9839
|
+
const linkOf2 = (path) => fs.readlink(path).then(
|
|
9840
|
+
(link2) => link2,
|
|
9841
|
+
() => void 0
|
|
9842
|
+
);
|
|
9843
|
+
const viaParent = async (path) => {
|
|
9844
|
+
if (!bases.has(baseOf2(path)) || !fs.realpath) return path;
|
|
9845
|
+
const parent = parentOf6(path);
|
|
9846
|
+
const dir = await fs.realpath(parent, true).catch(() => parent);
|
|
9847
|
+
return fs.resolvePath(dir, baseOf2(path));
|
|
9848
|
+
};
|
|
9849
|
+
return async (path) => {
|
|
9850
|
+
let current = path;
|
|
9851
|
+
for (let hop = 0; hop < MAX_HOPS2 && !files.has(current); hop++) {
|
|
9852
|
+
const link2 = await linkOf2(current);
|
|
9853
|
+
if (link2 === void 0) return viaParent(current);
|
|
9854
|
+
current = fs.resolvePath(parentOf6(current), link2);
|
|
9855
|
+
}
|
|
9856
|
+
return current;
|
|
9857
|
+
};
|
|
9858
|
+
}
|
|
9859
|
+
function materializer(fs, listedAbsent) {
|
|
9860
|
+
return async (path) => {
|
|
9861
|
+
const bytes = await listedAbsent(path);
|
|
9862
|
+
if (bytes !== void 0) await fs.writeFile(path, bytes);
|
|
9863
|
+
};
|
|
9864
|
+
}
|
|
9834
9865
|
function withEtcFiles(fs, files) {
|
|
9835
9866
|
const bytesOf2 = (path) => {
|
|
9836
9867
|
const text = files.get(path)?.();
|
|
9837
9868
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
9838
9869
|
};
|
|
9839
9870
|
const absent2 = (path) => fs.lstat(path).then(() => false, missing4);
|
|
9871
|
+
const follow2 = linkFollower(fs, files);
|
|
9872
|
+
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf2(path) : void 0;
|
|
9840
9873
|
const fallback = (path, make) => async (err) => {
|
|
9841
|
-
const
|
|
9842
|
-
|
|
9843
|
-
|
|
9874
|
+
const at = missing4(err) ? await follow2(path) : void 0;
|
|
9875
|
+
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
9876
|
+
if (bytes === void 0 || at === void 0) throw err;
|
|
9877
|
+
return make(bytes, at);
|
|
9844
9878
|
};
|
|
9845
9879
|
const ranged2 = rangedOps(fs);
|
|
9880
|
+
const materialize = materializer(fs, listedAbsent);
|
|
9846
9881
|
const own = {
|
|
9847
|
-
stat: (path) => fs.stat(path).catch(fallback(path, (b) => statOf(
|
|
9848
|
-
lstat: (path) => fs.lstat(path).catch(fallback(path, (b) => statOf(
|
|
9882
|
+
stat: (path) => fs.stat(path).catch(fallback(path, (b, at) => statOf(at, b))),
|
|
9883
|
+
lstat: (path) => fs.lstat(path).catch(fallback(path, (b, at) => statOf(at, b))),
|
|
9849
9884
|
exists: async (path) => await fs.exists(path) || files.has(path) && await absent2(path),
|
|
9850
9885
|
...fs.createExclusive ? {
|
|
9851
9886
|
createExclusive: async (path, owner) => {
|
|
@@ -9858,9 +9893,23 @@ function withEtcFiles(fs, files) {
|
|
|
9858
9893
|
}
|
|
9859
9894
|
} : {},
|
|
9860
9895
|
readFile: (path) => fs.readFile(path).catch(fallback(path, (b) => new TextDecoder().decode(b))),
|
|
9896
|
+
...fs.append ? {
|
|
9897
|
+
append: async (path, bytes) => {
|
|
9898
|
+
if (files.has(path)) await materialize(path);
|
|
9899
|
+
return fs.append.call(fs, path, bytes);
|
|
9900
|
+
}
|
|
9901
|
+
} : {},
|
|
9861
9902
|
readFileBuffer: (path) => fs.readFileBuffer(path).catch(fallback(path, (b) => b)),
|
|
9862
9903
|
...ranged2 ? {
|
|
9863
|
-
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(fallback(path, (b) => b.slice(offset, offset + length2)))
|
|
9904
|
+
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(fallback(path, (b) => b.slice(offset, offset + length2))),
|
|
9905
|
+
pwrite: async (path, offset, bytes, transfer) => {
|
|
9906
|
+
if (files.has(path)) await materialize(path);
|
|
9907
|
+
return ranged2.pwrite(path, offset, bytes, transfer);
|
|
9908
|
+
},
|
|
9909
|
+
truncate: async (path, size) => {
|
|
9910
|
+
if (files.has(path)) await materialize(path);
|
|
9911
|
+
return ranged2.truncate(path, size);
|
|
9912
|
+
}
|
|
9864
9913
|
} : {}
|
|
9865
9914
|
};
|
|
9866
9915
|
return new Proxy(fs, {
|
|
@@ -9993,7 +10042,7 @@ var FreshModules = class {
|
|
|
9993
10042
|
};
|
|
9994
10043
|
|
|
9995
10044
|
// src/fs/physical-path.ts
|
|
9996
|
-
var
|
|
10045
|
+
var MAX_HOPS3 = 40;
|
|
9997
10046
|
function start(path) {
|
|
9998
10047
|
return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
|
|
9999
10048
|
}
|
|
@@ -10018,7 +10067,7 @@ function rest(walk2, part) {
|
|
|
10018
10067
|
return lexical(`/${[...walk2.done, part, ...walk2.todo].join("/")}`);
|
|
10019
10068
|
}
|
|
10020
10069
|
function follow(walk2, target) {
|
|
10021
|
-
if (++walk2.hops >
|
|
10070
|
+
if (++walk2.hops > MAX_HOPS3) return false;
|
|
10022
10071
|
if (target.startsWith("/")) walk2.done.length = 0;
|
|
10023
10072
|
walk2.todo = [...target.split("/").filter((p) => p !== ""), ...walk2.todo];
|
|
10024
10073
|
return true;
|
|
@@ -10041,13 +10090,13 @@ async function physicalPathAsync(fs, path) {
|
|
|
10041
10090
|
|
|
10042
10091
|
// src/fs/watch.ts
|
|
10043
10092
|
var WATCH_NOTES_LIMIT = 1e3;
|
|
10044
|
-
var
|
|
10093
|
+
var baseOf3 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
10045
10094
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
10046
10095
|
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
10047
|
-
var
|
|
10096
|
+
var parentOf7 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
10048
10097
|
function touches(watcher, changed) {
|
|
10049
10098
|
return watcher.paths.some(
|
|
10050
|
-
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) :
|
|
10099
|
+
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) : parentOf7(changed) === watched)
|
|
10051
10100
|
);
|
|
10052
10101
|
}
|
|
10053
10102
|
var REALS_KEPT = 4096;
|
|
@@ -10071,11 +10120,11 @@ function route(watch, type, path) {
|
|
|
10071
10120
|
}
|
|
10072
10121
|
function routed(watch, root, type, path) {
|
|
10073
10122
|
if (path === root || type === "rename" && root !== "/" && under3(root, path)) {
|
|
10074
|
-
noted(watch, { type, filename:
|
|
10123
|
+
noted(watch, { type, filename: baseOf3(root) });
|
|
10075
10124
|
if (type === "rename") noted(watch, { ended: true });
|
|
10076
10125
|
return true;
|
|
10077
10126
|
}
|
|
10078
|
-
if (
|
|
10127
|
+
if (parentOf7(path) === root) noted(watch, { type, filename: baseOf3(path) });
|
|
10079
10128
|
else if (watch.recursive && under3(path, root)) {
|
|
10080
10129
|
noted(watch, { type, filename: path.slice(root === "/" ? 1 : root.length + 1) });
|
|
10081
10130
|
} else return false;
|
|
@@ -10151,7 +10200,7 @@ var FsWatchers = class {
|
|
|
10151
10200
|
covers(path) {
|
|
10152
10201
|
for (const watch of this.typed) {
|
|
10153
10202
|
for (const root of watch.roots) {
|
|
10154
|
-
if (path === root ||
|
|
10203
|
+
if (path === root || parentOf7(path) === root || watch.recursive && under3(path, root))
|
|
10155
10204
|
return true;
|
|
10156
10205
|
}
|
|
10157
10206
|
}
|
|
@@ -11320,7 +11369,7 @@ var HeldPaths = class extends Map {
|
|
|
11320
11369
|
return this.revoked.has(path);
|
|
11321
11370
|
}
|
|
11322
11371
|
};
|
|
11323
|
-
var
|
|
11372
|
+
var parentOf8 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
11324
11373
|
var readonly = (mount) => mount.caps.readonly === true || mount.options.ro !== void 0;
|
|
11325
11374
|
function inodeless(mount, attr2) {
|
|
11326
11375
|
if (attr2.ino !== void 0) return false;
|
|
@@ -11620,7 +11669,7 @@ var MountTable = class {
|
|
|
11620
11669
|
for (const [key, cached] of [...mount.attrs])
|
|
11621
11670
|
if (within6(key, path) || linked2(cached.value)) mount.attrs.delete(key);
|
|
11622
11671
|
mount.lists.delete(path);
|
|
11623
|
-
mount.lists.delete(
|
|
11672
|
+
mount.lists.delete(parentOf8(path));
|
|
11624
11673
|
for (const [key, cached] of [...mount.lists])
|
|
11625
11674
|
if (within6(key, path) || cached.value.some((e) => linked2(e.attr))) mount.lists.delete(key);
|
|
11626
11675
|
}
|
|
@@ -11740,7 +11789,7 @@ var MountFs = class _MountFs {
|
|
|
11740
11789
|
const real = normalizePath(path);
|
|
11741
11790
|
if (this.at(real)) return real;
|
|
11742
11791
|
try {
|
|
11743
|
-
await this.base.stat(
|
|
11792
|
+
await this.base.stat(parentOf8(real));
|
|
11744
11793
|
return real;
|
|
11745
11794
|
} catch (err) {
|
|
11746
11795
|
const moved2 = redirectOf(err);
|
|
@@ -11782,7 +11831,7 @@ var MountFs = class _MountFs {
|
|
|
11782
11831
|
if (this.rejectLinks) throw errnoError("ELOOP", path);
|
|
11783
11832
|
if (hops >= MAX_LINKS7) throw errnoError("ELOOP", path);
|
|
11784
11833
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
11785
|
-
return this.follow(this.base.resolvePath(
|
|
11834
|
+
return this.follow(this.base.resolvePath(parentOf8(real), target), hops + 1, create);
|
|
11786
11835
|
}
|
|
11787
11836
|
async open(mount, rel2, write, owner) {
|
|
11788
11837
|
return await mount.conn.call({
|
|
@@ -11798,8 +11847,8 @@ var MountFs = class _MountFs {
|
|
|
11798
11847
|
async driverOwner(found, real, owner, directory) {
|
|
11799
11848
|
const { mount, rel: rel2 } = found;
|
|
11800
11849
|
if (!owner || !mount.owners || !mount.caps.owners) return void 0;
|
|
11801
|
-
const dir =
|
|
11802
|
-
const above = statOf2(await this.table.getattr(mount, dir,
|
|
11850
|
+
const dir = parentOf8(real);
|
|
11851
|
+
const above = statOf2(await this.table.getattr(mount, dir, parentOf8(rel2)), dir, mount);
|
|
11803
11852
|
const setgid = (above.mode & S_ISGID4) !== 0;
|
|
11804
11853
|
let mode = owner.mode;
|
|
11805
11854
|
if (directory && setgid) mode = (mode ?? 493) | S_ISGID4;
|
|
@@ -12305,7 +12354,7 @@ var MountFs = class _MountFs {
|
|
|
12305
12354
|
}
|
|
12306
12355
|
async named(path) {
|
|
12307
12356
|
const at = normalizePath(path);
|
|
12308
|
-
return joinName(await realDir(this,
|
|
12357
|
+
return joinName(await realDir(this, parentOf8(at)), at.slice(at.lastIndexOf("/") + 1));
|
|
12309
12358
|
}
|
|
12310
12359
|
async link(source, target, follow2 = false) {
|
|
12311
12360
|
const from = follow2 ? await realTarget(this, normalizePath(source)) : await this.named(source);
|
|
@@ -14191,6 +14240,12 @@ var ProcTree = class {
|
|
|
14191
14240
|
if (node.kind !== "dir") throw syncError("ENOTDIR", path);
|
|
14192
14241
|
return node.names();
|
|
14193
14242
|
}
|
|
14243
|
+
escape(path) {
|
|
14244
|
+
const node = this.node(this.parts(path, true));
|
|
14245
|
+
if (node?.kind !== "link" || !node.target.startsWith("/")) return void 0;
|
|
14246
|
+
if (node.denied) throw syncError("EACCES", path);
|
|
14247
|
+
return node.target;
|
|
14248
|
+
}
|
|
14194
14249
|
readlink(path) {
|
|
14195
14250
|
const node = this.find(path, false);
|
|
14196
14251
|
if (node.kind !== "link") throw syncError("EINVAL", path);
|
|
@@ -14206,7 +14261,7 @@ var ProcTree = class {
|
|
|
14206
14261
|
}
|
|
14207
14262
|
}
|
|
14208
14263
|
};
|
|
14209
|
-
var
|
|
14264
|
+
var MAX_HOPS4 = 40;
|
|
14210
14265
|
function* procWalk(path, follow2) {
|
|
14211
14266
|
let done5 = [];
|
|
14212
14267
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -14225,7 +14280,7 @@ function* procWalk(path, follow2) {
|
|
|
14225
14280
|
if (!follow2 && todo.length === 0) return void 0;
|
|
14226
14281
|
const target = yield { at, check: todo.find((next3) => next3 !== ".") === ".." };
|
|
14227
14282
|
if (typeof target === "string") {
|
|
14228
|
-
if (++hops >
|
|
14283
|
+
if (++hops > MAX_HOPS4) return void 0;
|
|
14229
14284
|
[done5, todo] = throughLink(target, done5, todo);
|
|
14230
14285
|
} else {
|
|
14231
14286
|
broken ??= refusalOf(target);
|
|
@@ -21885,7 +21940,7 @@ function isWatchSyscall(req) {
|
|
|
21885
21940
|
return WATCHING.has(req.op);
|
|
21886
21941
|
}
|
|
21887
21942
|
var WATCHES_MAX = 8192;
|
|
21888
|
-
var
|
|
21943
|
+
var parentOf9 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
21889
21944
|
function visibleTo2(watch, root, visible) {
|
|
21890
21945
|
return {
|
|
21891
21946
|
close: () => watch.close(),
|
|
@@ -21895,7 +21950,7 @@ function visibleTo2(watch, root, visible) {
|
|
|
21895
21950
|
const shown = await Promise.all(
|
|
21896
21951
|
notes.map(async (note) => {
|
|
21897
21952
|
if (!("filename" in note) || !note.filename.includes("/")) return true;
|
|
21898
|
-
const dir =
|
|
21953
|
+
const dir = parentOf9(`${root === "/" ? "" : root}/${note.filename}`);
|
|
21899
21954
|
if (!seen.has(dir)) seen.set(dir, visible(dir));
|
|
21900
21955
|
return seen.get(dir);
|
|
21901
21956
|
})
|