@ai-ecoverse/slicc-kernel 1.178.2 → 1.178.4
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 +100 -74
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +117 -91
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/fs/dac.d.ts +1 -1
- package/dist/types/sudo-timestamp.d.ts +4 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1067,7 +1067,7 @@ With `users: 'enforce'`, the default, or `'report'`, files have owners, and [Per
|
|
|
1067
1067
|
- **Homes:** every `kernel.users.add` gives the user's home (only a real directory at `/home/<dir>`, not a symlink or a path through one) and everything in it without an owner of its own to the user, and sets the home's mode: `0700`, `0750` for a `scoop-` user, `2750` with `homeGroup`, and its `~/.local/share/pnpm`'s to `0700` (`0750` for a `scoop-` user). The embedder calls `add` for each user at boot, as it already does, so homes made before owners were on become the user's. That also means a user's own `chmod` or `chgrp` of its home lasts only until the next `add`, and `add` must get the same `homeGroup` every time.
|
|
1068
1068
|
- **`chown`, `lchown`, `fchown`:** Emscripten programs, and WASI programs through `slicc_fs` (see [File modes and the umask](#file-modes-and-the-umask)), change owners through the kernel, by the Linux rules: root may set any owner and group; a file's owner may set its group to one it belongs to, or leave it as it is; anything else fails with `EPERM`. `-1` keeps an id. A `chown` that sets an owner or group of a file clears its setuid bit, and its setgid bit if the file is group-executable, whoever calls it, root included, as on Linux. With `users: 'off'`, `chown` succeeds and changes nothing, as before.
|
|
1069
1069
|
- **What programs see:** `stat` shows the owners to Emscripten programs, whatever their libc reports for their own ids, so a program built before H1 sees real owners too, and its owner checks can fail. WASI programs read them with `slicc_fs.fd_owner` and `path_owner`. The commands in `/usr/bin` and `/bin` are root's, and a user's own commands in `~/.local/share/pnpm/bin` belong to the owner of the closest real directory above them, normally the user.
|
|
1070
|
-
- **Mounts:** the options `uid=` and `gid=` (decimal ids) give a mount its owner; without them it belongs to whoever mounted it: root for `kernel.mount`, `/etc/fstab` and a client, the process's effective ids for `mount(2)`, which then shows them in its options (a process that isn't root gets its own ids whatever `uid=` and `gid=` it passes, so it can't make a mount look root's). A mount whose driver keeps owners (`tmpfs`) starts with its root owned so, and its files get owners as on the root file system, `chown` included. On `hostfs`, `fsa` and any driver without `owners`, every file shows as the mount's owner and `chown` fails with `EPERM`, root's too, as on a FAT drive. An embedder that mounts a folder for a user (bios's linked and picked folders) passes that user's `uid` and `gid`, or the user's programs see root's files there, and git calls the repository's ownership dubious. Those mounts also take the FAT-style options `umask=`, `fmask=` and `dmask=` (octal, as on Linux `vfat`): when any is set, the kernel synthesises the permission bits that `stat` and DAC see from `0666` for files and `0777` for directories (and symlinks), less the mask (`fmask` for files, `dmask` for directories, and `umask` as the default for both). Without them, files stay `0644` and directories `0755` as before, so only the mount's `uid` may write. `umask=000` (or `fmask=000,dmask=000`) makes every file and directory world-writable under DAC, which is how a personal cone (another uid) can write a folder mounted as the template `cone` user. When a mask is set on a mount without a `chmod` capability (`fsa`), `chmod` is a no-op and is not owner-only, so a create that then sets the mode from another uid still succeeds. Without a mask, and on a mount that keeps real modes through `chmod` (`hostfs`), `chmod` still requires the mount's `uid` (or root). Drivers with `owners` (`tmpfs`) ignore the mask options: their modes stay real, and chmod still
|
|
1070
|
+
- **Mounts:** the options `uid=` and `gid=` (decimal ids) give a mount its owner; without them it belongs to whoever mounted it: root for `kernel.mount`, `/etc/fstab` and a client, the process's effective ids for `mount(2)`, which then shows them in its options (a process that isn't root gets its own ids whatever `uid=` and `gid=` it passes, so it can't make a mount look root's). A mount whose driver keeps owners (`tmpfs`) starts with its root owned so, and its files get owners as on the root file system, `chown` included. On `hostfs`, `fsa` and any driver without `owners`, every file shows as the mount's owner and `chown` fails with `EPERM`, root's too, as on a FAT drive. An embedder that mounts a folder for a user (bios's linked and picked folders) passes that user's `uid` and `gid`, or the user's programs see root's files there, and git calls the repository's ownership dubious. Those mounts also take the FAT-style options `umask=`, `fmask=` and `dmask=` (octal, as on Linux `vfat`): when any is set, the kernel synthesises the permission bits that `stat` and DAC see from `0666` for files and `0777` for directories (and symlinks), less the mask (`fmask` for files, `dmask` for directories, and `umask` as the default for both). Without them, files stay `0644` and directories `0755` as before, so only the mount's `uid` may write. `umask=000` (or `fmask=000,dmask=000`) makes every file and directory world-writable under DAC, which is how a personal cone (another uid) can write a folder mounted as the template `cone` user. When a mask is set on a mount without a `chmod` capability (`fsa`), `chmod` is a no-op and is not owner-only, so a create that then sets the mode from another uid still succeeds, and a non-owner who can write the file may set its times to an explicit value (`utimes` / `cp -p` / `tar x`), as on Linux `vfat` with a uid/umask mount; "now" times already needed only write access. Without a mask, and on a mount that keeps real modes through `chmod` (`hostfs`), `chmod` still requires the mount's `uid` (or root), and explicit times stay owner-only. Drivers with `owners` (`tmpfs`) ignore the mask options: their modes stay real, and chmod and explicit times still require the owner.
|
|
1071
1071
|
|
|
1072
1072
|
### Permissions
|
|
1073
1073
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -1339,8 +1339,8 @@ var RemoteWatch = class {
|
|
|
1339
1339
|
const { held = [], pending = [] } = await this.locks.query();
|
|
1340
1340
|
if (![...held, ...pending].some((lock) => lock.name === name2)) {
|
|
1341
1341
|
this.mourned.delete(peer);
|
|
1342
|
-
const
|
|
1343
|
-
if (tries > 1 &&
|
|
1342
|
+
const live2 = this.peers.has(peer) || this.flushes.has(peer);
|
|
1343
|
+
if (tries > 1 && live2) {
|
|
1344
1344
|
setTimeout(() => void this.mourn(peer, tries - 1), MOURN_RETRY_MS);
|
|
1345
1345
|
} else this.flushedAt(peer);
|
|
1346
1346
|
return;
|
|
@@ -1830,11 +1830,11 @@ async function positioned(handle, op) {
|
|
|
1830
1830
|
}
|
|
1831
1831
|
return;
|
|
1832
1832
|
}
|
|
1833
|
-
const
|
|
1833
|
+
const writable3 = await handle.createWritable({ keepExistingData: true });
|
|
1834
1834
|
try {
|
|
1835
1835
|
await op({
|
|
1836
1836
|
write: async (at, bytes) => {
|
|
1837
|
-
await
|
|
1837
|
+
await writable3.write({
|
|
1838
1838
|
type: "write",
|
|
1839
1839
|
position: at,
|
|
1840
1840
|
data: bytes
|
|
@@ -1842,15 +1842,15 @@ async function positioned(handle, op) {
|
|
|
1842
1842
|
extent.wrote(at + bytes.length);
|
|
1843
1843
|
},
|
|
1844
1844
|
truncate: async (n) => {
|
|
1845
|
-
await
|
|
1845
|
+
await writable3.truncate(n);
|
|
1846
1846
|
extent.cut(n);
|
|
1847
1847
|
}
|
|
1848
1848
|
});
|
|
1849
1849
|
} catch (err) {
|
|
1850
|
-
await
|
|
1850
|
+
await writable3.abort();
|
|
1851
1851
|
throw err;
|
|
1852
1852
|
}
|
|
1853
|
-
await
|
|
1853
|
+
await writable3.close();
|
|
1854
1854
|
if (extent.big()) extent.check((await handle.getFile()).size);
|
|
1855
1855
|
}
|
|
1856
1856
|
function syncAccessHandles(scope = globalThis) {
|
|
@@ -2936,21 +2936,21 @@ var OpfsFs = class {
|
|
|
2936
2936
|
}
|
|
2937
2937
|
async writeSession(path, truncate) {
|
|
2938
2938
|
const [handle, , target] = await this.fileFor(path);
|
|
2939
|
-
const
|
|
2939
|
+
const writable3 = await this.retrying(
|
|
2940
2940
|
path,
|
|
2941
2941
|
() => this.io(handle.createWritable({ keepExistingData: !truncate })),
|
|
2942
2942
|
true
|
|
2943
2943
|
);
|
|
2944
2944
|
return {
|
|
2945
|
-
write: (at, bytes) =>
|
|
2945
|
+
write: (at, bytes) => writable3.write({ type: "write", position: at, data: bytes }).catch((err) => {
|
|
2946
2946
|
throw translate(err, path, "write", false);
|
|
2947
2947
|
}),
|
|
2948
|
-
truncate: (size) =>
|
|
2948
|
+
truncate: (size) => writable3.truncate(size).catch((err) => {
|
|
2949
2949
|
throw translate(err, path, "write", false);
|
|
2950
2950
|
}),
|
|
2951
2951
|
close: async () => {
|
|
2952
2952
|
this.wrote(handle);
|
|
2953
|
-
await
|
|
2953
|
+
await writable3.close().catch((err) => {
|
|
2954
2954
|
this.wrote(handle);
|
|
2955
2955
|
throw translate(err, path, "commit", false);
|
|
2956
2956
|
});
|
|
@@ -3002,19 +3002,19 @@ var OpfsFs = class {
|
|
|
3002
3002
|
const [file, existed, target] = await this.fileFor(path, owner?.existing !== true);
|
|
3003
3003
|
if (!existed) await this.stampNew(target, owner, false);
|
|
3004
3004
|
if (!existed && content.length === 0) return;
|
|
3005
|
-
let
|
|
3005
|
+
let writable3;
|
|
3006
3006
|
this.wrote(file);
|
|
3007
3007
|
try {
|
|
3008
|
-
|
|
3009
|
-
await
|
|
3010
|
-
await
|
|
3008
|
+
writable3 = await this.io(file.createWritable());
|
|
3009
|
+
await writable3.write(content);
|
|
3010
|
+
await writable3.close();
|
|
3011
3011
|
if (typeof content !== "string" && content.length >= CHECKED_BYTES) {
|
|
3012
3012
|
const extent = new Extent();
|
|
3013
3013
|
extent.cut(content.length);
|
|
3014
3014
|
extent.check((await file.getFile()).size);
|
|
3015
3015
|
}
|
|
3016
3016
|
} catch (err) {
|
|
3017
|
-
await
|
|
3017
|
+
await writable3?.abort().catch(() => void 0);
|
|
3018
3018
|
throw translate(err, path, "commit", false);
|
|
3019
3019
|
} finally {
|
|
3020
3020
|
this.wrote(file);
|
|
@@ -3739,7 +3739,7 @@ var OpfsFs = class {
|
|
|
3739
3739
|
created4 = true;
|
|
3740
3740
|
}
|
|
3741
3741
|
let target = destination;
|
|
3742
|
-
let
|
|
3742
|
+
let writable3;
|
|
3743
3743
|
let handle;
|
|
3744
3744
|
try {
|
|
3745
3745
|
const kept = created4 ? this.files.get(destination) : void 0;
|
|
@@ -3758,11 +3758,11 @@ var OpfsFs = class {
|
|
|
3758
3758
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", to);
|
|
3759
3759
|
}
|
|
3760
3760
|
this.wrote(handle);
|
|
3761
|
-
|
|
3762
|
-
await
|
|
3763
|
-
await
|
|
3761
|
+
writable3 = await handle.createWritable();
|
|
3762
|
+
await writable3.write(file);
|
|
3763
|
+
await writable3.close();
|
|
3764
3764
|
} catch (err) {
|
|
3765
|
-
await
|
|
3765
|
+
await writable3?.abort().catch(() => void 0);
|
|
3766
3766
|
if (created4) await this.rm(target, { file: true }).catch(() => void 0);
|
|
3767
3767
|
throw translate(err, to, "commit", false);
|
|
3768
3768
|
} finally {
|
|
@@ -3851,10 +3851,10 @@ var OpfsFs = class {
|
|
|
3851
3851
|
}
|
|
3852
3852
|
if (handle.kind === "file") {
|
|
3853
3853
|
const made2 = await this.io(dir.getFileHandle(name2, { create: true }));
|
|
3854
|
-
const
|
|
3854
|
+
const writable3 = await this.io(made2.createWritable());
|
|
3855
3855
|
const file = await this.io(handle.getFile());
|
|
3856
|
-
await
|
|
3857
|
-
await
|
|
3856
|
+
await writable3.write(file);
|
|
3857
|
+
await writable3.close();
|
|
3858
3858
|
copies?.set(rest2, { before: copies.get(rest2)?.before ?? file.lastModified, made: made2 });
|
|
3859
3859
|
return;
|
|
3860
3860
|
}
|
|
@@ -5572,13 +5572,6 @@ async function linkable(g, from, to, follow2) {
|
|
|
5572
5572
|
}
|
|
5573
5573
|
await inParent(g, "link", to);
|
|
5574
5574
|
}
|
|
5575
|
-
async function ownerOnly(g, op, path, follow2) {
|
|
5576
|
-
const walked = await need(g, op, path, 0, { follow: follow2 });
|
|
5577
|
-
const perm = walked.perm;
|
|
5578
|
-
if (!perm || g.cred.euid === 0 || perm.uid === g.cred.euid) return walked;
|
|
5579
|
-
if (await present(g.fs, walked.path, false)) deny(g, op, path, "EPERM");
|
|
5580
|
-
return walked;
|
|
5581
|
-
}
|
|
5582
5575
|
async function chmodMode(g, path, mode) {
|
|
5583
5576
|
const walked = await need(g, "chmod", path, 0, { follow: true });
|
|
5584
5577
|
const perm = walked.perm;
|
|
@@ -5600,17 +5593,26 @@ function heldChmodMode(g, path, st, mode) {
|
|
|
5600
5593
|
function heldRetimable(g, path, st, now) {
|
|
5601
5594
|
const perm = permOf(st);
|
|
5602
5595
|
if (g.cred.euid === 0 || perm.uid === g.cred.euid) return;
|
|
5603
|
-
if (
|
|
5604
|
-
|
|
5596
|
+
if (now || st.fat) {
|
|
5597
|
+
if (!permits(g.cred, perm, W_OK, false)) deny(g, "futimens", path);
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
deny(g, "futimens", path, "EPERM");
|
|
5605
5601
|
}
|
|
5606
5602
|
async function retimable(g, op, path, now = false) {
|
|
5607
5603
|
const follow2 = op !== "lutimes";
|
|
5608
|
-
if (!now) return void await ownerOnly(g, op, path, follow2);
|
|
5609
5604
|
const walked = await need(g, op, path, 0, { follow: follow2 });
|
|
5610
5605
|
const perm = walked.perm;
|
|
5611
5606
|
if (!perm || g.cred.euid === 0 || perm.uid === g.cred.euid) return;
|
|
5612
|
-
|
|
5613
|
-
|
|
5607
|
+
const look = follow2 ? g.fs.stat : g.fs.lstat;
|
|
5608
|
+
const st = await look.call(g.fs, walked.path).catch(() => void 0);
|
|
5609
|
+
if (now || st?.fat) {
|
|
5610
|
+
if (!permits(g.cred, perm, W_OK, false) && await present(g.fs, walked.path, false)) {
|
|
5611
|
+
deny(g, op, path);
|
|
5612
|
+
}
|
|
5613
|
+
return;
|
|
5614
|
+
}
|
|
5615
|
+
if (await present(g.fs, walked.path, false)) deny(g, op, path, "EPERM");
|
|
5614
5616
|
}
|
|
5615
5617
|
async function fileWritable(g, op, path) {
|
|
5616
5618
|
await need(g, op, path, W_OK, { directory: false });
|
|
@@ -8777,7 +8779,7 @@ function satisfies(version, range2) {
|
|
|
8777
8779
|
}
|
|
8778
8780
|
|
|
8779
8781
|
// src/version.ts
|
|
8780
|
-
var KERNEL_VERSION = true ? "1.178.
|
|
8782
|
+
var KERNEL_VERSION = true ? "1.178.4" : "0.0.0-dev";
|
|
8781
8783
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8782
8784
|
function procVersion() {
|
|
8783
8785
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -17089,11 +17091,11 @@ function systemFile(name2, listing, now, memory) {
|
|
|
17089
17091
|
listing.processes.reduce((sum2, p) => sum2 + p.memory, 0)
|
|
17090
17092
|
);
|
|
17091
17093
|
}
|
|
17092
|
-
const
|
|
17094
|
+
const live2 = listing.processes.filter((p) => p.state !== "Z");
|
|
17093
17095
|
if (name2 === "loadavg") {
|
|
17094
17096
|
const last = Math.max(0, ...listing.processes.map((p) => p.pid));
|
|
17095
17097
|
const [one, five, fifteen] = (listing.load ?? [0, 0, 0]).map((n) => n.toFixed(2));
|
|
17096
|
-
return `${one} ${five} ${fifteen} 1/${
|
|
17098
|
+
return `${one} ${five} ${fifteen} 1/${live2.length} ${last}
|
|
17097
17099
|
`;
|
|
17098
17100
|
}
|
|
17099
17101
|
const sum = (key) => listing.cpu?.[key] ?? listing.processes.reduce((n, p) => n + (p[key] ?? 0), 0);
|
|
@@ -19582,30 +19584,49 @@ function timestampKey(owner, type) {
|
|
|
19582
19584
|
}
|
|
19583
19585
|
return parent ? JSON.stringify(["ppid", parent.pid, parent.started]) : void 0;
|
|
19584
19586
|
}
|
|
19587
|
+
function boundKey(bound3) {
|
|
19588
|
+
return JSON.stringify(
|
|
19589
|
+
Object.keys(bound3).sort().map((path) => [path, bound3[path]])
|
|
19590
|
+
);
|
|
19591
|
+
}
|
|
19592
|
+
function writable2(bound3) {
|
|
19593
|
+
return bound3 !== void 0 && Object.keys(bound3).length > 0;
|
|
19594
|
+
}
|
|
19595
|
+
function live(stamp, policy, now) {
|
|
19596
|
+
return stamp.at <= now && (policy.minutes < 0 || now - stamp.at < policy.minutes * MINUTE_MS2);
|
|
19597
|
+
}
|
|
19585
19598
|
var Timestamps = class {
|
|
19586
19599
|
users = /* @__PURE__ */ new Map();
|
|
19587
19600
|
now;
|
|
19588
19601
|
constructor(now) {
|
|
19589
19602
|
this.now = now;
|
|
19590
19603
|
}
|
|
19591
|
-
current(owner, policy) {
|
|
19604
|
+
current(owner, policy, bound3) {
|
|
19592
19605
|
if (policy.minutes === 0) return false;
|
|
19593
19606
|
const key = timestampKey(owner, policy.type);
|
|
19594
|
-
const
|
|
19595
|
-
if (
|
|
19607
|
+
const stamp = key === void 0 ? void 0 : this.users.get(owner.uid)?.get(key);
|
|
19608
|
+
if (stamp === void 0) return false;
|
|
19596
19609
|
const now = this.now();
|
|
19597
|
-
|
|
19610
|
+
if (!live(stamp, policy, now)) {
|
|
19611
|
+
this.drop(owner.uid, key);
|
|
19612
|
+
return false;
|
|
19613
|
+
}
|
|
19614
|
+
if (!writable2(bound3)) return true;
|
|
19615
|
+
return stamp.covered.has(boundKey(bound3));
|
|
19598
19616
|
}
|
|
19599
|
-
stamp(owner, policy) {
|
|
19617
|
+
stamp(owner, policy, bound3) {
|
|
19600
19618
|
const key = policy.minutes === 0 ? void 0 : timestampKey(owner, policy.type);
|
|
19601
19619
|
if (key === void 0) return false;
|
|
19602
19620
|
const now = this.now();
|
|
19603
19621
|
const records = this.users.get(owner.uid) ?? /* @__PURE__ */ new Map();
|
|
19604
19622
|
this.users.set(owner.uid, records);
|
|
19623
|
+
const prior = records.get(key);
|
|
19624
|
+
const covered = prior !== void 0 && live(prior, policy, now) ? prior.covered : /* @__PURE__ */ new Set();
|
|
19625
|
+
if (writable2(bound3)) covered.add(boundKey(bound3));
|
|
19605
19626
|
records.delete(key);
|
|
19606
|
-
records.set(key, now);
|
|
19607
|
-
for (const [old,
|
|
19608
|
-
const stale = policy.minutes > 0 && (
|
|
19627
|
+
records.set(key, { at: now, covered });
|
|
19628
|
+
for (const [old, stamp] of records) {
|
|
19629
|
+
const stale = policy.minutes > 0 && !live(stamp, policy, now);
|
|
19609
19630
|
if (stale || records.size > TIMESTAMPS_MAX) records.delete(old);
|
|
19610
19631
|
}
|
|
19611
19632
|
return true;
|
|
@@ -19619,6 +19640,11 @@ var Timestamps = class {
|
|
|
19619
19640
|
remove(uid) {
|
|
19620
19641
|
this.users.delete(uid);
|
|
19621
19642
|
}
|
|
19643
|
+
drop(uid, key) {
|
|
19644
|
+
const records = this.users.get(uid);
|
|
19645
|
+
records?.delete(key);
|
|
19646
|
+
if (records?.size === 0) this.users.delete(uid);
|
|
19647
|
+
}
|
|
19622
19648
|
};
|
|
19623
19649
|
|
|
19624
19650
|
// src/sudoers.ts
|
|
@@ -20248,12 +20274,12 @@ function usable(parsed2) {
|
|
|
20248
20274
|
function policyOf(settings) {
|
|
20249
20275
|
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
20250
20276
|
}
|
|
20251
|
-
function described(rule,
|
|
20277
|
+
function described(rule, writable3) {
|
|
20252
20278
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
20253
20279
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
20254
20280
|
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
20255
20281
|
const sums = Object.entries(rule.sha256 ?? {}).map(([path, hex4]) => `SHA256=${quoteWord(path)}:${hex4} `).join("");
|
|
20256
|
-
const flag =
|
|
20282
|
+
const flag = writable3 ? " # user-writable command" : "";
|
|
20257
20283
|
return ` (${rule.target}) ${cwd}${stdin}${sums}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}${flag}`;
|
|
20258
20284
|
}
|
|
20259
20285
|
var Sudo = class {
|
|
@@ -20546,8 +20572,8 @@ var Sudo = class {
|
|
|
20546
20572
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
20547
20573
|
);
|
|
20548
20574
|
}
|
|
20549
|
-
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
20550
|
-
this.timestamps.stamp(s.owner, s.policy);
|
|
20575
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy, bound3)) {
|
|
20576
|
+
this.timestamps.stamp(s.owner, s.policy, bound3);
|
|
20551
20577
|
this.logged(s, cwd, argv);
|
|
20552
20578
|
return grant();
|
|
20553
20579
|
}
|
|
@@ -20562,7 +20588,7 @@ var Sudo = class {
|
|
|
20562
20588
|
if (!now) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
20563
20589
|
const shown2 = recordable(cwd, [...parsed2.command, ...Object.keys(bound3)]);
|
|
20564
20590
|
const result = answer2.answer === "once" ? grant() : await this.always(self, target, { cwd, argv, bound: bound3 }, now, shown2, grant);
|
|
20565
|
-
if (!("error" in result)) this.stamped(s, answer2);
|
|
20591
|
+
if (!("error" in result)) this.stamped(s, answer2, bound3);
|
|
20566
20592
|
return result;
|
|
20567
20593
|
});
|
|
20568
20594
|
}
|
|
@@ -20596,8 +20622,8 @@ var Sudo = class {
|
|
|
20596
20622
|
this.pending.delete(uid);
|
|
20597
20623
|
}
|
|
20598
20624
|
}
|
|
20599
|
-
stamped(s, answer2) {
|
|
20600
|
-
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy);
|
|
20625
|
+
stamped(s, answer2, bound3 = {}) {
|
|
20626
|
+
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy, bound3);
|
|
20601
20627
|
}
|
|
20602
20628
|
logged(s, cwd, argv) {
|
|
20603
20629
|
const { caller, self, target, owner, policy } = s;
|
|
@@ -26954,18 +26980,18 @@ var VfsNodes = class {
|
|
|
26954
26980
|
if (id2 !== void 0) this.know(node, id2);
|
|
26955
26981
|
return node;
|
|
26956
26982
|
}
|
|
26957
|
-
open(path, pin,
|
|
26983
|
+
open(path, pin, writable3 = false, id2, ino) {
|
|
26958
26984
|
const found = this.named(path, id2);
|
|
26959
26985
|
const same3 = !found || ino === void 0 || found.ino === void 0 || found.ino === ino;
|
|
26960
26986
|
if (found && !same3) this.orphan(found);
|
|
26961
26987
|
const node = (same3 ? found : void 0) ?? this.create(path, id2, new VfsNode(this.fs, path, void 0, false, false, pin));
|
|
26962
26988
|
node.ino ??= ino;
|
|
26963
26989
|
node.opens++;
|
|
26964
|
-
if (
|
|
26990
|
+
if (writable3) node.writers++;
|
|
26965
26991
|
if (node.opens === 1) this.opened?.(node);
|
|
26966
26992
|
return node;
|
|
26967
26993
|
}
|
|
26968
|
-
adopt(path, contents2, dirty,
|
|
26994
|
+
adopt(path, contents2, dirty, writable3 = false, id2) {
|
|
26969
26995
|
let node = this.named(path, id2);
|
|
26970
26996
|
if (!node) {
|
|
26971
26997
|
node = this.create(path, id2, new VfsNode(this.fs, path, contents2, false, dirty));
|
|
@@ -26973,7 +26999,7 @@ var VfsNodes = class {
|
|
|
26973
26999
|
node.replace(contents2);
|
|
26974
27000
|
}
|
|
26975
27001
|
node.opens++;
|
|
26976
|
-
if (
|
|
27002
|
+
if (writable3) node.writers++;
|
|
26977
27003
|
if (node.opens === 1) this.opened?.(node);
|
|
26978
27004
|
return node;
|
|
26979
27005
|
}
|
|
@@ -26986,11 +27012,11 @@ var VfsNodes = class {
|
|
|
26986
27012
|
if (node.writers > 0 && within9(path, prefix)) return true;
|
|
26987
27013
|
return false;
|
|
26988
27014
|
}
|
|
26989
|
-
closed(node,
|
|
27015
|
+
closed(node, writable3 = false) {
|
|
26990
27016
|
node.opens--;
|
|
26991
|
-
if (
|
|
27017
|
+
if (writable3) node.writers--;
|
|
26992
27018
|
if (node.opens > 0) {
|
|
26993
|
-
if (
|
|
27019
|
+
if (writable3 && node.writers === 0) this.onClosed?.(node.path);
|
|
26994
27020
|
return;
|
|
26995
27021
|
}
|
|
26996
27022
|
this.forget(node);
|
|
@@ -27309,8 +27335,8 @@ function keepingOpen(fs, nodes, changed = () => {
|
|
|
27309
27335
|
function vfsFile(fs, opts, nodes) {
|
|
27310
27336
|
const access2 = opts.flags & O_ACCMODE;
|
|
27311
27337
|
const readable2 = access2 !== O_WRONLY;
|
|
27312
|
-
const
|
|
27313
|
-
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true,
|
|
27338
|
+
const writable3 = access2 === O_WRONLY || access2 === O_RDWR;
|
|
27339
|
+
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true, writable3, opts.id) : nodes.open(opts.path, opts.pin, writable3, opts.id, opts.ino);
|
|
27314
27340
|
let openError;
|
|
27315
27341
|
const atOpen = (op) => {
|
|
27316
27342
|
void node.serial(op).catch((err) => {
|
|
@@ -27337,7 +27363,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
27337
27363
|
offset += out.length;
|
|
27338
27364
|
return out;
|
|
27339
27365
|
}) : void 0,
|
|
27340
|
-
write:
|
|
27366
|
+
write: writable3 ? (bytes) => serial(async () => {
|
|
27341
27367
|
if (opts.flags & O_APPEND) offset = await node.append(bytes);
|
|
27342
27368
|
else offset += await node.pwrite(bytes, offset);
|
|
27343
27369
|
return bytes.length;
|
|
@@ -27356,11 +27382,11 @@ function vfsFile(fs, opts, nodes) {
|
|
|
27356
27382
|
return node.pread(max, at);
|
|
27357
27383
|
}),
|
|
27358
27384
|
pwrite: (bytes, at) => serial(() => {
|
|
27359
|
-
if (!
|
|
27385
|
+
if (!writable3) throw new KernelError("EBADF");
|
|
27360
27386
|
return node.pwrite(bytes, at);
|
|
27361
27387
|
}),
|
|
27362
27388
|
resize: (size) => serial(() => {
|
|
27363
|
-
if (!
|
|
27389
|
+
if (!writable3) throw new KernelError("EBADF");
|
|
27364
27390
|
return node.truncate(size);
|
|
27365
27391
|
}),
|
|
27366
27392
|
stat: () => serial(async () => ({
|
|
@@ -27376,7 +27402,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
27376
27402
|
takeOpenError();
|
|
27377
27403
|
await node.flush();
|
|
27378
27404
|
} finally {
|
|
27379
|
-
nodes?.closed(node,
|
|
27405
|
+
nodes?.closed(node, writable3);
|
|
27380
27406
|
}
|
|
27381
27407
|
})
|
|
27382
27408
|
});
|
|
@@ -29105,8 +29131,8 @@ var WasmProcess = class {
|
|
|
29105
29131
|
};
|
|
29106
29132
|
withDl(state) {
|
|
29107
29133
|
if (this.dlLog.length === 0) return state;
|
|
29108
|
-
const { next: next3, handle, free, live } = this.closures;
|
|
29109
|
-
const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...
|
|
29134
|
+
const { next: next3, handle, free, live: live2 } = this.closures;
|
|
29135
|
+
const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...live2] };
|
|
29110
29136
|
return { ...state, dl };
|
|
29111
29137
|
}
|
|
29112
29138
|
seedDl(dl) {
|
|
@@ -32330,7 +32356,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
32330
32356
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
32331
32357
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
32332
32358
|
};
|
|
32333
|
-
const
|
|
32359
|
+
const live2 = (fh) => {
|
|
32334
32360
|
const remote = handles.get(fh);
|
|
32335
32361
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
32336
32362
|
return fresh3(remote);
|
|
@@ -32349,7 +32375,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
32349
32375
|
}, againMs);
|
|
32350
32376
|
timer.unref?.();
|
|
32351
32377
|
});
|
|
32352
|
-
async function
|
|
32378
|
+
async function writable3(client, path, flags2) {
|
|
32353
32379
|
const { ifMatch: _, ...asked } = flags2;
|
|
32354
32380
|
const opening2 = () => client.call("open", { path: rel(path), ...asked });
|
|
32355
32381
|
try {
|
|
@@ -32380,7 +32406,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
32380
32406
|
async open(path, flags2) {
|
|
32381
32407
|
const client = current();
|
|
32382
32408
|
const token = client.token;
|
|
32383
|
-
const { opened: opened2, restore } = await
|
|
32409
|
+
const { opened: opened2, restore } = await writable3(client, path, flags2);
|
|
32384
32410
|
if (flags2.ifMatch !== void 0 && opened2.attr?.etag !== flags2.ifMatch) {
|
|
32385
32411
|
await client.call("release", { fh: opened2.fh }, true);
|
|
32386
32412
|
throw fsError2("ESTALE", `${path} changed on the host while it was being read`);
|
|
@@ -32395,7 +32421,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
32395
32421
|
return nextFh;
|
|
32396
32422
|
},
|
|
32397
32423
|
async read(fh, offset, size) {
|
|
32398
|
-
const remote =
|
|
32424
|
+
const remote = live2(fh);
|
|
32399
32425
|
return remote.client.read(
|
|
32400
32426
|
remote.fh,
|
|
32401
32427
|
offset,
|
|
@@ -32404,7 +32430,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
32404
32430
|
);
|
|
32405
32431
|
},
|
|
32406
32432
|
async write(fh, offset, bytes) {
|
|
32407
|
-
const remote =
|
|
32433
|
+
const remote = live2(fh);
|
|
32408
32434
|
const most = remote.client.maxIo;
|
|
32409
32435
|
for (let at = 0; at < bytes.length; at += most) {
|
|
32410
32436
|
await remote.client.write(remote.fh, offset + at, bytes.subarray(at, at + most));
|