@ai-ecoverse/slicc-kernel 1.88.1 → 1.89.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 +17 -8
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +419 -124
- package/dist/kernel-worker.js.map +3 -3
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +5507 -5256
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +417 -123
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +302 -51
- package/dist/process-worker.js.map +4 -4
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -140,6 +140,14 @@ function inodeOf(path) {
|
|
|
140
140
|
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
141
141
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;
|
|
142
142
|
}
|
|
143
|
+
function redirected(of, to) {
|
|
144
|
+
return Object.assign(fsError("EXDEV", `${of} leads to the mount at ${to}`), {
|
|
145
|
+
redirect: { of: normalizePath(of), to: normalizePath(to) }
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function redirectOf(err) {
|
|
149
|
+
return err?.redirect;
|
|
150
|
+
}
|
|
143
151
|
|
|
144
152
|
// src/fs/owners.ts
|
|
145
153
|
var ROOT_OWNER = Object.freeze({ uid: 0, gid: 0 });
|
|
@@ -311,7 +319,10 @@ var Perms = class {
|
|
|
311
319
|
function parts(path) {
|
|
312
320
|
return path.split("/").filter((part) => part !== "" && part !== ".");
|
|
313
321
|
}
|
|
314
|
-
|
|
322
|
+
function trustedLink(perm, links) {
|
|
323
|
+
return links === void 0 || perm.uid === 0 || perm.uid === links;
|
|
324
|
+
}
|
|
325
|
+
async function walk(fs, cred, path, follow2, links) {
|
|
315
326
|
const perms = new Perms(fs);
|
|
316
327
|
await perms.learn(path);
|
|
317
328
|
const queue = parts(path);
|
|
@@ -329,6 +340,7 @@ async function walk(fs, cred, path, follow2) {
|
|
|
329
340
|
const perm = await perms.at(next2);
|
|
330
341
|
const last = queue.length === 0;
|
|
331
342
|
if (perm?.link !== void 0 && (!last || follow2)) {
|
|
343
|
+
if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next2, link: true };
|
|
332
344
|
if (++hops > MAX_LINKS2) return { path: next2, perm: void 0 };
|
|
333
345
|
queue.unshift(...parts(perm.link));
|
|
334
346
|
if (perm.link.startsWith("/")) at = "/";
|
|
@@ -353,9 +365,9 @@ async function finalOf(fs, walked, want, options) {
|
|
|
353
365
|
return st ? [permOf(st), st.isDirectory] : [perm, false];
|
|
354
366
|
}
|
|
355
367
|
async function access(fs, cred, path, want, options = {}) {
|
|
356
|
-
const walked = await walk(fs, cred, path, options.follow !== false);
|
|
368
|
+
const walked = await walk(fs, cred, path, options.follow !== false, options.links);
|
|
357
369
|
if (walked.denied !== void 0) {
|
|
358
|
-
if (await present(fs, walked.denied, true)) return walked;
|
|
370
|
+
if (walked.link || await present(fs, walked.denied, true)) return walked;
|
|
359
371
|
return { path, perm: void 0, missing: true };
|
|
360
372
|
}
|
|
361
373
|
if (!walked.perm) return { ...walked, missing: true };
|
|
@@ -422,6 +434,9 @@ var Created = class {
|
|
|
422
434
|
return this.paths.delete(normalizePath(path));
|
|
423
435
|
}
|
|
424
436
|
};
|
|
437
|
+
function linked(g, options) {
|
|
438
|
+
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
439
|
+
}
|
|
425
440
|
function deny(g, op, path, errno = "EACCES") {
|
|
426
441
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
427
442
|
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno, ...tag });
|
|
@@ -432,8 +447,8 @@ function ttyOpenable(g, tty) {
|
|
|
432
447
|
deny(g, "open", tty.name ?? "/dev/tty");
|
|
433
448
|
}
|
|
434
449
|
async function need(g, op, path, want, options = {}, shown = path) {
|
|
435
|
-
const walked = await access(g.fs, g.cred, path, want, options);
|
|
436
|
-
if (walked.denied !== void 0) deny(g, op, shown);
|
|
450
|
+
const walked = await access(g.fs, g.cred, path, want, linked(g, options));
|
|
451
|
+
if (walked.denied !== void 0) deny(g, op, walked.link ? walked.denied : shown);
|
|
437
452
|
return walked;
|
|
438
453
|
}
|
|
439
454
|
function entryIn(dir, path) {
|
|
@@ -452,14 +467,16 @@ async function inParent(g, op, path, old = false) {
|
|
|
452
467
|
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
453
468
|
}
|
|
454
469
|
if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
|
|
455
|
-
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, DIR);
|
|
470
|
+
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, linked(g, DIR));
|
|
456
471
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
472
|
+
if (dir.link) return deny(g, op, dir.denied);
|
|
457
473
|
const lookup3 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
458
474
|
if (!lookup3 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
459
475
|
}
|
|
460
476
|
async function makeIn(g, op, path) {
|
|
461
477
|
for (let dir = parentOf(path); ; dir = parentOf(dir)) {
|
|
462
|
-
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, DIR);
|
|
478
|
+
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
479
|
+
if (walked.link) return deny(g, op, walked.denied);
|
|
463
480
|
if (walked.denied !== void 0) {
|
|
464
481
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
465
482
|
return;
|
|
@@ -3086,39 +3103,47 @@ var Integrity = class {
|
|
|
3086
3103
|
this.unknown = integrityUnknown(options);
|
|
3087
3104
|
this.report = report;
|
|
3088
3105
|
}
|
|
3089
|
-
async real(path) {
|
|
3106
|
+
async real(path, asked) {
|
|
3090
3107
|
const at = normalizePath(path);
|
|
3091
3108
|
const real = await this.root.realpath?.(at, true).catch(() => void 0) ?? at;
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
const
|
|
3096
|
-
|
|
3109
|
+
if (isProtected(this.prefixes, real)) return { real, name: real };
|
|
3110
|
+
const names = asked === void 0 ? [] : await namesOf(this.root, asked);
|
|
3111
|
+
if (real !== at) names.push(...await namesOf(this.root, at));
|
|
3112
|
+
const name2 = names.findLast((p) => isProtected(this.prefixes, p));
|
|
3113
|
+
return name2 === void 0 ? void 0 : { real, name: name2 };
|
|
3114
|
+
}
|
|
3115
|
+
async key(path, asked) {
|
|
3116
|
+
const found = await this.real(path, asked);
|
|
3117
|
+
if (found === void 0) return void 0;
|
|
3118
|
+
const { real, name: name2 } = found;
|
|
3119
|
+
if (name2 !== real) return `${name2}\0${real}\0`;
|
|
3120
|
+
if (!this.root.version) return void 0;
|
|
3097
3121
|
return `${real}\0${await this.root.version(real)}`;
|
|
3098
3122
|
}
|
|
3099
|
-
async read(path, caller, plain) {
|
|
3100
|
-
return (await this.readKeyed(path, caller, plain)).bytes;
|
|
3123
|
+
async read(path, caller, plain, asked) {
|
|
3124
|
+
return (await this.readKeyed(path, caller, plain, asked)).bytes;
|
|
3101
3125
|
}
|
|
3102
|
-
async readKeyed(path, caller, plain) {
|
|
3103
|
-
const
|
|
3104
|
-
if (
|
|
3105
|
-
const
|
|
3126
|
+
async readKeyed(path, caller, plain, asked) {
|
|
3127
|
+
const found = await this.real(path, asked);
|
|
3128
|
+
if (found === void 0) return { bytes: await plain() };
|
|
3129
|
+
const { real, name: name2 } = found;
|
|
3130
|
+
const read = name2 !== real ? { bytes: await plain(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
|
|
3106
3131
|
const { bytes } = read;
|
|
3107
3132
|
const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
|
|
3108
3133
|
const actual = await sha256(bytes);
|
|
3109
|
-
const denial = { pid: caller.pid, uid: caller.uid, path:
|
|
3134
|
+
const denial = { pid: caller.pid, uid: caller.uid, path: name2, actual };
|
|
3110
3135
|
const tagged = caller.tag !== void 0 ? { tag: caller.tag } : {};
|
|
3111
3136
|
let expected;
|
|
3112
3137
|
try {
|
|
3113
|
-
expected = await this.expected(
|
|
3138
|
+
expected = await this.expected(name2);
|
|
3114
3139
|
} catch {
|
|
3115
3140
|
this.say({ ...denial, ...tagged, op: "exec-integrity", errno: "EACCES" });
|
|
3116
|
-
throw fsError("EACCES", `integrity lookup failed: ${
|
|
3141
|
+
throw fsError("EACCES", `integrity lookup failed: ${name2}`);
|
|
3117
3142
|
}
|
|
3118
3143
|
if (expected === void 0) {
|
|
3119
3144
|
if (this.unknown === "allow") {
|
|
3120
|
-
if (!this.unverified.has(
|
|
3121
|
-
this.unverified.add(
|
|
3145
|
+
if (!this.unverified.has(name2)) {
|
|
3146
|
+
this.unverified.add(name2);
|
|
3122
3147
|
this.say({ ...denial, ...tagged, op: "exec-unverified", errno: "ENODATA" });
|
|
3123
3148
|
}
|
|
3124
3149
|
return keyed;
|
|
@@ -3128,7 +3153,12 @@ var Integrity = class {
|
|
|
3128
3153
|
}
|
|
3129
3154
|
const known = expected !== void 0 ? { expected } : {};
|
|
3130
3155
|
this.say({ ...denial, ...tagged, ...known, op: "exec-integrity", errno: "EACCES" });
|
|
3131
|
-
throw fsError("EACCES", `integrity check failed: ${
|
|
3156
|
+
throw fsError("EACCES", `integrity check failed: ${name2}`);
|
|
3157
|
+
}
|
|
3158
|
+
forget(path) {
|
|
3159
|
+
for (const name2 of [...this.unverified]) {
|
|
3160
|
+
if (path === void 0 || isProtected([path], name2)) this.unverified.delete(name2);
|
|
3161
|
+
}
|
|
3132
3162
|
}
|
|
3133
3163
|
async expected(path) {
|
|
3134
3164
|
const answer = await this.lookup(path);
|
|
@@ -3173,10 +3203,10 @@ function missing(err) {
|
|
|
3173
3203
|
const code = err?.code;
|
|
3174
3204
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
3175
3205
|
}
|
|
3176
|
-
async function resolved(fs, path, follow2) {
|
|
3206
|
+
async function resolved(fs, path, follow2, hops = []) {
|
|
3177
3207
|
let done4 = [];
|
|
3178
3208
|
let todo = partsOf(path);
|
|
3179
|
-
for (let
|
|
3209
|
+
for (let links = 0; todo.length > 0; ) {
|
|
3180
3210
|
const part = todo.shift();
|
|
3181
3211
|
if (part === "..") {
|
|
3182
3212
|
done4.pop();
|
|
@@ -3198,13 +3228,20 @@ async function resolved(fs, path, follow2) {
|
|
|
3198
3228
|
done4.push(part);
|
|
3199
3229
|
continue;
|
|
3200
3230
|
}
|
|
3201
|
-
if (++
|
|
3231
|
+
if (++links > MAX_LINKS4) throw fsError("ELOOP", path);
|
|
3232
|
+
hops.push(normalizePath([at, ...todo].join("/")));
|
|
3202
3233
|
const link2 = await fs.readlink(at);
|
|
3203
3234
|
if (link2.startsWith("/")) done4 = [];
|
|
3204
3235
|
todo = [...partsOf(link2), ...todo];
|
|
3205
3236
|
}
|
|
3206
3237
|
return `/${done4.join("/")}`;
|
|
3207
3238
|
}
|
|
3239
|
+
async function namesOf(fs, path) {
|
|
3240
|
+
const lexical2 = normalizePath(path);
|
|
3241
|
+
const hops = [];
|
|
3242
|
+
await resolved(fs, lexical2, true, hops).catch(() => void 0);
|
|
3243
|
+
return [lexical2, ...hops];
|
|
3244
|
+
}
|
|
3208
3245
|
var ProtectedFs = class {
|
|
3209
3246
|
prefixes;
|
|
3210
3247
|
constructor(prefixes2) {
|
|
@@ -3257,8 +3294,8 @@ var ProtectedFs = class {
|
|
|
3257
3294
|
await check(path, true);
|
|
3258
3295
|
return fs.utimes(path, atime, mtime);
|
|
3259
3296
|
},
|
|
3260
|
-
async mayChange(path, follow2) {
|
|
3261
|
-
await check(path, follow2);
|
|
3297
|
+
async mayChange(path, follow2, whole = false) {
|
|
3298
|
+
await check(path, follow2, whole);
|
|
3262
3299
|
},
|
|
3263
3300
|
async stat(path) {
|
|
3264
3301
|
return marked(path, await fs.stat(path));
|
|
@@ -3581,6 +3618,7 @@ var OpfsFs = class {
|
|
|
3581
3618
|
remote;
|
|
3582
3619
|
ranged;
|
|
3583
3620
|
owners = false;
|
|
3621
|
+
mounts = {};
|
|
3584
3622
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
3585
3623
|
this.root = root;
|
|
3586
3624
|
this.meta = sidecar(meta);
|
|
@@ -3654,6 +3692,12 @@ var OpfsFs = class {
|
|
|
3654
3692
|
trackOwners() {
|
|
3655
3693
|
this.owners = true;
|
|
3656
3694
|
}
|
|
3695
|
+
crossings(mounted) {
|
|
3696
|
+
this.mounts.mounted = mounted;
|
|
3697
|
+
}
|
|
3698
|
+
crossing(of, to) {
|
|
3699
|
+
if (this.mounts.mounted?.(to)) throw redirected(of, to);
|
|
3700
|
+
}
|
|
3657
3701
|
async hasOwner(path) {
|
|
3658
3702
|
return ownOf((await this.meta.get([path]))[0]) !== void 0;
|
|
3659
3703
|
}
|
|
@@ -3848,12 +3892,13 @@ var OpfsFs = class {
|
|
|
3848
3892
|
if (!link2) throw err;
|
|
3849
3893
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
3850
3894
|
const target = `${link2.link}${current.slice(link2.path.length)}`;
|
|
3851
|
-
current = target.split("/").includes("..") ? await this.physical(parentOf4(link2.path), target, hops + 1) : resolvePath(parentOf4(link2.path), target);
|
|
3895
|
+
current = target.split("/").includes("..") ? await this.physical(parentOf4(link2.path), target, hops + 1, path) : resolvePath(parentOf4(link2.path), target);
|
|
3896
|
+
this.crossing(path, current);
|
|
3852
3897
|
}
|
|
3853
3898
|
}
|
|
3854
3899
|
throw fsError("ELOOP", path);
|
|
3855
3900
|
}
|
|
3856
|
-
async physical(base, path, used) {
|
|
3901
|
+
async physical(base, path, used, of) {
|
|
3857
3902
|
let done4 = [];
|
|
3858
3903
|
let todo = (path.startsWith("/") ? path : `${base}/${path}`).split("/").filter((p) => p !== "" && p !== ".");
|
|
3859
3904
|
for (let hops = used; todo.length > 0; ) {
|
|
@@ -3862,6 +3907,7 @@ var OpfsFs = class {
|
|
|
3862
3907
|
else if (!todo.includes("..")) done4.push(part);
|
|
3863
3908
|
else {
|
|
3864
3909
|
const at = `/${[...done4, part].join("/")}`;
|
|
3910
|
+
this.crossing(of, [at, ...todo].join("/"));
|
|
3865
3911
|
const st = await this.lstat(at);
|
|
3866
3912
|
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
3867
3913
|
if (!st.isSymbolicLink) done4.push(part);
|
|
@@ -5992,14 +6038,14 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5992
6038
|
const own = await userDir(dir);
|
|
5993
6039
|
return own?.has(path.slice(slash + 1)) ? owned4(synthetic(false, path), dir) : void 0;
|
|
5994
6040
|
}
|
|
5995
|
-
async function
|
|
6041
|
+
async function linked2(path) {
|
|
5996
6042
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
5997
6043
|
}
|
|
5998
6044
|
async function stat(path, real) {
|
|
5999
6045
|
try {
|
|
6000
6046
|
return await real(path);
|
|
6001
6047
|
} catch (err) {
|
|
6002
|
-
const found = missing3(err) ? await
|
|
6048
|
+
const found = missing3(err) ? await linked2(path) : void 0;
|
|
6003
6049
|
if (found) return found;
|
|
6004
6050
|
throw err;
|
|
6005
6051
|
}
|
|
@@ -6011,7 +6057,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
6011
6057
|
try {
|
|
6012
6058
|
return await fs.readFileBuffer(path);
|
|
6013
6059
|
} catch (err) {
|
|
6014
|
-
if (missing3(err) && (await
|
|
6060
|
+
if (missing3(err) && (await linked2(path))?.isFile) return new Uint8Array(0);
|
|
6015
6061
|
throw err;
|
|
6016
6062
|
}
|
|
6017
6063
|
},
|
|
@@ -6019,7 +6065,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
6019
6065
|
link: (from, to, follow2) => fs.link(from, to, follow2),
|
|
6020
6066
|
links: (path) => mayLink(fs, path),
|
|
6021
6067
|
async exists(path) {
|
|
6022
|
-
return await fs.exists(path) || await
|
|
6068
|
+
return await fs.exists(path) || await linked2(path) !== void 0;
|
|
6023
6069
|
},
|
|
6024
6070
|
stat: (path) => stat(path, (p) => fs.stat(p)),
|
|
6025
6071
|
lstat: (path) => stat(path, (p) => fs.lstat(p)),
|
|
@@ -7389,6 +7435,7 @@ var MountTable = class {
|
|
|
7389
7435
|
return { quota: st.blocks * st.bsize, usage: (st.blocks - st.bfree) * st.bsize };
|
|
7390
7436
|
}
|
|
7391
7437
|
wrap(base) {
|
|
7438
|
+
base.crossings?.((path) => this.locate(normalizePath(path)) !== void 0);
|
|
7392
7439
|
return new MountFs(this, base);
|
|
7393
7440
|
}
|
|
7394
7441
|
};
|
|
@@ -7412,6 +7459,37 @@ var MountFs = class {
|
|
|
7412
7459
|
writable(mount, path) {
|
|
7413
7460
|
if (readonly(mount)) throw errnoError("EROFS", path);
|
|
7414
7461
|
}
|
|
7462
|
+
async through(path) {
|
|
7463
|
+
const real = normalizePath(path);
|
|
7464
|
+
if (this.at(real)) return real;
|
|
7465
|
+
try {
|
|
7466
|
+
await this.base.stat(parentOf7(real));
|
|
7467
|
+
return real;
|
|
7468
|
+
} catch (err) {
|
|
7469
|
+
const moved2 = redirectOf(err);
|
|
7470
|
+
return moved2 ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
async across(from, to, redirects) {
|
|
7474
|
+
const moved2 = [await this.through(from), await this.through(to)];
|
|
7475
|
+
const same = moved2[0] === normalizePath(from) && moved2[1] === normalizePath(to);
|
|
7476
|
+
if (same || redirects >= MAX_LINKS7) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
7477
|
+
return moved2;
|
|
7478
|
+
}
|
|
7479
|
+
async based(paths, redirects, run2, again) {
|
|
7480
|
+
try {
|
|
7481
|
+
return await run2();
|
|
7482
|
+
} catch (err) {
|
|
7483
|
+
const moved2 = redirectOf(err);
|
|
7484
|
+
if (!moved2) throw err;
|
|
7485
|
+
if (redirects >= MAX_LINKS7) throw errnoError("ELOOP", paths[0]);
|
|
7486
|
+
const at = paths.map((path) => {
|
|
7487
|
+
const real = normalizePath(path);
|
|
7488
|
+
return within5(real, moved2.of) ? normalizePath(moved2.to + real.slice(moved2.of.length)) : real;
|
|
7489
|
+
});
|
|
7490
|
+
return again(at, redirects + 1);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7415
7493
|
async follow(path, hops = 0, create = false) {
|
|
7416
7494
|
const found = this.at(path);
|
|
7417
7495
|
if (!found) return path;
|
|
@@ -7459,10 +7537,17 @@ var MountFs = class {
|
|
|
7459
7537
|
async readFile(path) {
|
|
7460
7538
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
7461
7539
|
}
|
|
7462
|
-
async readFileBuffer(path) {
|
|
7540
|
+
async readFileBuffer(path, redirects = 0) {
|
|
7463
7541
|
const real = await this.follow(path);
|
|
7464
7542
|
const found = this.at(real);
|
|
7465
|
-
if (!found)
|
|
7543
|
+
if (!found) {
|
|
7544
|
+
return this.based(
|
|
7545
|
+
[real],
|
|
7546
|
+
redirects,
|
|
7547
|
+
() => this.base.readFileBuffer(real),
|
|
7548
|
+
([to], n) => this.readFileBuffer(to, n)
|
|
7549
|
+
);
|
|
7550
|
+
}
|
|
7466
7551
|
for (let attempt = 1; ; attempt++) {
|
|
7467
7552
|
try {
|
|
7468
7553
|
return await this.readWhole(found.mount, real, found.rel);
|
|
@@ -7501,10 +7586,18 @@ var MountFs = class {
|
|
|
7501
7586
|
}
|
|
7502
7587
|
return concat3(chunks2, total);
|
|
7503
7588
|
}
|
|
7504
|
-
async writeFile(path, content, owner) {
|
|
7589
|
+
async writeFile(path, content, owner, redirects = 0) {
|
|
7505
7590
|
const real = await this.follow(path, 0, true);
|
|
7506
7591
|
const found = this.at(real);
|
|
7507
|
-
if (!found)
|
|
7592
|
+
if (!found) {
|
|
7593
|
+
const write = () => this.base.writeFile(real, content, owner);
|
|
7594
|
+
return this.based(
|
|
7595
|
+
[real],
|
|
7596
|
+
redirects,
|
|
7597
|
+
write,
|
|
7598
|
+
([to], n) => this.writeFile(to, content, owner, n)
|
|
7599
|
+
);
|
|
7600
|
+
}
|
|
7508
7601
|
const { mount, rel: rel2 } = found;
|
|
7509
7602
|
this.writable(mount, real);
|
|
7510
7603
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
@@ -7538,10 +7631,18 @@ var MountFs = class {
|
|
|
7538
7631
|
this.table.forget(mount, real);
|
|
7539
7632
|
}
|
|
7540
7633
|
}
|
|
7541
|
-
async pread(path, offset, length2, version) {
|
|
7634
|
+
async pread(path, offset, length2, version, redirects = 0) {
|
|
7542
7635
|
const real = await this.follow(path);
|
|
7543
7636
|
const found = this.at(real);
|
|
7544
|
-
|
|
7637
|
+
const { pread } = this.base;
|
|
7638
|
+
if (!found && pread) {
|
|
7639
|
+
return this.based(
|
|
7640
|
+
[real],
|
|
7641
|
+
redirects,
|
|
7642
|
+
() => pread.call(this.base, real, offset, length2),
|
|
7643
|
+
([to], n) => this.pread(to, offset, length2, version, n)
|
|
7644
|
+
);
|
|
7645
|
+
}
|
|
7545
7646
|
if (!found) return (await this.base.readFileBuffer(real)).slice(offset, offset + length2);
|
|
7546
7647
|
const { mount, rel: rel2 } = found;
|
|
7547
7648
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
@@ -7588,10 +7689,18 @@ var MountFs = class {
|
|
|
7588
7689
|
);
|
|
7589
7690
|
}
|
|
7590
7691
|
}
|
|
7591
|
-
async pwrite(path, offset, bytes, transfer = false) {
|
|
7692
|
+
async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
|
|
7592
7693
|
const real = await this.follow(path, 0, true);
|
|
7593
7694
|
const found = this.at(real);
|
|
7594
|
-
|
|
7695
|
+
const { pwrite } = this.base;
|
|
7696
|
+
if (!found && pwrite) {
|
|
7697
|
+
return this.based(
|
|
7698
|
+
[real],
|
|
7699
|
+
redirects,
|
|
7700
|
+
() => pwrite.call(this.base, real, offset, bytes),
|
|
7701
|
+
([to], n) => this.pwrite(to, offset, bytes, transfer, n)
|
|
7702
|
+
);
|
|
7703
|
+
}
|
|
7595
7704
|
if (!found)
|
|
7596
7705
|
return this.base.writeFile(
|
|
7597
7706
|
real,
|
|
@@ -7631,10 +7740,18 @@ var MountFs = class {
|
|
|
7631
7740
|
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
7632
7741
|
}
|
|
7633
7742
|
}
|
|
7634
|
-
async truncate(path, size) {
|
|
7743
|
+
async truncate(path, size, redirects = 0) {
|
|
7635
7744
|
const real = await this.follow(path);
|
|
7636
7745
|
const found = this.at(real);
|
|
7637
|
-
|
|
7746
|
+
const { truncate } = this.base;
|
|
7747
|
+
if (!found && truncate) {
|
|
7748
|
+
return this.based(
|
|
7749
|
+
[real],
|
|
7750
|
+
redirects,
|
|
7751
|
+
() => truncate.call(this.base, real, size),
|
|
7752
|
+
([to], n) => this.truncate(to, size, n)
|
|
7753
|
+
);
|
|
7754
|
+
}
|
|
7638
7755
|
if (!found?.mount.caps.ranges) {
|
|
7639
7756
|
return this.writeFile(real, resized(await this.readFileBuffer(real), size));
|
|
7640
7757
|
}
|
|
@@ -7650,8 +7767,15 @@ var MountFs = class {
|
|
|
7650
7767
|
this.table.forget(mount, real);
|
|
7651
7768
|
}
|
|
7652
7769
|
}
|
|
7653
|
-
async exists(path) {
|
|
7654
|
-
if (!this.at(path))
|
|
7770
|
+
async exists(path, redirects = 0) {
|
|
7771
|
+
if (!this.at(path)) {
|
|
7772
|
+
return this.based(
|
|
7773
|
+
[path],
|
|
7774
|
+
redirects,
|
|
7775
|
+
() => this.base.exists(path),
|
|
7776
|
+
([to], n) => this.exists(to, n)
|
|
7777
|
+
);
|
|
7778
|
+
}
|
|
7655
7779
|
try {
|
|
7656
7780
|
await this.stat(path);
|
|
7657
7781
|
return true;
|
|
@@ -7661,9 +7785,16 @@ var MountFs = class {
|
|
|
7661
7785
|
throw err;
|
|
7662
7786
|
}
|
|
7663
7787
|
}
|
|
7664
|
-
async lstat(path) {
|
|
7788
|
+
async lstat(path, redirects = 0) {
|
|
7665
7789
|
const found = this.at(path);
|
|
7666
|
-
if (!found)
|
|
7790
|
+
if (!found) {
|
|
7791
|
+
return this.based(
|
|
7792
|
+
[path],
|
|
7793
|
+
redirects,
|
|
7794
|
+
() => this.base.lstat(path),
|
|
7795
|
+
([to], n) => this.lstat(to, n)
|
|
7796
|
+
);
|
|
7797
|
+
}
|
|
7667
7798
|
const real = normalizePath(path);
|
|
7668
7799
|
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
7669
7800
|
return this.statWriting(
|
|
@@ -7676,9 +7807,15 @@ var MountFs = class {
|
|
|
7676
7807
|
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
7677
7808
|
return statOf({ ...attr2, size: Math.max(attr2.size, ...ends) }, real, mount);
|
|
7678
7809
|
}
|
|
7679
|
-
async stat(path) {
|
|
7810
|
+
async stat(path, redirects = 0) {
|
|
7680
7811
|
const real = await this.follow(path);
|
|
7681
|
-
|
|
7812
|
+
if (this.at(real)) return this.lstat(real);
|
|
7813
|
+
return this.based(
|
|
7814
|
+
[real],
|
|
7815
|
+
redirects,
|
|
7816
|
+
() => this.base.stat(real),
|
|
7817
|
+
([to], n) => this.stat(to, n)
|
|
7818
|
+
);
|
|
7682
7819
|
}
|
|
7683
7820
|
async entries(path) {
|
|
7684
7821
|
const real = await this.follow(path);
|
|
@@ -7690,12 +7827,26 @@ var MountFs = class {
|
|
|
7690
7827
|
list: await this.table.readdir(found.mount, real, found.rel)
|
|
7691
7828
|
};
|
|
7692
7829
|
}
|
|
7693
|
-
async readdir(path) {
|
|
7694
|
-
if (!this.at(path))
|
|
7830
|
+
async readdir(path, redirects = 0) {
|
|
7831
|
+
if (!this.at(path)) {
|
|
7832
|
+
return this.based(
|
|
7833
|
+
[path],
|
|
7834
|
+
redirects,
|
|
7835
|
+
() => this.base.readdir(path),
|
|
7836
|
+
([to], n) => this.readdir(to, n)
|
|
7837
|
+
);
|
|
7838
|
+
}
|
|
7695
7839
|
return (await this.entries(path)).list.map((e) => e.name);
|
|
7696
7840
|
}
|
|
7697
|
-
async readdirStat(path) {
|
|
7698
|
-
if (!this.at(path))
|
|
7841
|
+
async readdirStat(path, redirects = 0) {
|
|
7842
|
+
if (!this.at(path)) {
|
|
7843
|
+
return this.based(
|
|
7844
|
+
[path],
|
|
7845
|
+
redirects,
|
|
7846
|
+
() => this.base.readdirStat(path),
|
|
7847
|
+
([to], n) => this.readdirStat(to, n)
|
|
7848
|
+
);
|
|
7849
|
+
}
|
|
7699
7850
|
const { real, mount, list } = await this.entries(path);
|
|
7700
7851
|
return Promise.all(
|
|
7701
7852
|
list.map(async (entry) => {
|
|
@@ -7707,9 +7858,16 @@ var MountFs = class {
|
|
|
7707
7858
|
})
|
|
7708
7859
|
);
|
|
7709
7860
|
}
|
|
7710
|
-
async mkdir(path, options = {}) {
|
|
7861
|
+
async mkdir(path, options = {}, redirects = 0) {
|
|
7711
7862
|
const found = this.at(path);
|
|
7712
|
-
if (!found)
|
|
7863
|
+
if (!found) {
|
|
7864
|
+
return this.based(
|
|
7865
|
+
[path],
|
|
7866
|
+
redirects,
|
|
7867
|
+
() => this.base.mkdir(path, options),
|
|
7868
|
+
([to], n) => this.mkdir(to, options, n)
|
|
7869
|
+
);
|
|
7870
|
+
}
|
|
7713
7871
|
const { mount, rel: rel2 } = found;
|
|
7714
7872
|
const real = normalizePath(path);
|
|
7715
7873
|
this.writable(mount, real);
|
|
@@ -7734,11 +7892,18 @@ var MountFs = class {
|
|
|
7734
7892
|
await mount.conn.call({ op: "mkdir", path: sub, ...made2 });
|
|
7735
7893
|
}
|
|
7736
7894
|
}
|
|
7737
|
-
async rm(path, options = {}) {
|
|
7895
|
+
async rm(path, options = {}, redirects = 0) {
|
|
7738
7896
|
const found = this.at(path);
|
|
7739
7897
|
if (!found && options.recursive && this.table.under(normalizePath(path)))
|
|
7740
7898
|
return this.rmAround(normalizePath(path), options);
|
|
7741
|
-
if (!found)
|
|
7899
|
+
if (!found) {
|
|
7900
|
+
return this.based(
|
|
7901
|
+
[path],
|
|
7902
|
+
redirects,
|
|
7903
|
+
() => this.base.rm(path, options),
|
|
7904
|
+
([to], n) => this.rm(to, options, n)
|
|
7905
|
+
);
|
|
7906
|
+
}
|
|
7742
7907
|
const { mount, rel: rel2 } = found;
|
|
7743
7908
|
const real = normalizePath(path);
|
|
7744
7909
|
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
@@ -7779,11 +7944,22 @@ var MountFs = class {
|
|
|
7779
7944
|
}
|
|
7780
7945
|
throw first ?? errnoError("EBUSY", `${path} holds a mount point`);
|
|
7781
7946
|
}
|
|
7782
|
-
async rename(from, to) {
|
|
7947
|
+
async rename(from, to, redirects = 0) {
|
|
7783
7948
|
const a = this.at(from);
|
|
7784
7949
|
const b = this.at(to);
|
|
7785
|
-
if (!a && !b)
|
|
7786
|
-
|
|
7950
|
+
if (!a && !b) {
|
|
7951
|
+
return this.based(
|
|
7952
|
+
[from, to],
|
|
7953
|
+
redirects,
|
|
7954
|
+
() => this.base.rename(from, to),
|
|
7955
|
+
([f, t], n) => this.rename(f, t, n)
|
|
7956
|
+
);
|
|
7957
|
+
}
|
|
7958
|
+
if (!a || !b) {
|
|
7959
|
+
const [f, t] = await this.across(from, to, redirects);
|
|
7960
|
+
return this.rename(f, t, redirects + 1);
|
|
7961
|
+
}
|
|
7962
|
+
if (a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
7787
7963
|
this.writable(a.mount, normalizePath(to));
|
|
7788
7964
|
await this.table.commitUnder(from);
|
|
7789
7965
|
await this.table.commitUnder(to);
|
|
@@ -7824,9 +8000,17 @@ var MountFs = class {
|
|
|
7824
8000
|
this.table.forget(a.mount, normalizePath(to));
|
|
7825
8001
|
}
|
|
7826
8002
|
}
|
|
7827
|
-
async symlink(target, path, owner) {
|
|
8003
|
+
async symlink(target, path, owner, redirects = 0) {
|
|
7828
8004
|
const found = this.at(path);
|
|
7829
|
-
if (!found)
|
|
8005
|
+
if (!found) {
|
|
8006
|
+
const make = () => this.base.symlink(target, path, owner);
|
|
8007
|
+
return this.based(
|
|
8008
|
+
[path],
|
|
8009
|
+
redirects,
|
|
8010
|
+
make,
|
|
8011
|
+
([to], n) => this.symlink(target, to, owner, n)
|
|
8012
|
+
);
|
|
8013
|
+
}
|
|
7830
8014
|
this.writable(found.mount, normalizePath(path));
|
|
7831
8015
|
if (!found.mount.caps.symlinks)
|
|
7832
8016
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
@@ -7836,8 +8020,11 @@ var MountFs = class {
|
|
|
7836
8020
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel, ...made2 });
|
|
7837
8021
|
}
|
|
7838
8022
|
async realpath(path, follow2) {
|
|
7839
|
-
|
|
7840
|
-
|
|
8023
|
+
const { realpath: realpath2 } = this.base;
|
|
8024
|
+
if (this.at(path) || !realpath2) throw errnoError("ENOSYS", path);
|
|
8025
|
+
const real = await realpath2.call(this.base, path, follow2).catch((err) => {
|
|
8026
|
+
throw redirectOf(err) ? errnoError("ENOSYS", path) : err;
|
|
8027
|
+
});
|
|
7841
8028
|
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
7842
8029
|
return real;
|
|
7843
8030
|
}
|
|
@@ -7859,17 +8046,30 @@ var MountFs = class {
|
|
|
7859
8046
|
}
|
|
7860
8047
|
return out;
|
|
7861
8048
|
}
|
|
7862
|
-
async readlink(path) {
|
|
8049
|
+
async readlink(path, redirects = 0) {
|
|
7863
8050
|
const found = this.at(path);
|
|
7864
|
-
if (!found)
|
|
8051
|
+
if (!found) {
|
|
8052
|
+
return this.based(
|
|
8053
|
+
[path],
|
|
8054
|
+
redirects,
|
|
8055
|
+
() => this.base.readlink(path),
|
|
8056
|
+
([to], n) => this.readlink(to, n)
|
|
8057
|
+
);
|
|
8058
|
+
}
|
|
7865
8059
|
return await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
7866
8060
|
}
|
|
7867
|
-
async chown(path, change) {
|
|
8061
|
+
async chown(path, change, redirects = 0) {
|
|
7868
8062
|
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
7869
8063
|
const found = this.at(real);
|
|
7870
8064
|
if (found) return this.chownMounted(found, normalizePath(real), change);
|
|
7871
|
-
|
|
7872
|
-
|
|
8065
|
+
const { chown: chown2 } = this.base;
|
|
8066
|
+
if (!chown2) throw errnoError("EPERM", path);
|
|
8067
|
+
return this.based(
|
|
8068
|
+
[real],
|
|
8069
|
+
redirects,
|
|
8070
|
+
() => chown2.call(this.base, real, change),
|
|
8071
|
+
([to], n) => this.chown(to, change, n)
|
|
8072
|
+
);
|
|
7873
8073
|
}
|
|
7874
8074
|
async chownMounted(found, real, change) {
|
|
7875
8075
|
const { mount, rel: rel2 } = found;
|
|
@@ -7889,24 +8089,47 @@ var MountFs = class {
|
|
|
7889
8089
|
...Object.fromEntries(attrs.filter(([, value]) => value !== void 0))
|
|
7890
8090
|
});
|
|
7891
8091
|
}
|
|
7892
|
-
async chmod(path, mode) {
|
|
8092
|
+
async chmod(path, mode, redirects = 0) {
|
|
7893
8093
|
const real = await this.follow(path);
|
|
7894
8094
|
const found = this.at(real);
|
|
7895
|
-
if (!found)
|
|
8095
|
+
if (!found) {
|
|
8096
|
+
return this.based(
|
|
8097
|
+
[real],
|
|
8098
|
+
redirects,
|
|
8099
|
+
() => this.base.chmod(real, mode),
|
|
8100
|
+
([to], n) => this.chmod(to, mode, n)
|
|
8101
|
+
);
|
|
8102
|
+
}
|
|
7896
8103
|
this.writable(found.mount, real);
|
|
7897
8104
|
if (!found.mount.caps.chmod) return;
|
|
7898
8105
|
this.table.forget(found.mount, real);
|
|
7899
8106
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
7900
8107
|
}
|
|
7901
|
-
async utimes(path, atime, mtime) {
|
|
8108
|
+
async utimes(path, atime, mtime, redirects = 0) {
|
|
7902
8109
|
const real = await this.follow(path);
|
|
7903
8110
|
const found = this.at(real);
|
|
7904
|
-
if (!found)
|
|
8111
|
+
if (!found) {
|
|
8112
|
+
const set2 = () => this.base.utimes(real, atime, mtime);
|
|
8113
|
+
return this.based(
|
|
8114
|
+
[real],
|
|
8115
|
+
redirects,
|
|
8116
|
+
set2,
|
|
8117
|
+
([to], n) => this.utimes(to, atime, mtime, n)
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
7905
8120
|
await this.setMtime(found, real, mtime);
|
|
7906
8121
|
}
|
|
7907
|
-
async lutimes(path, atime, mtime) {
|
|
8122
|
+
async lutimes(path, atime, mtime, redirects = 0) {
|
|
7908
8123
|
const found = this.at(path);
|
|
7909
|
-
if (!found)
|
|
8124
|
+
if (!found) {
|
|
8125
|
+
const set2 = () => lutimesOf(this.base, path, atime, mtime);
|
|
8126
|
+
return this.based(
|
|
8127
|
+
[path],
|
|
8128
|
+
redirects,
|
|
8129
|
+
set2,
|
|
8130
|
+
([to], n) => this.lutimes(to, atime, mtime, n)
|
|
8131
|
+
);
|
|
8132
|
+
}
|
|
7910
8133
|
const real = normalizePath(path);
|
|
7911
8134
|
if (!found.mount.caps.linkTimes && (await this.lstat(real)).isSymbolicLink) {
|
|
7912
8135
|
throw errnoError("EOPNOTSUPP", path);
|
|
@@ -8125,7 +8348,8 @@ async function run(entry, path, req) {
|
|
|
8125
8348
|
function guardOf(entry) {
|
|
8126
8349
|
const cred = entry.dac && entry.cred?.();
|
|
8127
8350
|
if (!cred || !entry.dac) return void 0;
|
|
8128
|
-
|
|
8351
|
+
const links = entry.links === void 0 ? {} : { links: entry.links };
|
|
8352
|
+
return { fs: entry.fs, cred, pid: entry.pid ?? 0, dac: entry.dac, ...links };
|
|
8129
8353
|
}
|
|
8130
8354
|
var FOLLOWING = /* @__PURE__ */ new Set(["exists", "stat", "chown", "statfs"]);
|
|
8131
8355
|
var LOOKS = /* @__PURE__ */ new Set(["exists", "stat", "lstat"]);
|
|
@@ -8186,9 +8410,15 @@ async function holdOp(entry, path, req) {
|
|
|
8186
8410
|
entry.hold?.(path, on, open, void 0, req.handle);
|
|
8187
8411
|
return done;
|
|
8188
8412
|
}
|
|
8413
|
+
async function followed(g, path) {
|
|
8414
|
+
const st = await g.fs.lstat(path).catch(() => void 0);
|
|
8415
|
+
if (st?.isSymbolicLink && !trustedLink(permOf(st), g.links)) deny(g, "follow", path);
|
|
8416
|
+
return done;
|
|
8417
|
+
}
|
|
8189
8418
|
async function accessOp(entry, path, req) {
|
|
8190
8419
|
const g = guardOf(entry);
|
|
8191
8420
|
if (!g) return done;
|
|
8421
|
+
if (req.arg2 === "follow") return followed(g, path);
|
|
8192
8422
|
const open = req.arg2 === "open";
|
|
8193
8423
|
const cred = open || req.arg2 === "eaccess" ? g.cred : realIds(g.cred);
|
|
8194
8424
|
const options = { follow: req.nofollow !== true, ...open ? { directory: false } : {} };
|
|
@@ -8211,15 +8441,18 @@ var CHANGING = /* @__PURE__ */ new Set([
|
|
|
8211
8441
|
"lchown"
|
|
8212
8442
|
]);
|
|
8213
8443
|
var CONTENT = /* @__PURE__ */ new Set(["write", "pwrite", "truncate"]);
|
|
8444
|
+
var REMOVING = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm", "rename"]);
|
|
8214
8445
|
async function mayChange(entry, path, req) {
|
|
8215
8446
|
const { mayChange: mayChange2 } = entry.fs;
|
|
8216
8447
|
if (!mayChange2) return;
|
|
8217
8448
|
const { op } = req;
|
|
8218
8449
|
if (CONTENT.has(op) && req.handle === void 0) return mayChange2.call(entry.fs, path, true);
|
|
8219
8450
|
if (!CHANGING.has(op)) return;
|
|
8220
|
-
|
|
8451
|
+
const follow2 = op === "utimes" || op === "chmod" || op === "chown";
|
|
8452
|
+
await mayChange2.call(entry.fs, path, follow2, REMOVING.has(op));
|
|
8221
8453
|
if (op === "rename" || op === "link") {
|
|
8222
|
-
|
|
8454
|
+
const to = entry.fs.resolvePath(entry.cwd, req.arg2 ?? "");
|
|
8455
|
+
await mayChange2.call(entry.fs, to, false, op === "rename");
|
|
8223
8456
|
}
|
|
8224
8457
|
}
|
|
8225
8458
|
async function guarded(entry, path, req) {
|
|
@@ -8939,7 +9172,7 @@ function mountTable(mounts = []) {
|
|
|
8939
9172
|
}
|
|
8940
9173
|
|
|
8941
9174
|
// src/version.ts
|
|
8942
|
-
var KERNEL_VERSION = true ? "1.
|
|
9175
|
+
var KERNEL_VERSION = true ? "1.89.0" : "0.0.0-dev";
|
|
8943
9176
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8944
9177
|
function procVersion() {
|
|
8945
9178
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -13031,7 +13264,7 @@ var WasmProcess = class {
|
|
|
13031
13264
|
const { guard: guard2 } = this.options;
|
|
13032
13265
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
13033
13266
|
if (!guard2 || inherited2 || req.pin !== void 0) return;
|
|
13034
|
-
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13267
|
+
const g = { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13035
13268
|
if (req.exclusive) return inParent(g, "open", req.path);
|
|
13036
13269
|
if (req.created && guard2.created?.take(req.path)) return;
|
|
13037
13270
|
const access2 = req.flags & WRITE_ACCESS;
|
|
@@ -13087,7 +13320,7 @@ var WasmProcess = class {
|
|
|
13087
13320
|
}
|
|
13088
13321
|
guarded() {
|
|
13089
13322
|
const { guard: guard2 } = this.options;
|
|
13090
|
-
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
|
|
13323
|
+
return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid, links: guard2.links };
|
|
13091
13324
|
}
|
|
13092
13325
|
ttyOwner() {
|
|
13093
13326
|
return { uid: this.cred.euid, gid: this.cred.egid, mode: TTY_MODE };
|
|
@@ -13813,6 +14046,7 @@ function processInit(opts, sab, umask, cred, lane) {
|
|
|
13813
14046
|
umask,
|
|
13814
14047
|
cred,
|
|
13815
14048
|
...opts.owners ? { owners: true } : {},
|
|
14049
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
13816
14050
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
13817
14051
|
};
|
|
13818
14052
|
if (opts.program.abi === "js") {
|
|
@@ -13840,6 +14074,7 @@ function holdingToken(opts, holds, caller) {
|
|
|
13840
14074
|
return mintSyncFsToken({
|
|
13841
14075
|
...opts.owners ? caller : {},
|
|
13842
14076
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
14077
|
+
...opts.links !== void 0 ? { links: opts.links } : {},
|
|
13843
14078
|
...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
|
|
13844
14079
|
fs: opts.fs,
|
|
13845
14080
|
cwd: opts.cwd,
|
|
@@ -13853,6 +14088,9 @@ function holdingToken(opts, holds, caller) {
|
|
|
13853
14088
|
renamed: (from, to) => holds.renamed(from, to)
|
|
13854
14089
|
});
|
|
13855
14090
|
}
|
|
14091
|
+
function linksOf(opts) {
|
|
14092
|
+
return opts.links === void 0 ? {} : { links: opts.links };
|
|
14093
|
+
}
|
|
13856
14094
|
function clipboardName(opts) {
|
|
13857
14095
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
13858
14096
|
}
|
|
@@ -13864,7 +14102,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
13864
14102
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
13865
14103
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
13866
14104
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
13867
|
-
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
14105
|
+
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3, ...linksOf(opts) } } : {},
|
|
13868
14106
|
...opts.identity ? { identity: opts.identity } : {},
|
|
13869
14107
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
13870
14108
|
...opts.settling ? { settling: opts.settling } : {},
|
|
@@ -13910,6 +14148,7 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
13910
14148
|
sab,
|
|
13911
14149
|
cred: copyCred(cred),
|
|
13912
14150
|
owners: opts.owners === true,
|
|
14151
|
+
...opts.links !== void 0 ? { links: true } : {},
|
|
13913
14152
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
13914
14153
|
thread,
|
|
13915
14154
|
signals: main
|
|
@@ -17313,6 +17552,9 @@ var SUDO_SOURCE = [
|
|
|
17313
17552
|
].join("\n");
|
|
17314
17553
|
|
|
17315
17554
|
// src/launcher.ts
|
|
17555
|
+
function linksOf2(req) {
|
|
17556
|
+
return req.links === void 0 ? {} : { links: req.links };
|
|
17557
|
+
}
|
|
17316
17558
|
var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
17317
17559
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
17318
17560
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
@@ -17488,6 +17730,7 @@ var Launcher = class {
|
|
|
17488
17730
|
warned = /* @__PURE__ */ new Set();
|
|
17489
17731
|
compiled = /* @__PURE__ */ new Map();
|
|
17490
17732
|
texts = /* @__PURE__ */ new Map();
|
|
17733
|
+
revocations = 0;
|
|
17491
17734
|
integrity;
|
|
17492
17735
|
scannedFs;
|
|
17493
17736
|
get scanned() {
|
|
@@ -17500,6 +17743,7 @@ var Launcher = class {
|
|
|
17500
17743
|
described = /* @__PURE__ */ new Map();
|
|
17501
17744
|
creds = /* @__PURE__ */ new Map();
|
|
17502
17745
|
tags = /* @__PURE__ */ new Map();
|
|
17746
|
+
links = /* @__PURE__ */ new Map();
|
|
17503
17747
|
freshModules = new FreshModules();
|
|
17504
17748
|
granted = /* @__PURE__ */ new Map();
|
|
17505
17749
|
users;
|
|
@@ -17802,14 +18046,16 @@ var Launcher = class {
|
|
|
17802
18046
|
}
|
|
17803
18047
|
const path = this.fs.resolvePath(cwd, file);
|
|
17804
18048
|
const glue = await followLinks(this.base, path);
|
|
17805
|
-
const
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
const
|
|
18049
|
+
const asked = glue === path ? {} : { asked: path };
|
|
18050
|
+
const linked2 = COMMAND2.exec(glue)?.[1];
|
|
18051
|
+
if (linked2 !== void 0) {
|
|
18052
|
+
const found = await this.resolve(`/bin/${linked2}`, argv0, cwd);
|
|
18053
|
+
const target = found && { ...found, ...asked };
|
|
18054
|
+
const byPath = !COMMAND2.test(path) && (await this.commands()).get(linked2)?.argv0Path === true;
|
|
17809
18055
|
return target && byPath ? { ...target, argv0: path } : target;
|
|
17810
18056
|
}
|
|
17811
18057
|
const own = await this.commandAt(glue, scope);
|
|
17812
|
-
if (own) return own.script ? void 0 : targetOf(own);
|
|
18058
|
+
if (own) return own.script ? void 0 : { ...targetOf(own), ...asked };
|
|
17813
18059
|
const head = await this.head(glue);
|
|
17814
18060
|
if (!head) return void 0;
|
|
17815
18061
|
if (isWasm(head)) {
|
|
@@ -17817,13 +18063,14 @@ var Launcher = class {
|
|
|
17817
18063
|
abi: "wasi",
|
|
17818
18064
|
glue,
|
|
17819
18065
|
wasm: glue,
|
|
17820
|
-
argv0: baseName(argv0 || file).replace(/\.wasm$/, "")
|
|
18066
|
+
argv0: baseName(argv0 || file).replace(/\.wasm$/, ""),
|
|
18067
|
+
...asked
|
|
17821
18068
|
};
|
|
17822
18069
|
}
|
|
17823
18070
|
if (interpreter(head) !== "node") return void 0;
|
|
17824
18071
|
const wasm = modulePath(glue);
|
|
17825
18072
|
if (!await this.base.exists(wasm)) return void 0;
|
|
17826
|
-
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file) };
|
|
18073
|
+
return { abi: "emscripten", glue, wasm, argv0: baseName(argv0 || file), ...asked };
|
|
17827
18074
|
}
|
|
17828
18075
|
async head(path) {
|
|
17829
18076
|
try {
|
|
@@ -17841,6 +18088,8 @@ var Launcher = class {
|
|
|
17841
18088
|
async interpreted(file, argv, cwd, scope, depth = 0) {
|
|
17842
18089
|
const command = await this.scriptCommand(file, cwd, scope);
|
|
17843
18090
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
18091
|
+
const byPath = command && file.includes("/") && !COMMAND2.test(file);
|
|
18092
|
+
const named = byPath ? { [script]: this.fs.resolvePath(cwd, file) } : {};
|
|
17844
18093
|
const head = await this.head(script);
|
|
17845
18094
|
if (!head) return void 0;
|
|
17846
18095
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
@@ -17863,7 +18112,8 @@ var Launcher = class {
|
|
|
17863
18112
|
target: withScriptEnv(inner.target, command),
|
|
17864
18113
|
via,
|
|
17865
18114
|
sources,
|
|
17866
|
-
...bins.length > 0 ? { bins } : {}
|
|
18115
|
+
...bins.length > 0 ? { bins } : {},
|
|
18116
|
+
asked: { ...inner.asked, ...named }
|
|
17867
18117
|
};
|
|
17868
18118
|
}
|
|
17869
18119
|
const target = withScriptEnv(found, command);
|
|
@@ -17872,7 +18122,8 @@ var Launcher = class {
|
|
|
17872
18122
|
args: [...target.prefix ?? [], ...passed],
|
|
17873
18123
|
via: [interp],
|
|
17874
18124
|
sources: [script],
|
|
17875
|
-
...command?.bin ? { bins: [script] } : {}
|
|
18125
|
+
...command?.bin ? { bins: [script] } : {},
|
|
18126
|
+
asked: named
|
|
17876
18127
|
};
|
|
17877
18128
|
}
|
|
17878
18129
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17886,7 +18137,14 @@ var Launcher = class {
|
|
|
17886
18137
|
async mayExec(cred, req, planned) {
|
|
17887
18138
|
const { dac } = this;
|
|
17888
18139
|
if (!dac) return;
|
|
17889
|
-
const g = {
|
|
18140
|
+
const g = {
|
|
18141
|
+
fs: this.fs,
|
|
18142
|
+
cred,
|
|
18143
|
+
pid: req.pid,
|
|
18144
|
+
dac,
|
|
18145
|
+
tag: req.tag,
|
|
18146
|
+
links: this.links.get(req.pid)
|
|
18147
|
+
};
|
|
17890
18148
|
const byPath = (file) => file.includes("/") && !COMMAND2.test(file);
|
|
17891
18149
|
if (byPath(req.file)) {
|
|
17892
18150
|
const path = this.fs.resolvePath(req.cwd, req.file);
|
|
@@ -18043,8 +18301,8 @@ var Launcher = class {
|
|
|
18043
18301
|
readFile: (path) => this.integrity ? this.text(path, KERNEL_CALLER) : fs.readFile(path)
|
|
18044
18302
|
});
|
|
18045
18303
|
}
|
|
18046
|
-
async cacheKey(path) {
|
|
18047
|
-
const verified = await this.integrity?.key(path);
|
|
18304
|
+
async cacheKey(path, asked) {
|
|
18305
|
+
const verified = await this.integrity?.key(path, asked);
|
|
18048
18306
|
if (verified !== void 0) return verified;
|
|
18049
18307
|
const st = await this.base.stat(path);
|
|
18050
18308
|
return `${path}:${st.size}:${st.mtime.getTime()}`;
|
|
@@ -18053,30 +18311,31 @@ var Launcher = class {
|
|
|
18053
18311
|
const plain = () => fs.readFileBuffer(path);
|
|
18054
18312
|
return this.integrity ? this.integrity.read(path, caller, plain) : plain();
|
|
18055
18313
|
}
|
|
18056
|
-
keyed(path, caller) {
|
|
18314
|
+
keyed(path, caller, asked) {
|
|
18057
18315
|
const plain = async () => this.base.readFileBuffer(path);
|
|
18058
|
-
return this.integrity ? this.integrity.readKeyed(path, caller, plain) : plain().then((bytes) => ({ bytes }));
|
|
18316
|
+
return this.integrity ? this.integrity.readKeyed(path, caller, plain, asked) : plain().then((bytes) => ({ bytes }));
|
|
18059
18317
|
}
|
|
18060
18318
|
cached(cache, key, load) {
|
|
18061
18319
|
const hit = cache.get(key);
|
|
18062
18320
|
if (hit !== void 0) return hit;
|
|
18321
|
+
const revocations = this.revocations;
|
|
18063
18322
|
const loading2 = load();
|
|
18064
18323
|
const found = loading2.then(({ value }) => value);
|
|
18065
18324
|
cache.set(key, found);
|
|
18066
|
-
|
|
18067
|
-
(
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
()
|
|
18073
|
-
);
|
|
18325
|
+
const drop = () => {
|
|
18326
|
+
if (cache.get(key) === found) cache.delete(key);
|
|
18327
|
+
};
|
|
18328
|
+
loading2.then((done4) => {
|
|
18329
|
+
if (done4.key === key || done4.key === void 0 && !key.includes("\0")) return;
|
|
18330
|
+
drop();
|
|
18331
|
+
if (done4.key !== void 0 && revocations === this.revocations) cache.set(done4.key, found);
|
|
18332
|
+
}, drop);
|
|
18074
18333
|
return found;
|
|
18075
18334
|
}
|
|
18076
|
-
async module(path, caller) {
|
|
18077
|
-
const key = await this.cacheKey(path);
|
|
18335
|
+
async module(path, caller, asked) {
|
|
18336
|
+
const key = await this.cacheKey(path, asked);
|
|
18078
18337
|
return this.cached(this.compiled, key, async () => {
|
|
18079
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18338
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18080
18339
|
const memory = importedMemory(bytes);
|
|
18081
18340
|
const foreign = foreignImports(bytes);
|
|
18082
18341
|
const compiled = await WebAssembly.compile(bytes);
|
|
@@ -18085,22 +18344,30 @@ var Launcher = class {
|
|
|
18085
18344
|
}
|
|
18086
18345
|
async checkedSources(planned, caller) {
|
|
18087
18346
|
const { target } = planned;
|
|
18088
|
-
const files = [
|
|
18347
|
+
const files = [
|
|
18348
|
+
target.wasm,
|
|
18349
|
+
target.glue,
|
|
18350
|
+
target.imports,
|
|
18351
|
+
target.asked,
|
|
18352
|
+
...planned.sources ?? []
|
|
18353
|
+
];
|
|
18089
18354
|
const manifests = /* @__PURE__ */ new Set();
|
|
18090
18355
|
for (const file of files) {
|
|
18091
18356
|
const root = file === void 0 ? void 0 : PACKAGE_ROOT.exec(file)?.[1];
|
|
18092
18357
|
if (root !== void 0) manifests.add(`${root}/package.json`);
|
|
18093
18358
|
}
|
|
18094
|
-
for (const source of planned.sources ?? [])
|
|
18359
|
+
for (const source of planned.sources ?? []) {
|
|
18360
|
+
await this.text(source, caller, planned.asked?.[source]);
|
|
18361
|
+
}
|
|
18095
18362
|
for (const manifest of manifests) {
|
|
18096
18363
|
if (await this.base.exists(manifest)) await this.text(manifest, caller);
|
|
18097
18364
|
}
|
|
18098
18365
|
}
|
|
18099
|
-
async text(path, caller) {
|
|
18366
|
+
async text(path, caller, asked) {
|
|
18100
18367
|
if (!this.integrity) return this.base.readFile(path);
|
|
18101
|
-
const key = await this.cacheKey(path);
|
|
18368
|
+
const key = await this.cacheKey(path, asked);
|
|
18102
18369
|
return this.cached(this.texts, key, async () => {
|
|
18103
|
-
const { bytes, key: read } = await this.keyed(path, caller);
|
|
18370
|
+
const { bytes, key: read } = await this.keyed(path, caller, asked);
|
|
18104
18371
|
return { value: new TextDecoder().decode(bytes), key: read };
|
|
18105
18372
|
});
|
|
18106
18373
|
}
|
|
@@ -18117,17 +18384,18 @@ var Launcher = class {
|
|
|
18117
18384
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
18118
18385
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
18119
18386
|
}
|
|
18387
|
+
const { asked } = target;
|
|
18120
18388
|
if (target.abi === "js") {
|
|
18121
|
-
return { abi: "js", glue: await this.text(target.wasm, caller), path: target.wasm };
|
|
18389
|
+
return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
|
|
18122
18390
|
}
|
|
18123
18391
|
if (target.abi !== "wasi") {
|
|
18124
18392
|
const [glue, { module: module2 }] = await Promise.all([
|
|
18125
|
-
this.text(target.glue, caller),
|
|
18126
|
-
this.module(target.wasm, caller)
|
|
18393
|
+
this.text(target.glue, caller, asked),
|
|
18394
|
+
this.module(target.wasm, caller, asked && modulePath(asked))
|
|
18127
18395
|
]);
|
|
18128
18396
|
return { glue, module: module2 };
|
|
18129
18397
|
}
|
|
18130
|
-
const { module, memory, foreign } = await this.module(target.wasm, caller);
|
|
18398
|
+
const { module, memory, foreign } = await this.module(target.wasm, caller, asked);
|
|
18131
18399
|
const names = env.SLICC_WASM_BACKTRACE === "1" ? await this.names(target.wasm, module) : void 0;
|
|
18132
18400
|
const imports = target.imports ? await this.text(target.imports, caller) : void 0;
|
|
18133
18401
|
return {
|
|
@@ -18168,6 +18436,10 @@ var Launcher = class {
|
|
|
18168
18436
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18169
18437
|
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
18170
18438
|
}
|
|
18439
|
+
marks(pid, req) {
|
|
18440
|
+
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
18441
|
+
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
18442
|
+
}
|
|
18171
18443
|
start(req) {
|
|
18172
18444
|
this.sampling();
|
|
18173
18445
|
if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
|
|
@@ -18200,6 +18472,7 @@ var Launcher = class {
|
|
|
18200
18472
|
cred: req.cred,
|
|
18201
18473
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
18202
18474
|
...this.owners ? { owners: true } : {},
|
|
18475
|
+
...linksOf2(req),
|
|
18203
18476
|
sealed: this.sealed,
|
|
18204
18477
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
18205
18478
|
clipboard: this.clipboard,
|
|
@@ -18247,7 +18520,7 @@ var Launcher = class {
|
|
|
18247
18520
|
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18248
18521
|
const { cred } = req;
|
|
18249
18522
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
18250
|
-
|
|
18523
|
+
this.marks(pid, req);
|
|
18251
18524
|
if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
|
|
18252
18525
|
this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
|
|
18253
18526
|
if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
|
|
@@ -18300,6 +18573,7 @@ var Launcher = class {
|
|
|
18300
18573
|
this.childTimes.delete(pid);
|
|
18301
18574
|
this.creds.delete(pid);
|
|
18302
18575
|
this.tags.delete(pid);
|
|
18576
|
+
this.links.delete(pid);
|
|
18303
18577
|
this.granted.delete(pid);
|
|
18304
18578
|
}
|
|
18305
18579
|
reaped(pid, parent) {
|
|
@@ -18475,6 +18749,7 @@ var Launcher = class {
|
|
|
18475
18749
|
umask: this.umaskOf(ppid),
|
|
18476
18750
|
cred,
|
|
18477
18751
|
tag: this.tagOf(ppid),
|
|
18752
|
+
links: grant ? grant.cred.euid : this.links.get(ppid),
|
|
18478
18753
|
...group,
|
|
18479
18754
|
...exec
|
|
18480
18755
|
});
|
|
@@ -18536,7 +18811,8 @@ var Launcher = class {
|
|
|
18536
18811
|
blocked: this.blockedBy(ppid),
|
|
18537
18812
|
umask: this.umaskOf(ppid),
|
|
18538
18813
|
cred: this.credOf(ppid),
|
|
18539
|
-
tag: this.tagOf(ppid)
|
|
18814
|
+
tag: this.tagOf(ppid),
|
|
18815
|
+
links: this.links.get(ppid)
|
|
18540
18816
|
})
|
|
18541
18817
|
);
|
|
18542
18818
|
}
|
|
@@ -18716,6 +18992,23 @@ var Launcher = class {
|
|
|
18716
18992
|
}
|
|
18717
18993
|
};
|
|
18718
18994
|
}
|
|
18995
|
+
async revokeIntegrity(path) {
|
|
18996
|
+
if (path !== void 0 && (typeof path !== "string" || !path.startsWith("/"))) {
|
|
18997
|
+
throw new TypeError("integrity.revoke takes an absolute path");
|
|
18998
|
+
}
|
|
18999
|
+
if (!this.integrity) return;
|
|
19000
|
+
const at = path === void 0 ? void 0 : normalizePath(path);
|
|
19001
|
+
const real = at && await this.base.realpath?.(at, true).catch(() => void 0);
|
|
19002
|
+
const roots = [at, real].filter((p) => p !== void 0);
|
|
19003
|
+
this.revocations++;
|
|
19004
|
+
const hit = (key) => key.includes("\0") && (at === void 0 || key.split("\0").slice(0, 2).some((part) => isProtected(roots, part)));
|
|
19005
|
+
for (const cache of [this.compiled, this.texts]) {
|
|
19006
|
+
for (const key of [...cache.keys()]) if (hit(key)) cache.delete(key);
|
|
19007
|
+
}
|
|
19008
|
+
if (at === void 0) this.integrity.forget();
|
|
19009
|
+
for (const root of roots) this.integrity.forget(root);
|
|
19010
|
+
this.resetCatalogs();
|
|
19011
|
+
}
|
|
18719
19012
|
attest(path) {
|
|
18720
19013
|
return attest(this.rootFs, path, {
|
|
18721
19014
|
users: this.usersMode,
|
|
@@ -19537,7 +19830,7 @@ var RemoteTransport = class {
|
|
|
19537
19830
|
finish();
|
|
19538
19831
|
throw e;
|
|
19539
19832
|
}
|
|
19540
|
-
const { status, statusText, headers, url, redirected, redirects } = head;
|
|
19833
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
19541
19834
|
const read = async () => {
|
|
19542
19835
|
if (finished) return void 0;
|
|
19543
19836
|
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
@@ -19554,7 +19847,7 @@ var RemoteTransport = class {
|
|
|
19554
19847
|
this.cancel(nid);
|
|
19555
19848
|
};
|
|
19556
19849
|
return {
|
|
19557
|
-
...
|
|
19850
|
+
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
19558
19851
|
...redirects ? { redirects } : {},
|
|
19559
19852
|
status,
|
|
19560
19853
|
statusText,
|
|
@@ -20437,6 +20730,7 @@ async function createNodeKernel(options = {}) {
|
|
|
20437
20730
|
await launcher.fs.writeFile(path, data);
|
|
20438
20731
|
},
|
|
20439
20732
|
chmod: async (path, mode) => launcher.fs.chmod(path, modeOption(mode)),
|
|
20733
|
+
integrity: { revoke: (path) => guard2(() => launcher.revokeIntegrity(path)) },
|
|
20440
20734
|
readFile: async (path) => launcher.fs.readFileBuffer(path),
|
|
20441
20735
|
mount: (spec) => guard2(() => launcher.mount(spec)),
|
|
20442
20736
|
umount: (target) => guard2(async () => launcher.umount(target)),
|