@ai-ecoverse/slicc-kernel 1.152.1 → 1.153.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 +26 -2
- package/dist/driver-worker.js +147 -10
- package/dist/driver-worker.js.map +4 -4
- package/dist/index.js +168 -14
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +828 -152
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +147 -10
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +71 -21
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +966 -167
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +71 -21
- package/dist/process-worker.js.map +3 -3
- package/dist/types/client/attach.d.ts +2 -0
- package/dist/types/client/protocol.d.ts +4 -0
- package/dist/types/client/serve-client.d.ts +2 -0
- package/dist/types/embedder-relay.d.ts +58 -0
- package/dist/types/fs/unlinked.d.ts +4 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/kernel/embedder.d.ts +100 -0
- package/dist/types/kernel/fd-table.d.ts +3 -1
- package/dist/types/kernel/host.d.ts +8 -0
- package/dist/types/kernel/process.d.ts +17 -0
- package/dist/types/launcher.d.ts +13 -0
- package/dist/types/mount/mount-fs.d.ts +1 -0
- package/dist/types/node.d.ts +3 -0
- package/dist/types/process/kernel-streams.d.ts +2 -1
- package/dist/types/process/wasi/wasi-fds.d.ts +1 -0
- package/dist/types/realm/sync-fs-token-registry.d.ts +1 -0
- package/dist/types/serve.d.ts +3 -0
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -1922,9 +1922,9 @@ var OpfsFs = class {
|
|
|
1922
1922
|
this.lookups++;
|
|
1923
1923
|
if (split(path).length === 0) return this.root;
|
|
1924
1924
|
const cached = this.files.get(path);
|
|
1925
|
-
const
|
|
1926
|
-
if (cached && !
|
|
1927
|
-
if (cached &&
|
|
1925
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
1926
|
+
if (cached && !fresh3) this.files.delete(path);
|
|
1927
|
+
if (cached && fresh3) {
|
|
1928
1928
|
if (this.glanced(cached)) return this.remember(path, cached);
|
|
1929
1929
|
try {
|
|
1930
1930
|
await this.glance(cached);
|
|
@@ -2142,8 +2142,8 @@ var OpfsFs = class {
|
|
|
2142
2142
|
glanced(handle) {
|
|
2143
2143
|
if (this.exact > 0) return void 0;
|
|
2144
2144
|
const seen = this.glances.get(handle);
|
|
2145
|
-
const
|
|
2146
|
-
return
|
|
2145
|
+
const fresh3 = seen && seen.changes === this.changes && this.recent(seen, GLANCE_LOOKUPS);
|
|
2146
|
+
return fresh3 ? seen.file : void 0;
|
|
2147
2147
|
}
|
|
2148
2148
|
async glance(handle) {
|
|
2149
2149
|
const at = performance.now();
|
|
@@ -2333,13 +2333,13 @@ var OpfsFs = class {
|
|
|
2333
2333
|
async keptFor(path) {
|
|
2334
2334
|
const at = normalizePath(path);
|
|
2335
2335
|
const cached = this.files.get(at);
|
|
2336
|
-
const
|
|
2337
|
-
const [target, existed] =
|
|
2336
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
2337
|
+
const [target, existed] = fresh3 ? [at, true] : await this.writeTarget(path);
|
|
2338
2338
|
if (!existed) return [void 0, target, false];
|
|
2339
2339
|
this.refuse(target);
|
|
2340
2340
|
const [entry] = await this.meta.get([target]);
|
|
2341
2341
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
2342
|
-
const kept =
|
|
2342
|
+
const kept = fresh3 ? cached : this.files.get(target);
|
|
2343
2343
|
const usable2 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
2344
2344
|
return [usable2 ? kept : void 0, target, true];
|
|
2345
2345
|
}
|
|
@@ -4520,6 +4520,102 @@ function portCdpHook(ask, gone) {
|
|
|
4520
4520
|
});
|
|
4521
4521
|
}
|
|
4522
4522
|
|
|
4523
|
+
// src/embedder-relay.ts
|
|
4524
|
+
function fresh2(bytes) {
|
|
4525
|
+
return bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes : bytes.slice();
|
|
4526
|
+
}
|
|
4527
|
+
function embedderAsker(port) {
|
|
4528
|
+
const asks = /* @__PURE__ */ new Map();
|
|
4529
|
+
let next3 = 0;
|
|
4530
|
+
const post = (message3, transfer = []) => port.postMessage({ embedder: message3 }, transfer);
|
|
4531
|
+
const push = (asked, item) => {
|
|
4532
|
+
asked.chunks.push(item);
|
|
4533
|
+
asked.wake?.();
|
|
4534
|
+
};
|
|
4535
|
+
const reply = (id2, asked) => new ReadableStream(
|
|
4536
|
+
{
|
|
4537
|
+
pull: async (controller) => {
|
|
4538
|
+
if (asked.chunks.length === 0) {
|
|
4539
|
+
post({ id: id2, pull: true });
|
|
4540
|
+
await new Promise((resolve2) => {
|
|
4541
|
+
asked.wake = resolve2;
|
|
4542
|
+
});
|
|
4543
|
+
}
|
|
4544
|
+
const item = asked.chunks.shift();
|
|
4545
|
+
if (item instanceof Uint8Array) controller.enqueue(item);
|
|
4546
|
+
else if (item === null || item === void 0) {
|
|
4547
|
+
asks.delete(id2);
|
|
4548
|
+
controller.close();
|
|
4549
|
+
} else {
|
|
4550
|
+
asks.delete(id2);
|
|
4551
|
+
controller.error(Object.assign(new Error(item.message), { name: item.name }));
|
|
4552
|
+
}
|
|
4553
|
+
},
|
|
4554
|
+
cancel: (reason) => {
|
|
4555
|
+
asks.delete(id2);
|
|
4556
|
+
post({ id: id2, cancel: String(reason ?? "closed") });
|
|
4557
|
+
}
|
|
4558
|
+
},
|
|
4559
|
+
{ highWaterMark: 0 }
|
|
4560
|
+
);
|
|
4561
|
+
const sendBody = async (id2, asked) => {
|
|
4562
|
+
const got = await asked.body.read().catch(() => ({ done: true, value: void 0 }));
|
|
4563
|
+
if (got.done) post({ id: id2, bodyEnd: true });
|
|
4564
|
+
else {
|
|
4565
|
+
const bytes = fresh2(got.value);
|
|
4566
|
+
post({ id: id2, body: bytes }, [bytes.buffer]);
|
|
4567
|
+
}
|
|
4568
|
+
};
|
|
4569
|
+
const hookFor = (client, kinds) => ({
|
|
4570
|
+
kinds,
|
|
4571
|
+
handle: async (request3) => {
|
|
4572
|
+
const id2 = ++next3;
|
|
4573
|
+
const asked = {
|
|
4574
|
+
ready: Promise.withResolvers(),
|
|
4575
|
+
chunks: [],
|
|
4576
|
+
wake: void 0,
|
|
4577
|
+
body: request3.body.getReader(),
|
|
4578
|
+
progress: request3.progress
|
|
4579
|
+
};
|
|
4580
|
+
asks.set(id2, asked);
|
|
4581
|
+
const cancel = () => {
|
|
4582
|
+
asks.delete(id2);
|
|
4583
|
+
post({
|
|
4584
|
+
id: id2,
|
|
4585
|
+
cancel: String(request3.signal.reason?.message ?? "closed")
|
|
4586
|
+
});
|
|
4587
|
+
asked.ready.reject(request3.signal.reason);
|
|
4588
|
+
push(asked, { name: "AbortError", message: "cancelled" });
|
|
4589
|
+
};
|
|
4590
|
+
request3.signal.addEventListener("abort", cancel, { once: true });
|
|
4591
|
+
const { kind, options, stamp } = request3;
|
|
4592
|
+
post({ ask: { id: id2, client, kind, options, stamp } });
|
|
4593
|
+
await asked.ready.promise;
|
|
4594
|
+
return reply(id2, asked);
|
|
4595
|
+
}
|
|
4596
|
+
});
|
|
4597
|
+
const answer2 = (message3) => {
|
|
4598
|
+
const asked = asks.get(message3.id);
|
|
4599
|
+
if (!asked) return;
|
|
4600
|
+
if ("ready" in message3) asked.ready.resolve();
|
|
4601
|
+
else if ("chunk" in message3) push(asked, message3.chunk);
|
|
4602
|
+
else if ("done" in message3) push(asked, null);
|
|
4603
|
+
else if ("error" in message3) {
|
|
4604
|
+
asked.ready.reject(
|
|
4605
|
+
Object.assign(new Error(message3.error.message), { name: message3.error.name })
|
|
4606
|
+
);
|
|
4607
|
+
asks.delete(message3.id);
|
|
4608
|
+
void asked.body.cancel(message3.error.message).catch(() => void 0);
|
|
4609
|
+
push(asked, message3.error);
|
|
4610
|
+
} else if ("progress" in message3) asked.progress(message3.progress);
|
|
4611
|
+
else void sendBody(message3.id, asked);
|
|
4612
|
+
};
|
|
4613
|
+
return { hookFor, answer: answer2 };
|
|
4614
|
+
}
|
|
4615
|
+
function embedderReplyOf(data) {
|
|
4616
|
+
return data?.embedderReply;
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4523
4619
|
// src/facade/port.ts
|
|
4524
4620
|
var FACADE_GONE = "the facade host is gone";
|
|
4525
4621
|
function portFacadeHook(ask, gone) {
|
|
@@ -5347,6 +5443,7 @@ function kernelFdKind(file) {
|
|
|
5347
5443
|
if (file.tty) return "tty";
|
|
5348
5444
|
if (file.sealed) return "sealed";
|
|
5349
5445
|
if (file.clipboard) return "clipboard";
|
|
5446
|
+
if (file.embedder) return "embedder";
|
|
5350
5447
|
return file.seek ? "file" : "stream";
|
|
5351
5448
|
}
|
|
5352
5449
|
var FdTable = class _FdTable {
|
|
@@ -7231,7 +7328,7 @@ var UserDb = class {
|
|
|
7231
7328
|
joined(name2, extra);
|
|
7232
7329
|
group.push({ name: name2, gid: uid, members: [] });
|
|
7233
7330
|
passwd.push(row);
|
|
7234
|
-
const
|
|
7331
|
+
const fresh3 = !await this.fs.exists(home);
|
|
7235
7332
|
await this.fs.mkdir(home, { recursive: true });
|
|
7236
7333
|
try {
|
|
7237
7334
|
await this.provision(row, this.umaskFor(options), shared);
|
|
@@ -7239,7 +7336,7 @@ var UserDb = class {
|
|
|
7239
7336
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
7240
7337
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
7241
7338
|
} catch (err) {
|
|
7242
|
-
if (
|
|
7339
|
+
if (fresh3) await this.fs.rm(home, { recursive: true, force: true });
|
|
7243
7340
|
throw err;
|
|
7244
7341
|
}
|
|
7245
7342
|
remember();
|
|
@@ -7303,7 +7400,7 @@ var UserDb = class {
|
|
|
7303
7400
|
};
|
|
7304
7401
|
|
|
7305
7402
|
// src/client/protocol.ts
|
|
7306
|
-
var PROTOCOL = [1,
|
|
7403
|
+
var PROTOCOL = [1, 13];
|
|
7307
7404
|
var FS_METHODS = [
|
|
7308
7405
|
"readFile",
|
|
7309
7406
|
"writeFile",
|
|
@@ -7470,14 +7567,15 @@ async function runAs(l, self, requested) {
|
|
|
7470
7567
|
function clientCred(self) {
|
|
7471
7568
|
return self ? credOf(self) : copyCred(ROOT);
|
|
7472
7569
|
}
|
|
7473
|
-
async function runTagged(l, self, options, tag) {
|
|
7570
|
+
async function runTagged(l, self, options, tag, session = -1) {
|
|
7474
7571
|
tagOption(options.tag);
|
|
7475
7572
|
const tags = withTag(withTag(void 0, tag), options.tag);
|
|
7476
7573
|
return {
|
|
7477
7574
|
user: await runAs(l, self, options.user),
|
|
7478
7575
|
tag,
|
|
7479
7576
|
tags,
|
|
7480
|
-
tagBase: tag === void 0 ? 0 : 1
|
|
7577
|
+
tagBase: tag === void 0 ? 0 : 1,
|
|
7578
|
+
session
|
|
7481
7579
|
};
|
|
7482
7580
|
}
|
|
7483
7581
|
function processes(l, self) {
|
|
@@ -7558,10 +7656,12 @@ function facadeRegistry(send2, gone) {
|
|
|
7558
7656
|
}
|
|
7559
7657
|
};
|
|
7560
7658
|
}
|
|
7561
|
-
function hostRegistries(send2, gone) {
|
|
7659
|
+
function hostRegistries(send2, gone, port) {
|
|
7562
7660
|
const cdps = cdpRegistry(send2, gone);
|
|
7563
7661
|
const facades = facadeRegistry(send2, gone);
|
|
7662
|
+
const requests = requestBinding(send2, port);
|
|
7564
7663
|
return {
|
|
7664
|
+
requests,
|
|
7565
7665
|
answer(l, req) {
|
|
7566
7666
|
if (req.op === "serve-cdp") return cdps.serve(l, req);
|
|
7567
7667
|
if (req.op === "unserve-cdp") return cdps.drop(req.registration);
|
|
@@ -7569,6 +7669,7 @@ function hostRegistries(send2, gone) {
|
|
|
7569
7669
|
return facades.drop(req.registration);
|
|
7570
7670
|
},
|
|
7571
7671
|
close() {
|
|
7672
|
+
requests.close();
|
|
7572
7673
|
cdps.close();
|
|
7573
7674
|
facades.close();
|
|
7574
7675
|
}
|
|
@@ -7603,6 +7704,28 @@ var TRAITS_WATCH = -1;
|
|
|
7603
7704
|
function traitsWatch(launcher, transport, send2) {
|
|
7604
7705
|
return launcher.onTraits(() => send2({ traits: transport.traits }));
|
|
7605
7706
|
}
|
|
7707
|
+
function requestBinding(send2, port) {
|
|
7708
|
+
const asker = embedderAsker({ postMessage: (m, t) => send2(m, t) });
|
|
7709
|
+
let unbind;
|
|
7710
|
+
port.addEventListener("message", (event) => {
|
|
7711
|
+
const reply = embedderReplyOf(event.data);
|
|
7712
|
+
if (reply) asker.answer(reply);
|
|
7713
|
+
});
|
|
7714
|
+
return {
|
|
7715
|
+
async accept(host, hello) {
|
|
7716
|
+
if (!hello.requests) return void 0;
|
|
7717
|
+
if (!host.attachRequests || host.session === void 0)
|
|
7718
|
+
return "EPERM: this port may not answer requests";
|
|
7719
|
+
const launcher = await host.launcher();
|
|
7720
|
+
unbind = launcher.embedder.register(
|
|
7721
|
+
host.session,
|
|
7722
|
+
asker.hookFor(host.session, hello.requests)
|
|
7723
|
+
);
|
|
7724
|
+
return void 0;
|
|
7725
|
+
},
|
|
7726
|
+
close: () => unbind?.()
|
|
7727
|
+
};
|
|
7728
|
+
}
|
|
7606
7729
|
function serveClient(port, host) {
|
|
7607
7730
|
let state = "new";
|
|
7608
7731
|
let self;
|
|
@@ -7617,7 +7740,7 @@ function serveClient(port, host) {
|
|
|
7617
7740
|
if (state !== "closed") port.postMessage(message3, transfer);
|
|
7618
7741
|
};
|
|
7619
7742
|
const reply = (id2, body, transfer) => send2({ id: id2, ...body }, transfer);
|
|
7620
|
-
const hosts = hostRegistries(send2, ended.promise);
|
|
7743
|
+
const hosts = hostRegistries(send2, ended.promise, port);
|
|
7621
7744
|
function detach(kill = false, bye = "the slicc-kernel detached this client") {
|
|
7622
7745
|
if (state === "closed") return;
|
|
7623
7746
|
send2({ bye });
|
|
@@ -7634,7 +7757,7 @@ function serveClient(port, host) {
|
|
|
7634
7757
|
ended.resolve();
|
|
7635
7758
|
}
|
|
7636
7759
|
async function hello(message3) {
|
|
7637
|
-
const refused3 = versionError(message3.protocol);
|
|
7760
|
+
const refused3 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
7638
7761
|
if (refused3) {
|
|
7639
7762
|
send2({ hello: { protocol: PROTOCOL, error: refused3 } });
|
|
7640
7763
|
detach();
|
|
@@ -7659,7 +7782,7 @@ function serveClient(port, host) {
|
|
|
7659
7782
|
async function terminal(req, l) {
|
|
7660
7783
|
const session = await l.openTerminal(req.argv, {
|
|
7661
7784
|
...req.options,
|
|
7662
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
7785
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
7663
7786
|
onData: (bytes) => reply(req.id, { fd: 1, bytes: bytes.slice() })
|
|
7664
7787
|
});
|
|
7665
7788
|
if (state === "closed") {
|
|
@@ -7682,7 +7805,7 @@ function serveClient(port, host) {
|
|
|
7682
7805
|
let leader;
|
|
7683
7806
|
const result = await l.run(req.argv, {
|
|
7684
7807
|
...req.options,
|
|
7685
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
7808
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
7686
7809
|
collect: false,
|
|
7687
7810
|
onStdout: out(1),
|
|
7688
7811
|
onStderr: out(2),
|
|
@@ -7926,7 +8049,7 @@ function satisfies(version, range2) {
|
|
|
7926
8049
|
}
|
|
7927
8050
|
|
|
7928
8051
|
// src/version.ts
|
|
7929
|
-
var KERNEL_VERSION = true ? "1.
|
|
8052
|
+
var KERNEL_VERSION = true ? "1.153.0" : "0.0.0-dev";
|
|
7930
8053
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7931
8054
|
function procVersion() {
|
|
7932
8055
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -8771,9 +8894,9 @@ var Crontabs = class {
|
|
|
8771
8894
|
const json5 = JSON.stringify({ v: TAGS_VERSION, ...kept });
|
|
8772
8895
|
if (json5 === await fs.readFile(TAGS_PATH).catch(() => "")) return;
|
|
8773
8896
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
8774
|
-
const
|
|
8775
|
-
await fs.writeFile(
|
|
8776
|
-
await fs.rename(
|
|
8897
|
+
const fresh3 = `${TAGS_PATH}.${crypto.randomUUID()}.new`;
|
|
8898
|
+
await fs.writeFile(fresh3, json5, owner);
|
|
8899
|
+
await fs.rename(fresh3, TAGS_PATH);
|
|
8777
8900
|
}
|
|
8778
8901
|
async install(path, target, text, caller) {
|
|
8779
8902
|
if (text.length > CRONTAB_MAX) return { error: "crontab: the table is too long" };
|
|
@@ -8787,11 +8910,11 @@ var Crontabs = class {
|
|
|
8787
8910
|
await fs.mkdir(SPOOL_DIR, { recursive: true });
|
|
8788
8911
|
if (owners) await fs.chown?.(SPOOL_DIR, { uid: 0, gid: 0, mode: 448, follow: false });
|
|
8789
8912
|
}
|
|
8790
|
-
const
|
|
8913
|
+
const fresh3 = `${SPOOL_DIR}/.${target.name}.${crypto.randomUUID()}.new`;
|
|
8791
8914
|
const owner = owners ? { uid: target.uid, gid: target.gid, mode: 384 } : void 0;
|
|
8792
8915
|
await this.retag(path, text, caller);
|
|
8793
|
-
await fs.writeFile(
|
|
8794
|
-
await fs.rename(
|
|
8916
|
+
await fs.writeFile(fresh3, text, owner);
|
|
8917
|
+
await fs.rename(fresh3, path);
|
|
8795
8918
|
return { text: "" };
|
|
8796
8919
|
}
|
|
8797
8920
|
};
|
|
@@ -8803,6 +8926,7 @@ var PathMarks = class {
|
|
|
8803
8926
|
floor = 0;
|
|
8804
8927
|
touched = /* @__PURE__ */ new Map();
|
|
8805
8928
|
flying = /* @__PURE__ */ new Map();
|
|
8929
|
+
waiting = /* @__PURE__ */ new Set();
|
|
8806
8930
|
generation() {
|
|
8807
8931
|
return this.gen;
|
|
8808
8932
|
}
|
|
@@ -8835,10 +8959,22 @@ var PathMarks = class {
|
|
|
8835
8959
|
const n = (this.flying.get(p) ?? 1) - 1;
|
|
8836
8960
|
if (n > 0) this.flying.set(p, n);
|
|
8837
8961
|
else this.flying.delete(p);
|
|
8962
|
+
for (const wake of [...this.waiting]) wake();
|
|
8838
8963
|
this.touch(p);
|
|
8839
8964
|
}
|
|
8840
8965
|
}
|
|
8841
8966
|
}
|
|
8967
|
+
async landed(path) {
|
|
8968
|
+
if (!this.inFlight(path)) return;
|
|
8969
|
+
await new Promise((resolve2) => {
|
|
8970
|
+
const wake = () => {
|
|
8971
|
+
if (this.inFlight(path)) return;
|
|
8972
|
+
this.waiting.delete(wake);
|
|
8973
|
+
resolve2();
|
|
8974
|
+
};
|
|
8975
|
+
this.waiting.add(wake);
|
|
8976
|
+
});
|
|
8977
|
+
}
|
|
8842
8978
|
inFlight(path) {
|
|
8843
8979
|
for (let p = path; this.flying.size > 0; p = parentOf5(p)) {
|
|
8844
8980
|
if (this.flying.has(p)) return true;
|
|
@@ -9016,6 +9152,9 @@ var UnlinkedKeeper = class {
|
|
|
9016
9152
|
changedSince(path, gen) {
|
|
9017
9153
|
return this.marks.changedSince(path, gen);
|
|
9018
9154
|
}
|
|
9155
|
+
landed(path) {
|
|
9156
|
+
return this.marks.landed(path);
|
|
9157
|
+
}
|
|
9019
9158
|
inFlight(path) {
|
|
9020
9159
|
return this.marks.inFlight(path);
|
|
9021
9160
|
}
|
|
@@ -9051,15 +9190,15 @@ var UnlinkedKeeper = class {
|
|
|
9051
9190
|
const releases = [];
|
|
9052
9191
|
const take = async () => {
|
|
9053
9192
|
for (; ; ) {
|
|
9054
|
-
const
|
|
9055
|
-
if (
|
|
9056
|
-
|
|
9057
|
-
if (paths.some((path) => path >
|
|
9193
|
+
const fresh3 = [...this.heldWithin(target).keys()].filter((path) => !paths.includes(path));
|
|
9194
|
+
if (fresh3.length === 0) return;
|
|
9195
|
+
fresh3.sort();
|
|
9196
|
+
if (paths.some((path) => path > fresh3[0])) {
|
|
9058
9197
|
for (const release of releases.splice(0)) release();
|
|
9059
|
-
|
|
9060
|
-
|
|
9198
|
+
fresh3.push(...paths.splice(0));
|
|
9199
|
+
fresh3.sort();
|
|
9061
9200
|
}
|
|
9062
|
-
for (const path of
|
|
9201
|
+
for (const path of fresh3) {
|
|
9063
9202
|
paths.push(path);
|
|
9064
9203
|
releases.push(await this.gate.acquire(path));
|
|
9065
9204
|
}
|
|
@@ -9394,10 +9533,10 @@ var CronService = class {
|
|
|
9394
9533
|
const text = JSON.stringify(stamp);
|
|
9395
9534
|
const old = await fs.readFile(STAMP_PATH).catch(() => void 0);
|
|
9396
9535
|
if (old === text || old === void 0 && text === EMPTY_STAMP) return;
|
|
9397
|
-
const
|
|
9536
|
+
const fresh3 = `${STAMP_PATH}.new`;
|
|
9398
9537
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
9399
|
-
await fs.writeFile(
|
|
9400
|
-
await fs.rename(
|
|
9538
|
+
await fs.writeFile(fresh3, text, owner);
|
|
9539
|
+
await fs.rename(fresh3, STAMP_PATH);
|
|
9401
9540
|
}
|
|
9402
9541
|
async load() {
|
|
9403
9542
|
const { fs } = this.host;
|
|
@@ -10747,10 +10886,10 @@ var FreshModules = class {
|
|
|
10747
10886
|
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
10748
10887
|
}
|
|
10749
10888
|
forget(pid) {
|
|
10750
|
-
for (const [path,
|
|
10889
|
+
for (const [path, fresh3] of this.fresh) if (fresh3.pid === pid) this.fresh.delete(path);
|
|
10751
10890
|
}
|
|
10752
|
-
drop(
|
|
10753
|
-
for (const [key, note] of [...this.fresh]) if (note ===
|
|
10891
|
+
drop(fresh3) {
|
|
10892
|
+
for (const [key, note] of [...this.fresh]) if (note === fresh3) this.fresh.delete(key);
|
|
10754
10893
|
}
|
|
10755
10894
|
moved(from, to) {
|
|
10756
10895
|
const source = normalizePath(from);
|
|
@@ -10759,10 +10898,10 @@ var FreshModules = class {
|
|
|
10759
10898
|
for (const key of [...this.fresh.keys()]) {
|
|
10760
10899
|
if (key === target || within5(key, target)) this.fresh.delete(key);
|
|
10761
10900
|
}
|
|
10762
|
-
for (const [key,
|
|
10901
|
+
for (const [key, fresh3] of [...this.fresh]) {
|
|
10763
10902
|
if (key !== source && !within5(key, source)) continue;
|
|
10764
10903
|
this.fresh.delete(key);
|
|
10765
|
-
this.fresh.set(target + key.slice(source.length),
|
|
10904
|
+
this.fresh.set(target + key.slice(source.length), fresh3);
|
|
10766
10905
|
}
|
|
10767
10906
|
}
|
|
10768
10907
|
wrap(fs) {
|
|
@@ -10772,15 +10911,15 @@ var FreshModules = class {
|
|
|
10772
10911
|
};
|
|
10773
10912
|
const decide = async (given, known) => {
|
|
10774
10913
|
const path = normalizePath(given);
|
|
10775
|
-
const
|
|
10776
|
-
if (!
|
|
10914
|
+
const fresh3 = this.fresh.get(path);
|
|
10915
|
+
if (!fresh3) return;
|
|
10777
10916
|
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
10778
|
-
const want = isModule(bytes) ? 73 & ~
|
|
10779
|
-
|
|
10780
|
-
if (want ===
|
|
10917
|
+
const want = isModule(bytes) ? 73 & ~fresh3.umask : 0;
|
|
10918
|
+
fresh3.setup = false;
|
|
10919
|
+
if (want === fresh3.added) return;
|
|
10781
10920
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
10782
|
-
await fs.chmod(path, mode & ~
|
|
10783
|
-
|
|
10921
|
+
await fs.chmod(path, mode & ~fresh3.added | want);
|
|
10922
|
+
fresh3.added = want;
|
|
10784
10923
|
};
|
|
10785
10924
|
const overrides = {
|
|
10786
10925
|
writeFile: async (path, content, owner) => {
|
|
@@ -10793,9 +10932,9 @@ var FreshModules = class {
|
|
|
10793
10932
|
}
|
|
10794
10933
|
},
|
|
10795
10934
|
chmod: async (path, mode) => {
|
|
10796
|
-
const
|
|
10797
|
-
if (
|
|
10798
|
-
else if (
|
|
10935
|
+
const fresh3 = this.fresh.get(normalizePath(path));
|
|
10936
|
+
if (fresh3?.setup && (mode & 4095) === (438 & ~fresh3.umask)) fresh3.setup = false;
|
|
10937
|
+
else if (fresh3) this.drop(fresh3);
|
|
10799
10938
|
await fs.chmod(path, mode);
|
|
10800
10939
|
},
|
|
10801
10940
|
rm: async (path, options) => {
|
|
@@ -10812,8 +10951,8 @@ var FreshModules = class {
|
|
|
10812
10951
|
link: async (from, to, follow2) => {
|
|
10813
10952
|
await fs.link(from, to, follow2);
|
|
10814
10953
|
const source = follow2 && fs.realpath ? await fs.realpath(from, true).catch(() => from) : from;
|
|
10815
|
-
const
|
|
10816
|
-
if (
|
|
10954
|
+
const fresh3 = this.fresh.get(normalizePath(source));
|
|
10955
|
+
if (fresh3) this.fresh.set(normalizePath(to), fresh3);
|
|
10817
10956
|
}
|
|
10818
10957
|
};
|
|
10819
10958
|
const ranged2 = rangedOps(fs);
|
|
@@ -11131,7 +11270,7 @@ var FsWatchers = class {
|
|
|
11131
11270
|
};
|
|
11132
11271
|
const content = (run2, types) => async (...args) => {
|
|
11133
11272
|
const at = normalizePath(args[0]);
|
|
11134
|
-
const
|
|
11273
|
+
const fresh3 = this.covers(at) && !await fs.exists(at).catch(() => true);
|
|
11135
11274
|
let done5 = false;
|
|
11136
11275
|
try {
|
|
11137
11276
|
await run2(...args);
|
|
@@ -11140,11 +11279,11 @@ var FsWatchers = class {
|
|
|
11140
11279
|
const real = await realOf(at);
|
|
11141
11280
|
const paths = real === at ? [at] : [at, real];
|
|
11142
11281
|
this.report(paths);
|
|
11143
|
-
if (done5) for (const type of types(
|
|
11282
|
+
if (done5) for (const type of types(fresh3, args)) this.emit(type, paths);
|
|
11144
11283
|
}
|
|
11145
11284
|
};
|
|
11146
|
-
const written2 = (
|
|
11147
|
-
const overwritten = (
|
|
11285
|
+
const written2 = (fresh3) => fresh3 ? ["rename", "change"] : ["change"];
|
|
11286
|
+
const overwritten = (fresh3, args) => fresh3 || args[1].length === 0 ? written2(fresh3) : ["change", "change"];
|
|
11148
11287
|
const reshaping = (run2) => async (...args) => {
|
|
11149
11288
|
this.reshaped();
|
|
11150
11289
|
try {
|
|
@@ -11171,14 +11310,14 @@ var FsWatchers = class {
|
|
|
11171
11310
|
if (created4.length > 0 || !await fs.exists(ancestor)) created4.push(ancestor);
|
|
11172
11311
|
}
|
|
11173
11312
|
}
|
|
11174
|
-
const
|
|
11313
|
+
const fresh3 = !options?.recursive || this.typed.size > 0 && !await fs.exists(path);
|
|
11175
11314
|
let done5 = false;
|
|
11176
11315
|
try {
|
|
11177
11316
|
await fs.mkdir(path, options);
|
|
11178
11317
|
done5 = true;
|
|
11179
11318
|
} finally {
|
|
11180
11319
|
this.report([...created4, path]);
|
|
11181
|
-
if (done5) this.emit("rename",
|
|
11320
|
+
if (done5) this.emit("rename", fresh3 ? [...created4, path] : created4);
|
|
11182
11321
|
}
|
|
11183
11322
|
},
|
|
11184
11323
|
rm: reshaping(after(fs.rm.bind(fs), (path) => [path], "rename")),
|
|
@@ -11634,6 +11773,403 @@ var ClipboardBroker = class {
|
|
|
11634
11773
|
}
|
|
11635
11774
|
};
|
|
11636
11775
|
|
|
11776
|
+
// src/kernel/embedder.ts
|
|
11777
|
+
var EMBEDDER_PATH = "/dev/embedder";
|
|
11778
|
+
var EMBEDDER_HEADER_MAX = 64 * 1024;
|
|
11779
|
+
var EMBEDDER_WINDOW = 1024 * 1024;
|
|
11780
|
+
var EMBEDDER_BUDGET = 256 * 1024 * 1024;
|
|
11781
|
+
var EMBEDDER_PER_PROCESS = 16;
|
|
11782
|
+
var EMBEDDER_PROGRESS_PER_SECOND = 4;
|
|
11783
|
+
var KIND = /^[a-z][a-z0-9-]*(\.[a-z0-9-]+)*$/;
|
|
11784
|
+
var NL = 10;
|
|
11785
|
+
var READY2 = { readable: true, writable: true, hangup: false };
|
|
11786
|
+
function lineOf2(err) {
|
|
11787
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
11788
|
+
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
11789
|
+
}
|
|
11790
|
+
var ERRNOS = {
|
|
11791
|
+
NotAllowedError: "EACCES",
|
|
11792
|
+
AbortError: "EACCES",
|
|
11793
|
+
NotSupportedError: "ENOTSUP",
|
|
11794
|
+
NotFoundError: "ENOENT"
|
|
11795
|
+
};
|
|
11796
|
+
function embedderFailure(err) {
|
|
11797
|
+
if (err instanceof KernelError) return err;
|
|
11798
|
+
const name2 = err?.name;
|
|
11799
|
+
return new KernelError(ERRNOS[String(name2)] ?? "EIO", lineOf2(err));
|
|
11800
|
+
}
|
|
11801
|
+
function headerOf(bytes) {
|
|
11802
|
+
let parsed2;
|
|
11803
|
+
try {
|
|
11804
|
+
parsed2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
11805
|
+
} catch {
|
|
11806
|
+
throw new KernelError("EINVAL", "the request header is not JSON");
|
|
11807
|
+
}
|
|
11808
|
+
if (typeof parsed2 !== "object" || parsed2 === null || Array.isArray(parsed2))
|
|
11809
|
+
throw new KernelError("EINVAL", "the request header is not an object");
|
|
11810
|
+
const { kind, ...options } = parsed2;
|
|
11811
|
+
if (typeof kind !== "string" || kind.length > 64 || !KIND.test(kind))
|
|
11812
|
+
throw new KernelError("EINVAL", "the request has no valid kind");
|
|
11813
|
+
return { kind, options };
|
|
11814
|
+
}
|
|
11815
|
+
function joined3(a, b) {
|
|
11816
|
+
const out = new Uint8Array(a.length + b.length);
|
|
11817
|
+
out.set(a);
|
|
11818
|
+
out.set(b, a.length);
|
|
11819
|
+
return out;
|
|
11820
|
+
}
|
|
11821
|
+
function aborted(signal) {
|
|
11822
|
+
if (!signal) return void 0;
|
|
11823
|
+
return new Promise((_, reject) => {
|
|
11824
|
+
const stop = () => reject(new KernelError("EINTR"));
|
|
11825
|
+
if (signal.aborted) stop();
|
|
11826
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
11827
|
+
});
|
|
11828
|
+
}
|
|
11829
|
+
async function interruptible2(work, signal) {
|
|
11830
|
+
const stop = aborted(signal);
|
|
11831
|
+
if (!stop) return work;
|
|
11832
|
+
stop.catch(() => void 0);
|
|
11833
|
+
return Promise.race([work, stop]);
|
|
11834
|
+
}
|
|
11835
|
+
var Budget2 = class {
|
|
11836
|
+
used = 0;
|
|
11837
|
+
limit;
|
|
11838
|
+
constructor(limit) {
|
|
11839
|
+
this.limit = limit;
|
|
11840
|
+
}
|
|
11841
|
+
take(n) {
|
|
11842
|
+
if (this.used + n > this.limit) return false;
|
|
11843
|
+
this.used += n;
|
|
11844
|
+
return true;
|
|
11845
|
+
}
|
|
11846
|
+
give(n) {
|
|
11847
|
+
this.used = Math.max(0, this.used - n);
|
|
11848
|
+
}
|
|
11849
|
+
};
|
|
11850
|
+
var BodyPipe = class {
|
|
11851
|
+
queue = [];
|
|
11852
|
+
size = 0;
|
|
11853
|
+
ended = false;
|
|
11854
|
+
wake;
|
|
11855
|
+
room;
|
|
11856
|
+
stream;
|
|
11857
|
+
constructor() {
|
|
11858
|
+
this.stream = new ReadableStream(
|
|
11859
|
+
{
|
|
11860
|
+
pull: async (controller) => {
|
|
11861
|
+
while (this.queue.length === 0 && !this.ended) {
|
|
11862
|
+
await new Promise((resolve2) => {
|
|
11863
|
+
this.wake = resolve2;
|
|
11864
|
+
});
|
|
11865
|
+
}
|
|
11866
|
+
const next3 = this.queue.shift();
|
|
11867
|
+
if (next3) {
|
|
11868
|
+
this.size -= next3.length;
|
|
11869
|
+
this.room?.();
|
|
11870
|
+
controller.enqueue(next3);
|
|
11871
|
+
} else controller.close();
|
|
11872
|
+
}
|
|
11873
|
+
},
|
|
11874
|
+
{ highWaterMark: 0 }
|
|
11875
|
+
);
|
|
11876
|
+
}
|
|
11877
|
+
get full() {
|
|
11878
|
+
return this.size >= EMBEDDER_WINDOW;
|
|
11879
|
+
}
|
|
11880
|
+
push(bytes) {
|
|
11881
|
+
if (bytes.length === 0) return;
|
|
11882
|
+
this.queue.push(bytes.slice());
|
|
11883
|
+
this.size += bytes.length;
|
|
11884
|
+
this.wake?.();
|
|
11885
|
+
}
|
|
11886
|
+
waitRoom() {
|
|
11887
|
+
return new Promise((resolve2) => {
|
|
11888
|
+
this.room = resolve2;
|
|
11889
|
+
});
|
|
11890
|
+
}
|
|
11891
|
+
end() {
|
|
11892
|
+
this.ended = true;
|
|
11893
|
+
this.wake?.();
|
|
11894
|
+
this.room?.();
|
|
11895
|
+
}
|
|
11896
|
+
};
|
|
11897
|
+
function replyStream(reply) {
|
|
11898
|
+
if (reply instanceof ReadableStream) return reply;
|
|
11899
|
+
const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
|
|
11900
|
+
return new ReadableStream({
|
|
11901
|
+
start(controller) {
|
|
11902
|
+
if (bytes.length > 0) controller.enqueue(bytes);
|
|
11903
|
+
controller.close();
|
|
11904
|
+
}
|
|
11905
|
+
});
|
|
11906
|
+
}
|
|
11907
|
+
var Throttle = class {
|
|
11908
|
+
window = 0;
|
|
11909
|
+
count = 0;
|
|
11910
|
+
allow(now) {
|
|
11911
|
+
if (now - this.window >= 1e3) {
|
|
11912
|
+
this.window = now;
|
|
11913
|
+
this.count = 0;
|
|
11914
|
+
}
|
|
11915
|
+
this.count += 1;
|
|
11916
|
+
return this.count <= EMBEDDER_PROGRESS_PER_SECOND;
|
|
11917
|
+
}
|
|
11918
|
+
};
|
|
11919
|
+
var EmbedderChannel = class {
|
|
11920
|
+
access;
|
|
11921
|
+
owner;
|
|
11922
|
+
caller;
|
|
11923
|
+
broker;
|
|
11924
|
+
header = new Uint8Array(0);
|
|
11925
|
+
body;
|
|
11926
|
+
reply;
|
|
11927
|
+
replied;
|
|
11928
|
+
rest;
|
|
11929
|
+
done = false;
|
|
11930
|
+
failure;
|
|
11931
|
+
reported = false;
|
|
11932
|
+
abort = new AbortController();
|
|
11933
|
+
closed = false;
|
|
11934
|
+
throttle = new Throttle();
|
|
11935
|
+
constructor(broker, access2, caller) {
|
|
11936
|
+
this.broker = broker;
|
|
11937
|
+
this.access = access2;
|
|
11938
|
+
this.caller = caller;
|
|
11939
|
+
this.owner = caller.pid;
|
|
11940
|
+
}
|
|
11941
|
+
get dispatched() {
|
|
11942
|
+
return this.body !== void 0;
|
|
11943
|
+
}
|
|
11944
|
+
fail(err) {
|
|
11945
|
+
this.failure ??= embedderFailure(err);
|
|
11946
|
+
return this.failure;
|
|
11947
|
+
}
|
|
11948
|
+
report(err) {
|
|
11949
|
+
this.reported = true;
|
|
11950
|
+
return this.fail(err);
|
|
11951
|
+
}
|
|
11952
|
+
async dispatch(bytes) {
|
|
11953
|
+
const { kind, options } = headerOf(bytes);
|
|
11954
|
+
const stamp = await this.broker.admit(kind, this.caller);
|
|
11955
|
+
const hook = this.broker.hookFor(this.caller.client);
|
|
11956
|
+
const body = new BodyPipe();
|
|
11957
|
+
this.body = body;
|
|
11958
|
+
const caller = this.caller;
|
|
11959
|
+
const progress = (line) => {
|
|
11960
|
+
if (this.throttle.allow(Date.now())) caller.progress(lineOf2(line));
|
|
11961
|
+
};
|
|
11962
|
+
const asked = Promise.resolve().then(
|
|
11963
|
+
() => hook.handle({
|
|
11964
|
+
kind,
|
|
11965
|
+
options,
|
|
11966
|
+
body: body.stream,
|
|
11967
|
+
stamp,
|
|
11968
|
+
signal: this.abort.signal,
|
|
11969
|
+
progress
|
|
11970
|
+
})
|
|
11971
|
+
).then((reply) => replyStream(reply).getReader());
|
|
11972
|
+
this.replied = asked.catch((err) => {
|
|
11973
|
+
body.end();
|
|
11974
|
+
throw this.fail(err);
|
|
11975
|
+
});
|
|
11976
|
+
this.replied.catch(() => void 0);
|
|
11977
|
+
}
|
|
11978
|
+
async write(bytes, signal) {
|
|
11979
|
+
if (this.access === "read") throw new KernelError("EBADF");
|
|
11980
|
+
if (this.failure) throw this.report(this.failure);
|
|
11981
|
+
if (this.reply || this.done) throw new KernelError("EBADF");
|
|
11982
|
+
if (this.body) return this.writeBody(bytes, signal);
|
|
11983
|
+
const at = bytes.indexOf(NL);
|
|
11984
|
+
const head = at < 0 ? bytes : bytes.subarray(0, at);
|
|
11985
|
+
if (this.header.length + head.length > EMBEDDER_HEADER_MAX)
|
|
11986
|
+
throw this.report(new KernelError("EINVAL", "the request header is too long"));
|
|
11987
|
+
this.header = joined3(this.header, head);
|
|
11988
|
+
if (at < 0) return bytes.length;
|
|
11989
|
+
try {
|
|
11990
|
+
await this.dispatch(this.header);
|
|
11991
|
+
} catch (err) {
|
|
11992
|
+
throw this.report(err);
|
|
11993
|
+
}
|
|
11994
|
+
this.body?.push(bytes.subarray(at + 1));
|
|
11995
|
+
return bytes.length;
|
|
11996
|
+
}
|
|
11997
|
+
async writeBody(bytes, signal) {
|
|
11998
|
+
const body = this.body;
|
|
11999
|
+
while (body.full && !this.failure) {
|
|
12000
|
+
await interruptible2(body.waitRoom(), signal).catch((err) => {
|
|
12001
|
+
this.cancel("interrupted");
|
|
12002
|
+
throw err;
|
|
12003
|
+
});
|
|
12004
|
+
}
|
|
12005
|
+
if (this.failure) throw this.report(this.failure);
|
|
12006
|
+
body.push(bytes);
|
|
12007
|
+
return bytes.length;
|
|
12008
|
+
}
|
|
12009
|
+
async readerOf(signal) {
|
|
12010
|
+
if (this.reply) return this.reply;
|
|
12011
|
+
if (!this.body) {
|
|
12012
|
+
try {
|
|
12013
|
+
await this.dispatch(this.header);
|
|
12014
|
+
} catch (err) {
|
|
12015
|
+
throw this.fail(err);
|
|
12016
|
+
}
|
|
12017
|
+
}
|
|
12018
|
+
this.body?.end();
|
|
12019
|
+
this.reply = await interruptible2(
|
|
12020
|
+
this.replied,
|
|
12021
|
+
signal
|
|
12022
|
+
);
|
|
12023
|
+
return this.reply;
|
|
12024
|
+
}
|
|
12025
|
+
async read(max, signal) {
|
|
12026
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
12027
|
+
if (this.failure) throw this.report(this.failure);
|
|
12028
|
+
if (this.done || max <= 0) return new Uint8Array(0);
|
|
12029
|
+
try {
|
|
12030
|
+
return await this.next(max, signal);
|
|
12031
|
+
} catch (err) {
|
|
12032
|
+
if (err instanceof KernelError && err.code === "EINTR") {
|
|
12033
|
+
this.cancel("interrupted");
|
|
12034
|
+
throw err;
|
|
12035
|
+
}
|
|
12036
|
+
throw this.report(err);
|
|
12037
|
+
}
|
|
12038
|
+
}
|
|
12039
|
+
async next(max, signal) {
|
|
12040
|
+
const reader = await this.readerOf(signal);
|
|
12041
|
+
let chunk2 = this.rest;
|
|
12042
|
+
this.rest = void 0;
|
|
12043
|
+
if (!chunk2) {
|
|
12044
|
+
const got = await interruptible2(reader.read(), signal);
|
|
12045
|
+
if (got.done) {
|
|
12046
|
+
this.done = true;
|
|
12047
|
+
return new Uint8Array(0);
|
|
12048
|
+
}
|
|
12049
|
+
chunk2 = got.value;
|
|
12050
|
+
}
|
|
12051
|
+
if (chunk2.length > max) this.rest = chunk2.subarray(max);
|
|
12052
|
+
return chunk2.subarray(0, max);
|
|
12053
|
+
}
|
|
12054
|
+
poll() {
|
|
12055
|
+
return this.body?.full ? { ...READY2, writable: false } : READY2;
|
|
12056
|
+
}
|
|
12057
|
+
cancel(reason) {
|
|
12058
|
+
if (this.abort.signal.aborted) return;
|
|
12059
|
+
this.abort.abort(new DOMException(reason, "AbortError"));
|
|
12060
|
+
this.body?.end();
|
|
12061
|
+
void this.reply?.cancel(reason).catch(() => void 0);
|
|
12062
|
+
}
|
|
12063
|
+
async close() {
|
|
12064
|
+
if (this.closed) return;
|
|
12065
|
+
const signal = this.caller.closing();
|
|
12066
|
+
this.closed = true;
|
|
12067
|
+
try {
|
|
12068
|
+
if (this.access === "read") return;
|
|
12069
|
+
if (this.failure) {
|
|
12070
|
+
if (this.reported) return;
|
|
12071
|
+
throw this.report(this.failure);
|
|
12072
|
+
}
|
|
12073
|
+
if (this.access === "both" && this.dispatched) return;
|
|
12074
|
+
if (!this.dispatched && this.header.length === 0) return;
|
|
12075
|
+
await this.drain(signal);
|
|
12076
|
+
} finally {
|
|
12077
|
+
if (!this.done) this.cancel("closed");
|
|
12078
|
+
this.broker.release(this);
|
|
12079
|
+
}
|
|
12080
|
+
}
|
|
12081
|
+
async drain(signal) {
|
|
12082
|
+
try {
|
|
12083
|
+
const reader = await this.readerOf(signal);
|
|
12084
|
+
for (; ; ) {
|
|
12085
|
+
const got = await interruptible2(reader.read(), signal);
|
|
12086
|
+
if (got.done) break;
|
|
12087
|
+
}
|
|
12088
|
+
this.done = true;
|
|
12089
|
+
} catch (err) {
|
|
12090
|
+
if (err instanceof KernelError && err.code === "EINTR") this.cancel("interrupted");
|
|
12091
|
+
throw this.fail(err);
|
|
12092
|
+
}
|
|
12093
|
+
}
|
|
12094
|
+
};
|
|
12095
|
+
var EmbedderBroker = class {
|
|
12096
|
+
users;
|
|
12097
|
+
lookup;
|
|
12098
|
+
hooks = /* @__PURE__ */ new Map();
|
|
12099
|
+
budget;
|
|
12100
|
+
open = /* @__PURE__ */ new Map();
|
|
12101
|
+
tagsOf;
|
|
12102
|
+
constructor(users, lookup2, tagsOf = () => void 0, budget = EMBEDDER_BUDGET) {
|
|
12103
|
+
this.users = users;
|
|
12104
|
+
this.tagsOf = tagsOf;
|
|
12105
|
+
this.lookup = lookup2;
|
|
12106
|
+
this.budget = new Budget2(budget);
|
|
12107
|
+
}
|
|
12108
|
+
register(client, hook) {
|
|
12109
|
+
if (!hook) return () => void 0;
|
|
12110
|
+
this.hooks.set(client, hook);
|
|
12111
|
+
return () => {
|
|
12112
|
+
if (this.hooks.get(client) === hook) this.hooks.delete(client);
|
|
12113
|
+
};
|
|
12114
|
+
}
|
|
12115
|
+
hookFor(client) {
|
|
12116
|
+
return this.hooks.get(client);
|
|
12117
|
+
}
|
|
12118
|
+
async allowed(policy, caller) {
|
|
12119
|
+
if (caller.euid === 0 || caller.euid === caller.sessionUid) return true;
|
|
12120
|
+
if (policy.group !== void 0) {
|
|
12121
|
+
const gid = await this.lookup.groupId(policy.group);
|
|
12122
|
+
if (gid !== void 0 && (caller.egid === gid || caller.groups.includes(gid))) return true;
|
|
12123
|
+
}
|
|
12124
|
+
for (const user of policy.users ?? []) {
|
|
12125
|
+
const uid = typeof user === "number" ? user : await this.lookup.userId(user);
|
|
12126
|
+
if (uid === caller.euid) return true;
|
|
12127
|
+
}
|
|
12128
|
+
return false;
|
|
12129
|
+
}
|
|
12130
|
+
async admit(kind, caller) {
|
|
12131
|
+
const hook = this.hooks.get(caller.client);
|
|
12132
|
+
if (!hook) throw new KernelError("ENOTSUP", "no page answers requests for this session");
|
|
12133
|
+
const policy = Object.hasOwn(hook.kinds, kind) ? hook.kinds[kind] : void 0;
|
|
12134
|
+
if (!policy) throw new KernelError("ENOTSUP", `this embedder does not answer ${kind}`);
|
|
12135
|
+
if (this.users !== "off" && !await this.allowed(policy, caller))
|
|
12136
|
+
throw new KernelError("EACCES", `${kind} is not allowed for this user`);
|
|
12137
|
+
const tags = caller.tags;
|
|
12138
|
+
return {
|
|
12139
|
+
pid: caller.shownPid,
|
|
12140
|
+
uid: caller.euid,
|
|
12141
|
+
gid: caller.egid,
|
|
12142
|
+
groups: [...caller.groups],
|
|
12143
|
+
users: this.users,
|
|
12144
|
+
kind,
|
|
12145
|
+
...tags?.length ? { tag: tags[0], tags: [...tags] } : {}
|
|
12146
|
+
};
|
|
12147
|
+
}
|
|
12148
|
+
channel(access2, caller) {
|
|
12149
|
+
const mine = this.open.get(caller.pid) ?? /* @__PURE__ */ new Set();
|
|
12150
|
+
if (mine.size >= EMBEDDER_PER_PROCESS)
|
|
12151
|
+
throw new KernelError("EMFILE", `at most ${EMBEDDER_PER_PROCESS} requests per process`);
|
|
12152
|
+
if (!this.budget.take(2 * EMBEDDER_WINDOW))
|
|
12153
|
+
throw new KernelError("EAGAIN", "the embedder request budget is spent");
|
|
12154
|
+
const channel = new EmbedderChannel(this, access2, caller);
|
|
12155
|
+
mine.add(channel);
|
|
12156
|
+
this.open.set(caller.pid, mine);
|
|
12157
|
+
return new OpenFile({
|
|
12158
|
+
read: channel.read.bind(channel),
|
|
12159
|
+
write: (bytes, signal) => channel.write(bytes, signal),
|
|
12160
|
+
poll: () => channel.poll(),
|
|
12161
|
+
close: () => channel.close(),
|
|
12162
|
+
embedder: channel
|
|
12163
|
+
});
|
|
12164
|
+
}
|
|
12165
|
+
release(channel) {
|
|
12166
|
+
const mine = this.open.get(channel.owner);
|
|
12167
|
+
if (!mine?.delete(channel)) return;
|
|
12168
|
+
if (mine.size === 0) this.open.delete(channel.owner);
|
|
12169
|
+
this.budget.give(2 * EMBEDDER_WINDOW);
|
|
12170
|
+
}
|
|
12171
|
+
};
|
|
12172
|
+
|
|
11637
12173
|
// src/kernel/exec-ticket.ts
|
|
11638
12174
|
var TICKET_ENV = "SLICC_SEALED_TICKET";
|
|
11639
12175
|
var TICKET_TTL_MS = 3e4;
|
|
@@ -12170,6 +12706,9 @@ var HeldPaths = class extends Map {
|
|
|
12170
12706
|
trust(handle, doubt) {
|
|
12171
12707
|
if (this.doubted.get(handle) === doubt) this.doubted.delete(handle);
|
|
12172
12708
|
}
|
|
12709
|
+
pathOf(handle) {
|
|
12710
|
+
return this.handles.get(handle);
|
|
12711
|
+
}
|
|
12173
12712
|
keptFor(handle) {
|
|
12174
12713
|
return this.keptHandles.get(handle);
|
|
12175
12714
|
}
|
|
@@ -12182,9 +12721,9 @@ var HeldPaths = class extends Map {
|
|
|
12182
12721
|
return false;
|
|
12183
12722
|
}
|
|
12184
12723
|
keep(path, file) {
|
|
12185
|
-
const
|
|
12186
|
-
for (const id2 of
|
|
12187
|
-
this.uses.set(file, Math.max(
|
|
12724
|
+
const fresh3 = this.handlesAt(path).filter((id2) => !this.keptHandles.has(id2));
|
|
12725
|
+
for (const id2 of fresh3) this.keptHandles.set(id2, file);
|
|
12726
|
+
this.uses.set(file, Math.max(fresh3.length, 1));
|
|
12188
12727
|
this.unlinked.set(path, file);
|
|
12189
12728
|
}
|
|
12190
12729
|
unkeep(path, file) {
|
|
@@ -13380,8 +13919,8 @@ var MountFs = class _MountFs {
|
|
|
13380
13919
|
}
|
|
13381
13920
|
this.writable(mount, real);
|
|
13382
13921
|
const { uid, gid, mode } = change;
|
|
13383
|
-
const
|
|
13384
|
-
const set3 =
|
|
13922
|
+
const fresh3 = change.kind === "new" && { uid, gid, mode };
|
|
13923
|
+
const set3 = fresh3 ? await this.driverOwner(found, real, fresh3, false) : change;
|
|
13385
13924
|
this.table.forget(mount, real);
|
|
13386
13925
|
const attrs = Object.entries({ uid: set3.uid, gid: set3.gid, mode: set3.mode });
|
|
13387
13926
|
await mount.conn.call({
|
|
@@ -13653,10 +14192,10 @@ async function runMkdir(entry, path, req) {
|
|
|
13653
14192
|
const plain3 = plainDirMode(entry, req.mode);
|
|
13654
14193
|
const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
|
|
13655
14194
|
const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
|
|
13656
|
-
const
|
|
14195
|
+
const fresh3 = plain3 !== void 0 && !await fs.exists(path);
|
|
13657
14196
|
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
13658
14197
|
await fixParents?.();
|
|
13659
|
-
if (
|
|
14198
|
+
if (fresh3) await fs.chmod(path, plain3);
|
|
13660
14199
|
return done2;
|
|
13661
14200
|
}
|
|
13662
14201
|
async function shownAs(entry, path, st) {
|
|
@@ -14053,12 +14592,20 @@ async function linkedElsewhere(fs, path, from) {
|
|
|
14053
14592
|
const source = from === void 0 ? void 0 : await fs.lstat(from).catch(() => void 0);
|
|
14054
14593
|
return !(source && source.ino === st.ino && source.dev === st.dev);
|
|
14055
14594
|
}
|
|
14595
|
+
async function gatedByHandle(entry, opEntry, path, req, opReq) {
|
|
14596
|
+
const heldAt2 = () => req.handle === void 0 ? void 0 : opEntry.heldAt?.(req.handle);
|
|
14597
|
+
if (req.handle !== void 0) await opEntry.replacements?.landed?.(heldAt2() ?? path);
|
|
14598
|
+
const at = heldAt2() ?? path;
|
|
14599
|
+
const serve = async () => run(opEntry, await keptOr(opEntry, at, req.handle), opReq);
|
|
14600
|
+
return entry.gate ? entry.gate(at, serve) : serve();
|
|
14601
|
+
}
|
|
14056
14602
|
async function keptOr(entry, path, handle) {
|
|
14057
14603
|
if (handle !== void 0) {
|
|
14058
14604
|
const hidden = entry.keptFor?.(handle)?.hidden;
|
|
14059
14605
|
if (hidden !== void 0) return hidden;
|
|
14060
|
-
|
|
14061
|
-
|
|
14606
|
+
const at = entry.heldAt?.(handle) ?? path;
|
|
14607
|
+
await bound(entry, at, handle);
|
|
14608
|
+
return at;
|
|
14062
14609
|
}
|
|
14063
14610
|
const kept = entry.unlinked?.(path);
|
|
14064
14611
|
return kept && !await entry.fs.exists(path) ? kept.hidden : path;
|
|
@@ -14251,8 +14798,7 @@ async function dispatchPath(entry, req) {
|
|
|
14251
14798
|
if (entry.revoked?.(resolvedPath))
|
|
14252
14799
|
return { ok: false, errno: "EIO", message: `${resolvedPath} was unmounted` };
|
|
14253
14800
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
14254
|
-
|
|
14255
|
-
return await (entry.gate ? entry.gate(resolvedPath, serve) : serve());
|
|
14801
|
+
return await gatedByHandle(entry, opEntry, resolvedPath, req, opReq);
|
|
14256
14802
|
}
|
|
14257
14803
|
if (!entry.own || !OWN_OPS.has(req.op)) return await run(opEntry, resolvedPath, opReq);
|
|
14258
14804
|
const target = resolvedArg2 ?? (TWO_PATHS.has(req.op) ? fs.resolvePath(cwd, req.arg2 ?? "") : resolvedPath);
|
|
@@ -14653,9 +15199,9 @@ var Pages = class {
|
|
|
14653
15199
|
const page = (start2 + at) / PAGE;
|
|
14654
15200
|
if (this.pages.has(page)) continue;
|
|
14655
15201
|
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
14656
|
-
const
|
|
14657
|
-
|
|
14658
|
-
this.pages.set(page,
|
|
15202
|
+
const fresh3 = this.take(part.length);
|
|
15203
|
+
fresh3.set(part);
|
|
15204
|
+
this.pages.set(page, fresh3);
|
|
14659
15205
|
}
|
|
14660
15206
|
}
|
|
14661
15207
|
read(at, length2) {
|
|
@@ -16961,18 +17507,18 @@ var TlsEngine = class {
|
|
|
16961
17507
|
chainFlags(store, chain2, hostname) {
|
|
16962
17508
|
const verify = this.m._tls_chain_verify;
|
|
16963
17509
|
if (!verify || chain2.length === 0) return void 0;
|
|
16964
|
-
const
|
|
17510
|
+
const joined5 = new Uint8Array(chain2.reduce((n, c) => n + c.length, 0));
|
|
16965
17511
|
let at = 0;
|
|
16966
17512
|
for (const der2 of chain2) {
|
|
16967
|
-
|
|
17513
|
+
joined5.set(der2, at);
|
|
16968
17514
|
at += der2.length;
|
|
16969
17515
|
}
|
|
16970
17516
|
const name2 = this.put(new TextEncoder().encode(hostname));
|
|
16971
17517
|
try {
|
|
16972
|
-
return this.withBytes(
|
|
17518
|
+
return this.withBytes(joined5, (p) => {
|
|
16973
17519
|
const out = this.scratch;
|
|
16974
17520
|
this.m.HEAPU8.fill(255, out, out + 4);
|
|
16975
|
-
const ret = verify(store.ptr, p,
|
|
17521
|
+
const ret = verify(store.ptr, p, joined5.length, name2, out);
|
|
16976
17522
|
const flags2 = new DataView(this.m.HEAPU8.buffer, out, 4).getUint32(0, true);
|
|
16977
17523
|
if (ret === 0) return flags2 === 0 ? 0 : void 0;
|
|
16978
17524
|
return ret === 1 && flags2 !== 0 ? flags2 : void 0;
|
|
@@ -19822,6 +20368,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
19822
20368
|
...file.tty ? { tty: file.tty } : {},
|
|
19823
20369
|
identity: file.identity ?? file,
|
|
19824
20370
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
20371
|
+
...file.embedder ? { embedder: file.embedder } : {},
|
|
19825
20372
|
...file.write ? {
|
|
19826
20373
|
write: async (bytes, signal) => {
|
|
19827
20374
|
await turn(signal);
|
|
@@ -19878,7 +20425,8 @@ function scrubStdio(fds, scrubber) {
|
|
|
19878
20425
|
const stdio = stdioFiles(fds);
|
|
19879
20426
|
for (const fd of fds.numbers()) {
|
|
19880
20427
|
const original = fds.get(fd);
|
|
19881
|
-
|
|
20428
|
+
const named = original.file.tty || original.file.clipboard || original.file.embedder;
|
|
20429
|
+
if (!stdio.has(original) && !named) continue;
|
|
19882
20430
|
const known = wrapped.get(original);
|
|
19883
20431
|
const flags2 = fds.statusFlags(fd);
|
|
19884
20432
|
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
@@ -19891,9 +20439,9 @@ function scrubStdio(fds, scrubber) {
|
|
|
19891
20439
|
// src/kernel/net/sealed-scrubs.ts
|
|
19892
20440
|
function addTo(tree2, host, secrets) {
|
|
19893
20441
|
const entry = tree2.get(host) ?? { secrets: [], version: 0, scrubber: void 0 };
|
|
19894
|
-
const
|
|
19895
|
-
if (
|
|
19896
|
-
entry.secrets = [...entry.secrets, ...
|
|
20442
|
+
const fresh3 = secrets.filter((s) => !entry.secrets.some((e) => e.value === s.value));
|
|
20443
|
+
if (fresh3.length === 0) return;
|
|
20444
|
+
entry.secrets = [...entry.secrets, ...fresh3];
|
|
19897
20445
|
entry.version += 1;
|
|
19898
20446
|
entry.scrubber = void 0;
|
|
19899
20447
|
tree2.set(host, entry);
|
|
@@ -20107,13 +20655,13 @@ function serialized(reply) {
|
|
|
20107
20655
|
const text = JSON.stringify(reply);
|
|
20108
20656
|
plain3 = text === void 0 ? void 0 : JSON.parse(text);
|
|
20109
20657
|
} catch (err) {
|
|
20110
|
-
return JSON.stringify(errorReply("EIO",
|
|
20658
|
+
return JSON.stringify(errorReply("EIO", lineOf3(err)));
|
|
20111
20659
|
}
|
|
20112
20660
|
if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
20113
20661
|
const { v: _, ...rest2 } = plain3;
|
|
20114
20662
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
20115
20663
|
}
|
|
20116
|
-
function
|
|
20664
|
+
function lineOf3(err) {
|
|
20117
20665
|
const text = err instanceof Error ? err.message : String(err);
|
|
20118
20666
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
20119
20667
|
}
|
|
@@ -20164,7 +20712,7 @@ var SealedChannel = class {
|
|
|
20164
20712
|
if (signal.aborted) return void 0;
|
|
20165
20713
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
20166
20714
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
20167
|
-
(err) => errorReply("EIO",
|
|
20715
|
+
(err) => errorReply("EIO", lineOf3(err))
|
|
20168
20716
|
);
|
|
20169
20717
|
const reply = await Promise.race([asked, stopped]);
|
|
20170
20718
|
if (!signal.aborted) return reply;
|
|
@@ -21281,13 +21829,13 @@ var PgServer = class {
|
|
|
21281
21829
|
at += whole;
|
|
21282
21830
|
}
|
|
21283
21831
|
this.buffer = data.slice(at);
|
|
21284
|
-
const
|
|
21832
|
+
const joined5 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
|
|
21285
21833
|
let to = 0;
|
|
21286
21834
|
for (const b of out) {
|
|
21287
|
-
|
|
21835
|
+
joined5.set(b, to);
|
|
21288
21836
|
to += b.length;
|
|
21289
21837
|
}
|
|
21290
|
-
return
|
|
21838
|
+
return joined5;
|
|
21291
21839
|
}
|
|
21292
21840
|
};
|
|
21293
21841
|
function frame3(type, body) {
|
|
@@ -21629,12 +22177,12 @@ var SessionWriter = class {
|
|
|
21629
22177
|
if (this.failed !== void 0) throw this.failed;
|
|
21630
22178
|
if (this.mode === "pass") return this.conn.write(bytes);
|
|
21631
22179
|
clearTimeout(this.timer);
|
|
21632
|
-
const
|
|
21633
|
-
|
|
21634
|
-
|
|
22180
|
+
const joined5 = new Uint8Array(this.buffer.length + bytes.length);
|
|
22181
|
+
joined5.set(this.buffer);
|
|
22182
|
+
joined5.set(bytes, this.buffer.length);
|
|
21635
22183
|
this.buffer.fill(0);
|
|
21636
|
-
this.buffer =
|
|
21637
|
-
if (this.mode === "sniff") this.mode = modeOf(latin12(
|
|
22184
|
+
this.buffer = joined5;
|
|
22185
|
+
if (this.mode === "sniff") this.mode = modeOf(latin12(joined5.subarray(0, 8))) ?? "sniff";
|
|
21638
22186
|
if (this.mode === "pg" && !this.sawPg) {
|
|
21639
22187
|
this.sawPg = true;
|
|
21640
22188
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -21782,7 +22330,7 @@ var ScrubReader = class {
|
|
|
21782
22330
|
const before = this.current();
|
|
21783
22331
|
const out = this.through(got);
|
|
21784
22332
|
if (before.length === 0 && out !== void 0) return out;
|
|
21785
|
-
if (before.length > 0) return
|
|
22333
|
+
if (before.length > 0) return joined4(before, out);
|
|
21786
22334
|
}
|
|
21787
22335
|
}
|
|
21788
22336
|
through(got) {
|
|
@@ -21798,7 +22346,7 @@ var ScrubReader = class {
|
|
|
21798
22346
|
return out.length > 0 ? out : void 0;
|
|
21799
22347
|
}
|
|
21800
22348
|
};
|
|
21801
|
-
function
|
|
22349
|
+
function joined4(a, b) {
|
|
21802
22350
|
if (!b) return a;
|
|
21803
22351
|
const out = new Uint8Array(a.length + b.length);
|
|
21804
22352
|
out.set(a);
|
|
@@ -22706,7 +23254,7 @@ async function connect(req, proc) {
|
|
|
22706
23254
|
dialing?.catch(() => void 0);
|
|
22707
23255
|
throw new KernelError("EINPROGRESS");
|
|
22708
23256
|
}
|
|
22709
|
-
if (dialing !== void 0) await
|
|
23257
|
+
if (dialing !== void 0) await interruptible3(dialing, proc.blocking());
|
|
22710
23258
|
return ok3();
|
|
22711
23259
|
}
|
|
22712
23260
|
async function bindUnixDgram(proc, socket, addr) {
|
|
@@ -22771,7 +23319,7 @@ async function unixDatagram(req, dgram, proc) {
|
|
|
22771
23319
|
function domainOf(socket) {
|
|
22772
23320
|
return socket instanceof UnixDgram ? "unix" : "inet";
|
|
22773
23321
|
}
|
|
22774
|
-
function
|
|
23322
|
+
function interruptible3(dialing, signal) {
|
|
22775
23323
|
return new Promise((resolve2, reject) => {
|
|
22776
23324
|
const abort = () => reject(new KernelError("EINTR"));
|
|
22777
23325
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -23775,7 +24323,7 @@ var ProcessWatches = class {
|
|
|
23775
24323
|
};
|
|
23776
24324
|
|
|
23777
24325
|
// src/kernel/process.ts
|
|
23778
|
-
function
|
|
24326
|
+
function aborted2(signal) {
|
|
23779
24327
|
return new Promise((_, reject) => {
|
|
23780
24328
|
signal.addEventListener("abort", () => reject(new KernelError("EINTR")), { once: true });
|
|
23781
24329
|
});
|
|
@@ -23865,6 +24413,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
23865
24413
|
"fd-open-sealed",
|
|
23866
24414
|
"fd-open-clipboard",
|
|
23867
24415
|
"fd-clipboard-abort",
|
|
24416
|
+
"fd-open-embedder",
|
|
23868
24417
|
"tty-get",
|
|
23869
24418
|
"tty-set",
|
|
23870
24419
|
"tty-winsz",
|
|
@@ -24418,6 +24967,7 @@ var WasmProcess = class {
|
|
|
24418
24967
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
24419
24968
|
if (file.tty) this.checkForeground(file.tty);
|
|
24420
24969
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
24970
|
+
if (file.embedder) return this.readEmbedder(file, req, cancelled);
|
|
24421
24971
|
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
24422
24972
|
if (req.max <= 0) return new Uint8Array(0);
|
|
24423
24973
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
@@ -24438,6 +24988,81 @@ var WasmProcess = class {
|
|
|
24438
24988
|
throw err;
|
|
24439
24989
|
}
|
|
24440
24990
|
}
|
|
24991
|
+
async readEmbedder(file, req, cancelled) {
|
|
24992
|
+
const channel = file.embedder;
|
|
24993
|
+
if (req.max <= 0) return new Uint8Array(0);
|
|
24994
|
+
channel.caller = await this.embedderCaller();
|
|
24995
|
+
try {
|
|
24996
|
+
return await channel.read(Math.min(req.max, MAX_READ), this.blockingSignal(cancelled));
|
|
24997
|
+
} catch (err) {
|
|
24998
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
24999
|
+
throw err;
|
|
25000
|
+
}
|
|
25001
|
+
}
|
|
25002
|
+
async writeEmbedder(file, body, nonblock, cancelled) {
|
|
25003
|
+
const channel = file.embedder;
|
|
25004
|
+
channel.caller = await this.embedderCaller();
|
|
25005
|
+
const write = file.write;
|
|
25006
|
+
if (!pollFile(file).writable && nonblock) throw new KernelError("EAGAIN");
|
|
25007
|
+
try {
|
|
25008
|
+
return await write.call(file, body, this.blockingSignal(cancelled));
|
|
25009
|
+
} catch (err) {
|
|
25010
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
25011
|
+
throw err;
|
|
25012
|
+
}
|
|
25013
|
+
}
|
|
25014
|
+
async deviceComplaint(path, err) {
|
|
25015
|
+
const name2 = this.options.clipboardName;
|
|
25016
|
+
if (name2 === void 0 || !(err instanceof KernelError) || err.detail === void 0) return;
|
|
25017
|
+
if (err.code === "EINTR") return;
|
|
25018
|
+
await this.complainLine(`${name2}: ${path}: ${clipboardLine(err.detail)}`);
|
|
25019
|
+
}
|
|
25020
|
+
async complainLine(line) {
|
|
25021
|
+
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
25022
|
+
if (!stderr?.write || stderr.clipboard || stderr.embedder || stderr.sealed) return;
|
|
25023
|
+
const timeout = new Promise((r) => setTimeout(() => r(0), 1e3));
|
|
25024
|
+
await Promise.race([
|
|
25025
|
+
stderr.write(new TextEncoder().encode(`${line}
|
|
25026
|
+
`), AbortSignal.timeout(1e3)).catch(() => 0),
|
|
25027
|
+
timeout
|
|
25028
|
+
]);
|
|
25029
|
+
}
|
|
25030
|
+
async embedderCaller() {
|
|
25031
|
+
const shown = await this.options.identity?.();
|
|
25032
|
+
const session = this.options.embedderSession?.() ?? { client: 0, uid: 0 };
|
|
25033
|
+
const name2 = this.options.clipboardName ?? this.options.embedderName ?? "program";
|
|
25034
|
+
return {
|
|
25035
|
+
pid: this.pid,
|
|
25036
|
+
shownPid: shown?.pid ?? this.pid,
|
|
25037
|
+
euid: this.cred.euid,
|
|
25038
|
+
egid: this.cred.egid,
|
|
25039
|
+
groups: [...this.cred.groups],
|
|
25040
|
+
sessionUid: session.uid,
|
|
25041
|
+
client: session.client,
|
|
25042
|
+
tags: this.options.embedder?.tagsOf(this.pid),
|
|
25043
|
+
progress: (line) => void this.complainLine(`${name2}: ${line}`),
|
|
25044
|
+
closing: () => AbortSignal.any([this.interrupt.signal, this.gone.signal])
|
|
25045
|
+
};
|
|
25046
|
+
}
|
|
25047
|
+
async closeFd(fd) {
|
|
25048
|
+
this.options.locks?.closed(this.pid, fd);
|
|
25049
|
+
await this.dropRecordLocks(fd);
|
|
25050
|
+
const closing2 = this.fds.get(fd).file;
|
|
25051
|
+
const channel = closing2.clipboard;
|
|
25052
|
+
if (channel) channel.stamp = await this.clipboardStamp();
|
|
25053
|
+
if (closing2.embedder) closing2.embedder.caller = await this.embedderCaller();
|
|
25054
|
+
await Promise.resolve(this.fds.close(fd)).catch(async (err) => {
|
|
25055
|
+
if (channel) await this.clipboardComplaint(err);
|
|
25056
|
+
if (closing2.embedder) await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
25057
|
+
throw err;
|
|
25058
|
+
});
|
|
25059
|
+
}
|
|
25060
|
+
async openEmbedder(flags2) {
|
|
25061
|
+
const broker = this.options.embedder;
|
|
25062
|
+
if (!broker) throw new KernelError("ENOENT");
|
|
25063
|
+
const file = broker.channel(openAccess(flags2), await this.embedderCaller());
|
|
25064
|
+
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
25065
|
+
}
|
|
24441
25066
|
async complain(line) {
|
|
24442
25067
|
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
24443
25068
|
if (!stderr?.write || stderr.sealed || stderr.clipboard) return false;
|
|
@@ -24468,6 +25093,7 @@ var WasmProcess = class {
|
|
|
24468
25093
|
const file = this.fds.get(fd).file;
|
|
24469
25094
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
24470
25095
|
if (!file.write) throw new KernelError("EBADF");
|
|
25096
|
+
if (file.embedder) return this.writeEmbedder(file, body, nonblock, cancelled);
|
|
24471
25097
|
if (!pollFile(file).writable) {
|
|
24472
25098
|
if (nonblock) throw new KernelError("EAGAIN");
|
|
24473
25099
|
return file.write(body, this.blockingSignal(cancelled));
|
|
@@ -24515,11 +25141,11 @@ var WasmProcess = class {
|
|
|
24515
25141
|
} else if (req.create) {
|
|
24516
25142
|
await nodes.onEntry(path, async () => {
|
|
24517
25143
|
const marks = this.options.owners || plain3 !== void 0;
|
|
24518
|
-
const
|
|
25144
|
+
const fresh3 = marks && !await present3(fs, path, true);
|
|
24519
25145
|
this.fds.installAt(fd, this.openVfsFile(open2, await nodes.identify(path), fs));
|
|
24520
25146
|
await this.fds.get(fd).file.stat?.();
|
|
24521
|
-
if (
|
|
24522
|
-
else if (
|
|
25147
|
+
if (fresh3 && plain3 !== void 0) await fs.chmod?.(path, plain3);
|
|
25148
|
+
else if (fresh3) {
|
|
24523
25149
|
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
24524
25150
|
}
|
|
24525
25151
|
});
|
|
@@ -24737,17 +25363,9 @@ var WasmProcess = class {
|
|
|
24737
25363
|
kind: "json",
|
|
24738
25364
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
24739
25365
|
};
|
|
24740
|
-
case "fd-close":
|
|
24741
|
-
this.
|
|
24742
|
-
await this.dropRecordLocks(req.fd);
|
|
24743
|
-
const channel = this.fds.get(req.fd).file.clipboard;
|
|
24744
|
-
if (channel) channel.stamp = await this.clipboardStamp();
|
|
24745
|
-
await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
|
|
24746
|
-
if (channel) await this.clipboardComplaint(err);
|
|
24747
|
-
throw err;
|
|
24748
|
-
});
|
|
25366
|
+
case "fd-close":
|
|
25367
|
+
await this.closeFd(req.fd);
|
|
24749
25368
|
return { ok: true, kind: "void" };
|
|
24750
|
-
}
|
|
24751
25369
|
case "fd-pipe": {
|
|
24752
25370
|
const pipe = openPipe();
|
|
24753
25371
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -24807,6 +25425,8 @@ var WasmProcess = class {
|
|
|
24807
25425
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
24808
25426
|
case "fd-open-clipboard":
|
|
24809
25427
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
25428
|
+
case "fd-open-embedder":
|
|
25429
|
+
return { ok: true, kind: "json", json: await this.openEmbedder(req.flags) };
|
|
24810
25430
|
case "fd-clipboard-abort": {
|
|
24811
25431
|
const file = this.fds.get(req.fd);
|
|
24812
25432
|
file.file.clipboard?.abort();
|
|
@@ -25301,7 +25921,7 @@ var WasmProcess = class {
|
|
|
25301
25921
|
else {
|
|
25302
25922
|
const { source, target, type, flags: flags2, data } = req;
|
|
25303
25923
|
const signal = this.blockingSignal(cancelled);
|
|
25304
|
-
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal),
|
|
25924
|
+
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal), aborted2(signal)]);
|
|
25305
25925
|
}
|
|
25306
25926
|
} catch (err) {
|
|
25307
25927
|
const code = err?.code;
|
|
@@ -25311,7 +25931,7 @@ var WasmProcess = class {
|
|
|
25311
25931
|
return { ok: true, kind: "void" };
|
|
25312
25932
|
}
|
|
25313
25933
|
pause(cancelled) {
|
|
25314
|
-
return
|
|
25934
|
+
return aborted2(this.blockingSignal(cancelled));
|
|
25315
25935
|
}
|
|
25316
25936
|
alarm;
|
|
25317
25937
|
dlLog = [];
|
|
@@ -25847,6 +26467,7 @@ function holdingToken(opts, holds2, caller) {
|
|
|
25847
26467
|
boundIno: holds2.boundIno.bind(holds2),
|
|
25848
26468
|
trust: holds2.trust.bind(holds2),
|
|
25849
26469
|
keptFor: (handle) => holds2.keptFor(handle),
|
|
26470
|
+
heldAt: (handle) => holds2.pathOf(handle),
|
|
25850
26471
|
unlinked: (path) => holds2.keptAt(path),
|
|
25851
26472
|
gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
|
|
25852
26473
|
own: (path, op) => holds2.own(path, op),
|
|
@@ -25860,6 +26481,15 @@ function linksOf(opts) {
|
|
|
25860
26481
|
function clipboardName(opts) {
|
|
25861
26482
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
25862
26483
|
}
|
|
26484
|
+
function embedderOptions(opts) {
|
|
26485
|
+
if (!opts.embedder) return {};
|
|
26486
|
+
return {
|
|
26487
|
+
embedder: opts.embedder.broker,
|
|
26488
|
+
embedderSession: opts.embedder.session,
|
|
26489
|
+
embedderName: opts.argv0,
|
|
26490
|
+
...clipboardName(opts)
|
|
26491
|
+
};
|
|
26492
|
+
}
|
|
25863
26493
|
function processOptions(opts, header4, hooks, created4) {
|
|
25864
26494
|
return {
|
|
25865
26495
|
...inherited(opts),
|
|
@@ -25867,6 +26497,7 @@ function processOptions(opts, header4, hooks, created4) {
|
|
|
25867
26497
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
25868
26498
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
25869
26499
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
26500
|
+
...embedderOptions(opts),
|
|
25870
26501
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
25871
26502
|
...opts.source ? { source: opts.source } : {},
|
|
25872
26503
|
noLinks: opts.noLinks,
|
|
@@ -28017,14 +28648,14 @@ var RESTORE_AGAIN_MS = 3e4;
|
|
|
28017
28648
|
function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
28018
28649
|
const handles = /* @__PURE__ */ new Map();
|
|
28019
28650
|
let nextFh = 0;
|
|
28020
|
-
const
|
|
28651
|
+
const fresh3 = (remote) => {
|
|
28021
28652
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
28022
28653
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
28023
28654
|
};
|
|
28024
28655
|
const live = (fh) => {
|
|
28025
28656
|
const remote = handles.get(fh);
|
|
28026
28657
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
28027
|
-
return
|
|
28658
|
+
return fresh3(remote);
|
|
28028
28659
|
};
|
|
28029
28660
|
const call = (op, body = {}) => current().call(op, body);
|
|
28030
28661
|
const same3 = (was, mode, seen) => seen?.mode === (mode | 128) && (was.ino !== void 0 && seen.ino !== void 0 ? seen.ino === was.ino : seen.size === was.size && seen.mtime === was.mtime);
|
|
@@ -28106,7 +28737,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
28106
28737
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
28107
28738
|
handles.delete(fh);
|
|
28108
28739
|
try {
|
|
28109
|
-
await
|
|
28740
|
+
await fresh3(remote).client.call("release", { fh: remote.fh }, true);
|
|
28110
28741
|
} finally {
|
|
28111
28742
|
if (remote.restore) await settle3(current(), remote.restore);
|
|
28112
28743
|
}
|
|
@@ -29338,12 +29969,12 @@ ${lines2}
|
|
|
29338
29969
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
29339
29970
|
const withdraw = () => control.abort("withdrawn");
|
|
29340
29971
|
requester.addEventListener("abort", withdraw, { once: true });
|
|
29341
|
-
const
|
|
29972
|
+
const aborted3 = new Promise(
|
|
29342
29973
|
(resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
|
|
29343
29974
|
);
|
|
29344
29975
|
try {
|
|
29345
29976
|
const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
29346
|
-
const answer2 = await Promise.race([answered2,
|
|
29977
|
+
const answer2 = await Promise.race([answered2, aborted3]);
|
|
29347
29978
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
29348
29979
|
return control.signal.reason === "expired" ? failed2("ETIMEDOUT", "sudo: the request expired") : failed2("EINTR", "sudo: the request was withdrawn");
|
|
29349
29980
|
}
|
|
@@ -29469,6 +30100,7 @@ var SUDO_SOURCE = [
|
|
|
29469
30100
|
].join("\n");
|
|
29470
30101
|
|
|
29471
30102
|
// src/launcher.ts
|
|
30103
|
+
var NO_SESSION = { client: -1, uid: -1 };
|
|
29472
30104
|
var MODULE_URLS = 16;
|
|
29473
30105
|
function dataModuleUrl(source) {
|
|
29474
30106
|
const bytes = new TextEncoder().encode(source);
|
|
@@ -29731,6 +30363,7 @@ var Launcher = class {
|
|
|
29731
30363
|
described = /* @__PURE__ */ new Map();
|
|
29732
30364
|
creds = /* @__PURE__ */ new Map();
|
|
29733
30365
|
tags = /* @__PURE__ */ new Map();
|
|
30366
|
+
sessions = /* @__PURE__ */ new Map();
|
|
29734
30367
|
tagBases = /* @__PURE__ */ new Map();
|
|
29735
30368
|
links = /* @__PURE__ */ new Map();
|
|
29736
30369
|
freshModules = new FreshModules();
|
|
@@ -29791,6 +30424,7 @@ var Launcher = class {
|
|
|
29791
30424
|
sealed;
|
|
29792
30425
|
scrubs = /* @__PURE__ */ new Map();
|
|
29793
30426
|
clipboard;
|
|
30427
|
+
embedder;
|
|
29794
30428
|
rootFs;
|
|
29795
30429
|
fileWatches;
|
|
29796
30430
|
nextPid = 1e3;
|
|
@@ -29812,14 +30446,14 @@ var Launcher = class {
|
|
|
29812
30446
|
void 0,
|
|
29813
30447
|
(pid) => this.tagsOf(pid)
|
|
29814
30448
|
);
|
|
30449
|
+
this.embedder = this.embedderBroker(options.embedder);
|
|
29815
30450
|
this.sealed = new SealedBroker(
|
|
29816
30451
|
options.sealed,
|
|
29817
30452
|
this.usersMode,
|
|
29818
30453
|
void 0,
|
|
29819
30454
|
(pid) => this.tagsOf(pid)
|
|
29820
30455
|
);
|
|
29821
|
-
this.
|
|
29822
|
-
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
30456
|
+
this.wireSealed();
|
|
29823
30457
|
if (this.owners) options.fs.trackOwners?.();
|
|
29824
30458
|
this.watchers.tap((paths) => {
|
|
29825
30459
|
this.changes.publish(...paths);
|
|
@@ -30880,6 +31514,8 @@ var Launcher = class {
|
|
|
30880
31514
|
}
|
|
30881
31515
|
marks(pid, req) {
|
|
30882
31516
|
if (req.tags?.length) this.tags.set(pid, req.tags);
|
|
31517
|
+
const session = req.session ?? this.sessions.get(req.ppid ?? -1);
|
|
31518
|
+
if (session) this.sessions.set(pid, session);
|
|
30883
31519
|
if (req.tags?.length) this.tagBases.set(pid, req.tagBase ?? req.tags.length);
|
|
30884
31520
|
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
30885
31521
|
}
|
|
@@ -30959,6 +31595,7 @@ var Launcher = class {
|
|
|
30959
31595
|
sealed: this.sealed,
|
|
30960
31596
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
30961
31597
|
clipboard: this.clipboard,
|
|
31598
|
+
embedder: { broker: this.embedder, session: () => this.sessionOf(pid) },
|
|
30962
31599
|
...this.dac ? { dac: this.dac } : {},
|
|
30963
31600
|
program: req.program,
|
|
30964
31601
|
changes: this.changes.sab,
|
|
@@ -31087,6 +31724,7 @@ var Launcher = class {
|
|
|
31087
31724
|
this.childTimes.delete(pid);
|
|
31088
31725
|
this.creds.delete(pid);
|
|
31089
31726
|
this.tags.delete(pid);
|
|
31727
|
+
this.sessions.delete(pid);
|
|
31090
31728
|
this.tagBases.delete(pid);
|
|
31091
31729
|
this.links.delete(pid);
|
|
31092
31730
|
this.granted.delete(pid);
|
|
@@ -31132,8 +31770,8 @@ var Launcher = class {
|
|
|
31132
31770
|
this.sampledAt = Math.max(this.sampledAt, now);
|
|
31133
31771
|
this.load = this.load.map((avg, i) => {
|
|
31134
31772
|
const window = LOAD_WINDOWS_MS[i];
|
|
31135
|
-
const
|
|
31136
|
-
return avg * Math.exp(-elapsed / window) + running *
|
|
31773
|
+
const fresh3 = 1 - Math.exp(-LOAD_SAMPLE_MS / window);
|
|
31774
|
+
return avg * Math.exp(-elapsed / window) + running * fresh3;
|
|
31137
31775
|
});
|
|
31138
31776
|
}
|
|
31139
31777
|
idleSince;
|
|
@@ -31363,7 +32001,7 @@ var Launcher = class {
|
|
|
31363
32001
|
forker(ppid, parent) {
|
|
31364
32002
|
const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
|
|
31365
32003
|
return async (state, given) => {
|
|
31366
|
-
const
|
|
32004
|
+
const fresh3 = (fds, quietOom) => this.start({
|
|
31367
32005
|
...image,
|
|
31368
32006
|
quietOom,
|
|
31369
32007
|
cwd: state.cwd ?? parent.cwd,
|
|
@@ -31379,7 +32017,7 @@ var Launcher = class {
|
|
|
31379
32017
|
tagBase: this.tagBases.get(ppid),
|
|
31380
32018
|
links: this.links.get(ppid)
|
|
31381
32019
|
});
|
|
31382
|
-
return childHandle(await this.admitted(parent.program.abi !== "js", given,
|
|
32020
|
+
return childHandle(await this.admitted(parent.program.abi !== "js", given, fresh3));
|
|
31383
32021
|
};
|
|
31384
32022
|
}
|
|
31385
32023
|
keySignal(tty, fallback, sig, send2) {
|
|
@@ -31415,6 +32053,25 @@ var Launcher = class {
|
|
|
31415
32053
|
credOf(pid) {
|
|
31416
32054
|
return this.creds.get(pid)?.() ?? copyCred(ROOT);
|
|
31417
32055
|
}
|
|
32056
|
+
wireSealed() {
|
|
32057
|
+
this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
|
|
32058
|
+
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
32059
|
+
}
|
|
32060
|
+
embedderBroker(hook) {
|
|
32061
|
+
const broker = new EmbedderBroker(
|
|
32062
|
+
this.usersMode,
|
|
32063
|
+
{
|
|
32064
|
+
groupId: async (name2) => (await this.users.groups()).find((g) => g.name === name2)?.gid,
|
|
32065
|
+
userId: async (name2) => (await this.users.lookup(name2))?.uid
|
|
32066
|
+
},
|
|
32067
|
+
(pid) => this.tagsOf(pid)
|
|
32068
|
+
);
|
|
32069
|
+
broker.register(0, hook);
|
|
32070
|
+
return broker;
|
|
32071
|
+
}
|
|
32072
|
+
sessionOf(pid) {
|
|
32073
|
+
return this.sessions.get(pid) ?? NO_SESSION;
|
|
32074
|
+
}
|
|
31418
32075
|
tagOf(pid) {
|
|
31419
32076
|
return this.tags.get(pid)?.[0];
|
|
31420
32077
|
}
|
|
@@ -31686,8 +32343,8 @@ var Launcher = class {
|
|
|
31686
32343
|
for (const [path, mode] of layout) {
|
|
31687
32344
|
if (isProtected(this.prefixes, normalizePath(path))) continue;
|
|
31688
32345
|
const real = await this.realLayoutPath(path);
|
|
31689
|
-
const
|
|
31690
|
-
if (
|
|
32346
|
+
const fresh3 = real !== void 0 && !await this.base.hasOwner?.(real);
|
|
32347
|
+
if (fresh3) await this.base.chown?.(real, { uid: 0, gid: 0, mode, follow: false });
|
|
31691
32348
|
}
|
|
31692
32349
|
}
|
|
31693
32350
|
async realLayoutPath(given) {
|
|
@@ -31860,9 +32517,10 @@ var Launcher = class {
|
|
|
31860
32517
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
31861
32518
|
return found;
|
|
31862
32519
|
}
|
|
31863
|
-
identity(account, given) {
|
|
32520
|
+
identity(account, given, session = 0) {
|
|
31864
32521
|
return {
|
|
31865
32522
|
...given,
|
|
32523
|
+
session: { client: session, uid: account.uid },
|
|
31866
32524
|
cred: credOf(account),
|
|
31867
32525
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
31868
32526
|
};
|
|
@@ -31982,9 +32640,9 @@ var Launcher = class {
|
|
|
31982
32640
|
}
|
|
31983
32641
|
moved(from, to, source) {
|
|
31984
32642
|
this.renameLog.add(from, to);
|
|
32643
|
+
for (const holds2 of this.held) holds2.renamed(from, to);
|
|
31985
32644
|
if (source) return;
|
|
31986
32645
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
31987
|
-
for (const holds2 of this.held) holds2.renamed(from, to);
|
|
31988
32646
|
this.watchers.moved(from, to);
|
|
31989
32647
|
}
|
|
31990
32648
|
processChain(fs, nodes, unlinked) {
|
|
@@ -32049,7 +32707,7 @@ var Launcher = class {
|
|
|
32049
32707
|
cwd,
|
|
32050
32708
|
fds,
|
|
32051
32709
|
report,
|
|
32052
|
-
...this.identity(account, tagged)
|
|
32710
|
+
...this.identity(account, tagged, options.session)
|
|
32053
32711
|
});
|
|
32054
32712
|
leader = handle.pid;
|
|
32055
32713
|
void handle.exited.then(() => tty.hangup());
|
|
@@ -32106,7 +32764,7 @@ var Launcher = class {
|
|
|
32106
32764
|
fds,
|
|
32107
32765
|
report,
|
|
32108
32766
|
...group,
|
|
32109
|
-
...this.identity(account, tagged)
|
|
32767
|
+
...this.identity(account, tagged, options.session)
|
|
32110
32768
|
});
|
|
32111
32769
|
options.onStarted?.(handle.pid);
|
|
32112
32770
|
const status = await handle.exited;
|
|
@@ -32572,6 +33230,8 @@ function isUsersRequest(req) {
|
|
|
32572
33230
|
}
|
|
32573
33231
|
function transferOf2(req, result) {
|
|
32574
33232
|
if (result instanceof MessagePort) return [result];
|
|
33233
|
+
const bound3 = result?.port;
|
|
33234
|
+
if (req.op === "connect" && bound3 instanceof MessagePort) return [bound3];
|
|
32575
33235
|
if (req.op === "attest") return [result.bytes.buffer];
|
|
32576
33236
|
return void 0;
|
|
32577
33237
|
}
|
|
@@ -32605,7 +33265,35 @@ function usersOp(l, req) {
|
|
|
32605
33265
|
if (req.op === "groups-remove-member") return l.users.removeMember(req.group, req.user);
|
|
32606
33266
|
return l.users.list();
|
|
32607
33267
|
}
|
|
32608
|
-
|
|
33268
|
+
var clientIds = 0;
|
|
33269
|
+
async function connectClient(deps, { user, tag, bind: bind2 }) {
|
|
33270
|
+
const l = await deps.ready();
|
|
33271
|
+
tagOption(tag);
|
|
33272
|
+
if (user !== void 0 && !await l.users.lookup(user)) {
|
|
33273
|
+
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
33274
|
+
}
|
|
33275
|
+
const { port1, port2 } = new MessageChannel();
|
|
33276
|
+
const held = deps.held ? await deps.held() : void 0;
|
|
33277
|
+
const client = ++clientIds;
|
|
33278
|
+
const served2 = serveClient(port1, {
|
|
33279
|
+
launcher: deps.ready,
|
|
33280
|
+
signal: signalNumber,
|
|
33281
|
+
session: client,
|
|
33282
|
+
...bind2 === "attach" ? { attachRequests: true } : {},
|
|
33283
|
+
...user !== void 0 ? { user } : {},
|
|
33284
|
+
...tag !== void 0 ? { tag } : {},
|
|
33285
|
+
...deps.locks ? { locks: deps.locks } : {},
|
|
33286
|
+
...held ? { lock: held } : {}
|
|
33287
|
+
});
|
|
33288
|
+
deps.clients.add(served2);
|
|
33289
|
+
const unbind = bind2 && bind2 !== "attach" ? l.embedder.register(client, deps.requests.hookFor(client, bind2)) : void 0;
|
|
33290
|
+
void served2.closed.then(() => {
|
|
33291
|
+
deps.clients.delete(served2);
|
|
33292
|
+
unbind?.();
|
|
33293
|
+
});
|
|
33294
|
+
return unbind ? { port: port2, client } : port2;
|
|
33295
|
+
}
|
|
33296
|
+
function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
|
|
32609
33297
|
return {
|
|
32610
33298
|
cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
|
|
32611
33299
|
...req.hostname !== void 0 ? { hostname: req.hostname } : {},
|
|
@@ -32614,7 +33302,8 @@ function hostOptions(req, port, sealed, clipboard, lookup2) {
|
|
|
32614
33302
|
...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
|
|
32615
33303
|
...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},
|
|
32616
33304
|
...req.sealed ? { sealed } : {},
|
|
32617
|
-
...req.clipboard ? { clipboard } : {}
|
|
33305
|
+
...req.clipboard ? { clipboard } : {},
|
|
33306
|
+
...req.requests ? { embedder: requests.hookFor(0, req.requests) } : {}
|
|
32618
33307
|
};
|
|
32619
33308
|
}
|
|
32620
33309
|
function hostProtect(init, lookup2) {
|
|
@@ -32649,6 +33338,7 @@ function serveKernel(port, deps) {
|
|
|
32649
33338
|
const clients = /* @__PURE__ */ new Set();
|
|
32650
33339
|
const sealed = sealedAsker(port);
|
|
32651
33340
|
const clipboard = clipboardAsker(port);
|
|
33341
|
+
const requests = embedderAsker(port);
|
|
32652
33342
|
const integrity = integrityAsker(port);
|
|
32653
33343
|
const approvals = sudoApprovals(port);
|
|
32654
33344
|
const locks = deps.locks === null ? void 0 : deps.locks ?? locksOf();
|
|
@@ -32664,26 +33354,10 @@ function serveKernel(port, deps) {
|
|
|
32664
33354
|
});
|
|
32665
33355
|
return holding;
|
|
32666
33356
|
}
|
|
32667
|
-
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
|
|
32671
|
-
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
32672
|
-
}
|
|
32673
|
-
const { port1, port2 } = new MessageChannel();
|
|
32674
|
-
const held = locks ? await holdLock(locks) : void 0;
|
|
32675
|
-
const served2 = serveClient(port1, {
|
|
32676
|
-
launcher: ready2,
|
|
32677
|
-
signal: signalNumber,
|
|
32678
|
-
...user !== void 0 ? { user } : {},
|
|
32679
|
-
...tag !== void 0 ? { tag } : {},
|
|
32680
|
-
...locks ? { locks } : {},
|
|
32681
|
-
...held ? { lock: held } : {}
|
|
32682
|
-
});
|
|
32683
|
-
clients.add(served2);
|
|
32684
|
-
void served2.closed.then(() => clients.delete(served2));
|
|
32685
|
-
return port2;
|
|
32686
|
-
}
|
|
33357
|
+
const connect2 = (user, tag, bind2) => connectClient(
|
|
33358
|
+
{ ready: ready2, clients, requests, held: locks ? () => holdLock(locks) : void 0, locks },
|
|
33359
|
+
{ user, tag, bind: bind2 }
|
|
33360
|
+
);
|
|
32687
33361
|
async function ready2() {
|
|
32688
33362
|
if (!launcher) throw new Error("the kernel is not initialized");
|
|
32689
33363
|
return launcher;
|
|
@@ -32717,7 +33391,7 @@ function serveKernel(port, deps) {
|
|
|
32717
33391
|
...req.modules ? { modules: req.modules } : {},
|
|
32718
33392
|
...req.commands ? { commands: req.commands } : {},
|
|
32719
33393
|
...req.env ? { env: req.env } : {},
|
|
32720
|
-
...hostOptions(req, port, sealed.hook, clipboard.hook, integrity.lookup),
|
|
33394
|
+
...hostOptions(req, port, sealed.hook, clipboard.hook, integrity.lookup, requests),
|
|
32721
33395
|
...req.approve ? { approve: approvals.ask } : {},
|
|
32722
33396
|
...net,
|
|
32723
33397
|
...media ? { media } : {},
|
|
@@ -32745,7 +33419,7 @@ function serveKernel(port, deps) {
|
|
|
32745
33419
|
if (req.op === "init") return init(req);
|
|
32746
33420
|
if (isAttestRequest(req)) return attestOp(await ready2(), req);
|
|
32747
33421
|
if (req.op === "open-terminal") return terminal(req);
|
|
32748
|
-
if (req.op === "connect") return connect2(req.user, req.tag);
|
|
33422
|
+
if (req.op === "connect") return connect2(req.user, req.tag, req.requests);
|
|
32749
33423
|
if (isUsersRequest(req)) return usersOp(await ready2(), req);
|
|
32750
33424
|
if (req.op === "routes" || req.op === "transport-traits") {
|
|
32751
33425
|
return networkOp(await ready2(), req, remote);
|
|
@@ -32787,6 +33461,8 @@ function serveKernel(port, deps) {
|
|
|
32787
33461
|
if (sealedReply) return sealed.answer(sealedReply);
|
|
32788
33462
|
const clipboardReply = event.data.clipboardReply;
|
|
32789
33463
|
if (clipboardReply) return clipboard.answer(clipboardReply);
|
|
33464
|
+
const embedderReply = embedderReplyOf(event.data);
|
|
33465
|
+
if (embedderReply) return requests.answer(embedderReply);
|
|
32790
33466
|
const integrityReply = event.data.integrityReply;
|
|
32791
33467
|
if (integrityReply) return integrity.answer(integrityReply);
|
|
32792
33468
|
const grant = event.data.hostfsGrant;
|