@ai-ecoverse/slicc-kernel 1.70.0 → 1.71.1
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 +24 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +314 -74
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +6 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +304 -64
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +6 -1
- package/dist/process-worker.js.map +2 -2
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -2490,22 +2490,22 @@ function act(session, req, signal) {
|
|
|
2490
2490
|
}
|
|
2491
2491
|
async function realpath(fs, path) {
|
|
2492
2492
|
let parts2 = fs.resolvePath("/", path).split("/").filter(Boolean);
|
|
2493
|
-
let
|
|
2493
|
+
let resolved2 = "";
|
|
2494
2494
|
for (let hops = 0; parts2.length > 0; ) {
|
|
2495
2495
|
const [name2, ...rest2] = parts2;
|
|
2496
|
-
const next2 = `${
|
|
2496
|
+
const next2 = `${resolved2}/${name2}`;
|
|
2497
2497
|
if (!(await fs.lstat(next2)).isSymbolicLink) {
|
|
2498
|
-
|
|
2498
|
+
resolved2 = next2;
|
|
2499
2499
|
parts2 = rest2;
|
|
2500
2500
|
continue;
|
|
2501
2501
|
}
|
|
2502
2502
|
if (++hops > MAX_LINKS3) throw fsError("ELOOP", path);
|
|
2503
2503
|
const target = await fs.readlink(next2);
|
|
2504
|
-
const base = target.startsWith("/") ? "/" :
|
|
2504
|
+
const base = target.startsWith("/") ? "/" : resolved2 || "/";
|
|
2505
2505
|
parts2 = [...fs.resolvePath(base, target).split("/").filter(Boolean), ...rest2];
|
|
2506
|
-
|
|
2506
|
+
resolved2 = "";
|
|
2507
2507
|
}
|
|
2508
|
-
return
|
|
2508
|
+
return resolved2 || "/";
|
|
2509
2509
|
}
|
|
2510
2510
|
var CLIENT_CHECKS = {
|
|
2511
2511
|
readFile: (g, at) => readable(g, "read", at(0)),
|
|
@@ -2810,7 +2810,7 @@ function serveClient(port, host) {
|
|
|
2810
2810
|
if (!FS_METHODS.includes(req.method)) {
|
|
2811
2811
|
throw new Error(`unknown file system call ${req.method}`);
|
|
2812
2812
|
}
|
|
2813
|
-
return fsCall(l.
|
|
2813
|
+
return fsCall(l.processFs, req.method, req.args, ownerFor(l, self), guardFor(l, self));
|
|
2814
2814
|
case "watch":
|
|
2815
2815
|
case "unwatch":
|
|
2816
2816
|
return watchOp(l, req, watches, send, guardFor(l, self));
|
|
@@ -2997,6 +2997,183 @@ var MemoryMeta = class {
|
|
|
2997
2997
|
}
|
|
2998
2998
|
};
|
|
2999
2999
|
|
|
3000
|
+
// src/fs/protect.ts
|
|
3001
|
+
var PROTECT_WRITER = "slicc-kernel: protect.writer needs the process tag (#405), which this kernel does not have yet";
|
|
3002
|
+
function protectedPrefixes(paths) {
|
|
3003
|
+
return [...new Set(paths.map((p) => normalizePath(p)))];
|
|
3004
|
+
}
|
|
3005
|
+
function within(path, prefix) {
|
|
3006
|
+
return prefix === "/" || path === prefix || path.startsWith(`${prefix}/`);
|
|
3007
|
+
}
|
|
3008
|
+
function isProtected(prefixes2, path) {
|
|
3009
|
+
return prefixes2.some((prefix) => within(path, prefix));
|
|
3010
|
+
}
|
|
3011
|
+
function holdsProtected(prefixes2, path) {
|
|
3012
|
+
return prefixes2.some((prefix) => within(prefix, path));
|
|
3013
|
+
}
|
|
3014
|
+
var MAX_LINKS4 = 40;
|
|
3015
|
+
function partsOf(path) {
|
|
3016
|
+
return path.split("/").filter((p) => p !== "" && p !== ".");
|
|
3017
|
+
}
|
|
3018
|
+
function missing(err) {
|
|
3019
|
+
const code = err?.code;
|
|
3020
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
3021
|
+
}
|
|
3022
|
+
async function resolved(fs, path, follow2) {
|
|
3023
|
+
let done4 = [];
|
|
3024
|
+
let todo = partsOf(path);
|
|
3025
|
+
for (let hops = 0; todo.length > 0; ) {
|
|
3026
|
+
const part = todo.shift();
|
|
3027
|
+
if (part === "..") {
|
|
3028
|
+
done4.pop();
|
|
3029
|
+
continue;
|
|
3030
|
+
}
|
|
3031
|
+
if (todo.length === 0 && !follow2) {
|
|
3032
|
+
done4.push(part);
|
|
3033
|
+
break;
|
|
3034
|
+
}
|
|
3035
|
+
const at = `/${[...done4, part].join("/")}`;
|
|
3036
|
+
const st = await fs.lstat(at).catch((err) => {
|
|
3037
|
+
if (missing(err)) return void 0;
|
|
3038
|
+
throw err;
|
|
3039
|
+
});
|
|
3040
|
+
if (!st) {
|
|
3041
|
+
return normalizePath([...done4, part, ...todo].join("/"));
|
|
3042
|
+
}
|
|
3043
|
+
if (!st.isSymbolicLink) {
|
|
3044
|
+
done4.push(part);
|
|
3045
|
+
continue;
|
|
3046
|
+
}
|
|
3047
|
+
if (++hops > MAX_LINKS4) throw fsError("ELOOP", path);
|
|
3048
|
+
const link2 = await fs.readlink(at);
|
|
3049
|
+
if (link2.startsWith("/")) done4 = [];
|
|
3050
|
+
todo = [...partsOf(link2), ...todo];
|
|
3051
|
+
}
|
|
3052
|
+
return `/${done4.join("/")}`;
|
|
3053
|
+
}
|
|
3054
|
+
var ProtectedFs = class {
|
|
3055
|
+
prefixes;
|
|
3056
|
+
constructor(prefixes2) {
|
|
3057
|
+
this.prefixes = prefixes2;
|
|
3058
|
+
}
|
|
3059
|
+
async check(fs, path, follow2, whole = false) {
|
|
3060
|
+
const lexical2 = normalizePath(path);
|
|
3061
|
+
const real = await resolved(fs, lexical2, follow2);
|
|
3062
|
+
for (const p of /* @__PURE__ */ new Set([lexical2, real])) {
|
|
3063
|
+
if (isProtected(this.prefixes, p) || whole && holdsProtected(this.prefixes, p)) {
|
|
3064
|
+
throw fsError("EROFS", path);
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
view(fs) {
|
|
3069
|
+
const check = (path, follow2, whole = false) => this.check(fs, path, follow2, whole);
|
|
3070
|
+
const marked = (path, st) => !st.readonly && isProtected(this.prefixes, normalizePath(path)) ? { ...st, readonly: true } : st;
|
|
3071
|
+
const own = {
|
|
3072
|
+
async writeFile(...args) {
|
|
3073
|
+
await check(args[0], true);
|
|
3074
|
+
return fs.writeFile(...args);
|
|
3075
|
+
},
|
|
3076
|
+
async mkdir(...args) {
|
|
3077
|
+
await check(args[0], false);
|
|
3078
|
+
return fs.mkdir(...args);
|
|
3079
|
+
},
|
|
3080
|
+
async rm(...args) {
|
|
3081
|
+
await check(args[0], false, true);
|
|
3082
|
+
return fs.rm(...args);
|
|
3083
|
+
},
|
|
3084
|
+
async rename(from, to) {
|
|
3085
|
+
await check(from, false, true);
|
|
3086
|
+
await check(to, false, true);
|
|
3087
|
+
return fs.rename(from, to);
|
|
3088
|
+
},
|
|
3089
|
+
async link(from, to, follow2) {
|
|
3090
|
+
await check(from, follow2 === true);
|
|
3091
|
+
await check(to, false);
|
|
3092
|
+
return fs.link(from, to, follow2);
|
|
3093
|
+
},
|
|
3094
|
+
async symlink(...args) {
|
|
3095
|
+
await check(args[1], false);
|
|
3096
|
+
return fs.symlink(...args);
|
|
3097
|
+
},
|
|
3098
|
+
async chmod(path, mode) {
|
|
3099
|
+
await check(path, true);
|
|
3100
|
+
return fs.chmod(path, mode);
|
|
3101
|
+
},
|
|
3102
|
+
async utimes(path, atime, mtime) {
|
|
3103
|
+
await check(path, true);
|
|
3104
|
+
return fs.utimes(path, atime, mtime);
|
|
3105
|
+
},
|
|
3106
|
+
async stat(path) {
|
|
3107
|
+
return marked(path, await fs.stat(path));
|
|
3108
|
+
},
|
|
3109
|
+
async lstat(path) {
|
|
3110
|
+
return marked(path, await fs.lstat(path));
|
|
3111
|
+
},
|
|
3112
|
+
async readdirStat(path) {
|
|
3113
|
+
const dir = normalizePath(path);
|
|
3114
|
+
return (await fs.readdirStat(path)).map(([name2, st]) => [
|
|
3115
|
+
name2,
|
|
3116
|
+
st && marked(`${dir}/${name2}`, st)
|
|
3117
|
+
]);
|
|
3118
|
+
},
|
|
3119
|
+
...fs.createExclusive ? {
|
|
3120
|
+
async createExclusive(...args) {
|
|
3121
|
+
await check(args[0], true);
|
|
3122
|
+
return fs.createExclusive?.(...args);
|
|
3123
|
+
}
|
|
3124
|
+
} : {},
|
|
3125
|
+
...fs.chown ? {
|
|
3126
|
+
async chown(...args) {
|
|
3127
|
+
await check(args[0], args[1].follow !== false);
|
|
3128
|
+
return fs.chown?.(...args);
|
|
3129
|
+
}
|
|
3130
|
+
} : {},
|
|
3131
|
+
...fs.lutimes ? {
|
|
3132
|
+
async lutimes(path, atime, mtime) {
|
|
3133
|
+
await check(path, false);
|
|
3134
|
+
return fs.lutimes?.(path, atime, mtime);
|
|
3135
|
+
}
|
|
3136
|
+
} : {},
|
|
3137
|
+
...fs.pwrite ? {
|
|
3138
|
+
async pwrite(...args) {
|
|
3139
|
+
await check(args[0], true);
|
|
3140
|
+
return fs.pwrite?.(...args);
|
|
3141
|
+
}
|
|
3142
|
+
} : {},
|
|
3143
|
+
...fs.truncate ? {
|
|
3144
|
+
async truncate(path, size) {
|
|
3145
|
+
await check(path, true);
|
|
3146
|
+
return fs.truncate?.(path, size);
|
|
3147
|
+
}
|
|
3148
|
+
} : {},
|
|
3149
|
+
...fs.exclusive ? {
|
|
3150
|
+
async exclusive(path, run2, follow2) {
|
|
3151
|
+
return fs.exclusive(
|
|
3152
|
+
path,
|
|
3153
|
+
(held) => run2({
|
|
3154
|
+
...held,
|
|
3155
|
+
writeFile: async (...args) => {
|
|
3156
|
+
await check(args[0], true);
|
|
3157
|
+
return held.writeFile(...args);
|
|
3158
|
+
}
|
|
3159
|
+
}),
|
|
3160
|
+
follow2
|
|
3161
|
+
);
|
|
3162
|
+
}
|
|
3163
|
+
} : {}
|
|
3164
|
+
};
|
|
3165
|
+
const view = {};
|
|
3166
|
+
for (let at = fs; at && at !== Object.prototype; at = Object.getPrototypeOf(at)) {
|
|
3167
|
+
for (const name2 of Object.getOwnPropertyNames(at)) {
|
|
3168
|
+
if (name2 === "constructor" || Object.hasOwn(view, name2)) continue;
|
|
3169
|
+
const value = fs[name2];
|
|
3170
|
+
view[name2] = typeof value === "function" ? value.bind(fs) : value;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
return Object.assign(view, own);
|
|
3174
|
+
}
|
|
3175
|
+
};
|
|
3176
|
+
|
|
3000
3177
|
// src/fs/opfs.ts
|
|
3001
3178
|
var S_IFDIR = 16384;
|
|
3002
3179
|
var S_IFREG = 32768;
|
|
@@ -3004,7 +3181,7 @@ var S_IFLNK = 40960;
|
|
|
3004
3181
|
var PERM_MASK = 4095;
|
|
3005
3182
|
var S_ISGID3 = 1024;
|
|
3006
3183
|
var READ_ATTEMPTS = 3;
|
|
3007
|
-
var
|
|
3184
|
+
var MAX_LINKS5 = 40;
|
|
3008
3185
|
var CHECK_MS = 1e3;
|
|
3009
3186
|
var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
|
|
3010
3187
|
var ERRNO_BY_DOM_ERROR = {
|
|
@@ -3041,7 +3218,7 @@ function sidecar(meta) {
|
|
|
3041
3218
|
});
|
|
3042
3219
|
return Object.fromEntries(META_OPS.map((op) => [op, guarded2(op)]));
|
|
3043
3220
|
}
|
|
3044
|
-
function
|
|
3221
|
+
function missing2(err) {
|
|
3045
3222
|
const code = err?.code;
|
|
3046
3223
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
3047
3224
|
}
|
|
@@ -3058,7 +3235,7 @@ function prefixes(path) {
|
|
|
3058
3235
|
const parts2 = split(path);
|
|
3059
3236
|
return parts2.map((_, i) => `/${parts2.slice(0, i + 1).join("/")}`);
|
|
3060
3237
|
}
|
|
3061
|
-
function
|
|
3238
|
+
function within2(path, root) {
|
|
3062
3239
|
return path === root || path.startsWith(`${root}/`);
|
|
3063
3240
|
}
|
|
3064
3241
|
var LOCKED = /* @__PURE__ */ new Set(["NotReadableError", "NoModificationAllowedError", "InvalidStateError"]);
|
|
@@ -3193,14 +3370,25 @@ var OpfsFs = class {
|
|
|
3193
3370
|
const fields = await this.newFields(path, owner, directory);
|
|
3194
3371
|
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
3195
3372
|
}
|
|
3373
|
+
guarded = [];
|
|
3374
|
+
protect(prefixes2) {
|
|
3375
|
+
this.guarded = prefixes2;
|
|
3376
|
+
}
|
|
3377
|
+
refuse(path, holding = false) {
|
|
3378
|
+
if (isProtected(this.guarded, path) || holding && holdsProtected(this.guarded, path)) {
|
|
3379
|
+
throw fsError("EROFS", path);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3196
3382
|
async chown(path, change) {
|
|
3197
3383
|
if (!this.owners) return;
|
|
3198
3384
|
if (change.kind === "new") {
|
|
3199
3385
|
const at = resolvePath((await this.locate(parentOf4(path), true)).path, baseOf(path));
|
|
3386
|
+
this.refuse(at);
|
|
3200
3387
|
const { uid = 0, gid = 0, mode } = change;
|
|
3201
3388
|
return this.stampNew(at, { uid, gid, ...mode !== void 0 ? { mode } : {} }, false);
|
|
3202
3389
|
}
|
|
3203
3390
|
const found = await this.locate(path, change.follow !== false);
|
|
3391
|
+
this.refuse(found.path);
|
|
3204
3392
|
const [stored] = found.link ? [found.link] : await this.meta.get([found.path]);
|
|
3205
3393
|
const current = await this.ownerAt(found.path, stored);
|
|
3206
3394
|
const next2 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
|
|
@@ -3313,11 +3501,11 @@ var OpfsFs = class {
|
|
|
3313
3501
|
}
|
|
3314
3502
|
async locate(path, follow2) {
|
|
3315
3503
|
let current = path;
|
|
3316
|
-
for (let hops = 0; hops <=
|
|
3504
|
+
for (let hops = 0; hops <= MAX_LINKS5; hops++) {
|
|
3317
3505
|
try {
|
|
3318
3506
|
return { path: current, handle: await this.handle(current) };
|
|
3319
3507
|
} catch (err) {
|
|
3320
|
-
if (!
|
|
3508
|
+
if (!missing2(err)) throw err;
|
|
3321
3509
|
const link2 = await this.linkAlong(current);
|
|
3322
3510
|
if (!link2) throw err;
|
|
3323
3511
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
@@ -3339,7 +3527,7 @@ var OpfsFs = class {
|
|
|
3339
3527
|
const st = await this.lstat(at);
|
|
3340
3528
|
if (!st.isSymbolicLink && !st.isDirectory) throw fsError("ENOTDIR", at);
|
|
3341
3529
|
if (!st.isSymbolicLink) done4.push(part);
|
|
3342
|
-
else if (++hops >
|
|
3530
|
+
else if (++hops > MAX_LINKS5) throw fsError("ELOOP", path);
|
|
3343
3531
|
else {
|
|
3344
3532
|
const link2 = await this.readlink(at);
|
|
3345
3533
|
if (link2.startsWith("/")) done4 = [];
|
|
@@ -3436,7 +3624,7 @@ var OpfsFs = class {
|
|
|
3436
3624
|
return this.locate(path, true).then(
|
|
3437
3625
|
() => true,
|
|
3438
3626
|
(err) => {
|
|
3439
|
-
if (
|
|
3627
|
+
if (missing2(err)) return false;
|
|
3440
3628
|
throw err;
|
|
3441
3629
|
}
|
|
3442
3630
|
);
|
|
@@ -3454,8 +3642,10 @@ var OpfsFs = class {
|
|
|
3454
3642
|
}
|
|
3455
3643
|
}
|
|
3456
3644
|
}
|
|
3457
|
-
async existing(path) {
|
|
3458
|
-
const
|
|
3645
|
+
async existing(path, writing = false) {
|
|
3646
|
+
const found = await this.locate(path, true);
|
|
3647
|
+
if (writing) this.refuse(found.path);
|
|
3648
|
+
const handle = found.handle;
|
|
3459
3649
|
if (handle.kind === "directory") throw fsError("EISDIR", path);
|
|
3460
3650
|
return handle;
|
|
3461
3651
|
}
|
|
@@ -3480,7 +3670,7 @@ var OpfsFs = class {
|
|
|
3480
3670
|
await this.retrying(path, () => positioned(handle, (io) => io.write(offset, bytes)), true);
|
|
3481
3671
|
}
|
|
3482
3672
|
async truncate(path, size) {
|
|
3483
|
-
const handle = await this.existing(path);
|
|
3673
|
+
const handle = await this.existing(path, true);
|
|
3484
3674
|
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
3485
3675
|
}
|
|
3486
3676
|
async writeSession(path, truncate) {
|
|
@@ -3506,10 +3696,15 @@ var OpfsFs = class {
|
|
|
3506
3696
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
3507
3697
|
}
|
|
3508
3698
|
async writeTarget(path) {
|
|
3699
|
+
const [target, existed] = await this.locateWrite(path);
|
|
3700
|
+
this.refuse(target);
|
|
3701
|
+
return [target, existed];
|
|
3702
|
+
}
|
|
3703
|
+
async locateWrite(path) {
|
|
3509
3704
|
try {
|
|
3510
3705
|
return [(await this.locate(path, true)).path, true];
|
|
3511
3706
|
} catch (err) {
|
|
3512
|
-
if (!
|
|
3707
|
+
if (!missing2(err)) throw err;
|
|
3513
3708
|
}
|
|
3514
3709
|
const [entry] = await this.meta.get([path]);
|
|
3515
3710
|
const wanted = entry?.link === void 0 ? path : resolvePath(parentOf4(path), entry.link);
|
|
@@ -3578,7 +3773,7 @@ var OpfsFs = class {
|
|
|
3578
3773
|
try {
|
|
3579
3774
|
found = await this.locate(path, true);
|
|
3580
3775
|
} catch (err) {
|
|
3581
|
-
if (!
|
|
3776
|
+
if (!missing2(err)) throw err;
|
|
3582
3777
|
}
|
|
3583
3778
|
if (found) {
|
|
3584
3779
|
const directory = found.handle?.kind === "directory";
|
|
@@ -3599,6 +3794,7 @@ var OpfsFs = class {
|
|
|
3599
3794
|
}
|
|
3600
3795
|
const parent = await this.locate(parentOf4(path), true);
|
|
3601
3796
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
3797
|
+
this.refuse(resolvePath(parent.path, baseOf(path)));
|
|
3602
3798
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
3603
3799
|
const made2 = `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`;
|
|
3604
3800
|
await this.stampNew(made2, owner, true);
|
|
@@ -3613,6 +3809,7 @@ var OpfsFs = class {
|
|
|
3613
3809
|
if (options.force && error.code === "ENOENT") return;
|
|
3614
3810
|
throw error;
|
|
3615
3811
|
}
|
|
3812
|
+
this.refuse(found.path, true);
|
|
3616
3813
|
if (found.handle) {
|
|
3617
3814
|
const [dir, name2] = await this.parent(found.path);
|
|
3618
3815
|
try {
|
|
@@ -3631,19 +3828,28 @@ var OpfsFs = class {
|
|
|
3631
3828
|
links() {
|
|
3632
3829
|
return false;
|
|
3633
3830
|
}
|
|
3634
|
-
async link(from) {
|
|
3831
|
+
async link(from, to, follow2) {
|
|
3832
|
+
await (follow2 ? this.stat(from) : this.lstat(from));
|
|
3833
|
+
if (!(await this.stat(parentOf4(to))).isDirectory) throw fsError("ENOTDIR", to);
|
|
3834
|
+
if (await this.lstat(to).then(
|
|
3835
|
+
() => true,
|
|
3836
|
+
() => false
|
|
3837
|
+
))
|
|
3838
|
+
throw fsError("EEXIST", to);
|
|
3635
3839
|
throw fsError("EPERM", `${from}: this file system has no hard links`);
|
|
3636
3840
|
}
|
|
3637
3841
|
async rename(from, to) {
|
|
3638
3842
|
if (from === to) return;
|
|
3639
3843
|
const source = await this.locate(from, false);
|
|
3844
|
+
this.refuse(source.path, true);
|
|
3640
3845
|
this.forget(source.path);
|
|
3641
3846
|
const parent = await this.locate(parentOf4(to), true);
|
|
3642
3847
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
3848
|
+
this.refuse(destination, true);
|
|
3643
3849
|
const sourceStat = await this.describe(source);
|
|
3644
|
-
if (sourceStat.isDirectory &&
|
|
3850
|
+
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
3645
3851
|
const target = await this.locate(destination, false).catch((err) => {
|
|
3646
|
-
if (
|
|
3852
|
+
if (missing2(err)) return null;
|
|
3647
3853
|
throw err;
|
|
3648
3854
|
});
|
|
3649
3855
|
const targetStat = target && await this.describe(target);
|
|
@@ -3737,9 +3943,10 @@ var OpfsFs = class {
|
|
|
3737
3943
|
const parent = await this.locate(parentOf4(path), true);
|
|
3738
3944
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
3739
3945
|
const at = resolvePath(parent.path, baseOf(path));
|
|
3946
|
+
this.refuse(at);
|
|
3740
3947
|
if (await this.locate(at, false).then(
|
|
3741
3948
|
() => true,
|
|
3742
|
-
(err) => !
|
|
3949
|
+
(err) => !missing2(err)
|
|
3743
3950
|
)) {
|
|
3744
3951
|
throw fsError("EEXIST", path);
|
|
3745
3952
|
}
|
|
@@ -3766,6 +3973,7 @@ var OpfsFs = class {
|
|
|
3766
3973
|
}
|
|
3767
3974
|
async chmod(path, mode) {
|
|
3768
3975
|
const found = await this.locate(path, true);
|
|
3976
|
+
this.refuse(found.path);
|
|
3769
3977
|
const ctimeMs = Date.now();
|
|
3770
3978
|
await this.meta.update(found.path, (entry) => ({
|
|
3771
3979
|
...entry,
|
|
@@ -3781,6 +3989,7 @@ var OpfsFs = class {
|
|
|
3781
3989
|
await this.setTimes(await this.locate(path, false), atime, mtime);
|
|
3782
3990
|
}
|
|
3783
3991
|
async setTimes(found, atime, mtime) {
|
|
3992
|
+
this.refuse(found.path);
|
|
3784
3993
|
const { link: link2 } = found;
|
|
3785
3994
|
if (link2) {
|
|
3786
3995
|
const ctimeMs2 = Date.now();
|
|
@@ -3880,7 +4089,7 @@ function pidOwner(proc) {
|
|
|
3880
4089
|
function webLocks() {
|
|
3881
4090
|
return globalThis.navigator?.locks;
|
|
3882
4091
|
}
|
|
3883
|
-
var
|
|
4092
|
+
var within3 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
3884
4093
|
var parentOf5 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
3885
4094
|
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
3886
4095
|
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
@@ -3980,7 +4189,7 @@ var UnlinkedKeeper = class {
|
|
|
3980
4189
|
for (const holder of this.holders) {
|
|
3981
4190
|
if (holder.owns(target)) continue;
|
|
3982
4191
|
for (const path of holder.held()) {
|
|
3983
|
-
if (!
|
|
4192
|
+
if (!within3(path, target) || holder.isKept(path)) continue;
|
|
3984
4193
|
held.set(path, [...held.get(path) ?? [], holder]);
|
|
3985
4194
|
}
|
|
3986
4195
|
}
|
|
@@ -5068,8 +5277,8 @@ function binfmtOf(binfmts, path) {
|
|
|
5068
5277
|
var S_IFDIR2 = 16384;
|
|
5069
5278
|
var S_IFREG2 = 32768;
|
|
5070
5279
|
var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
5071
|
-
var
|
|
5072
|
-
function
|
|
5280
|
+
var MAX_LINKS6 = 40;
|
|
5281
|
+
function missing3(err) {
|
|
5073
5282
|
return err?.code === "ENOENT";
|
|
5074
5283
|
}
|
|
5075
5284
|
function synthetic(directory, path) {
|
|
@@ -5088,7 +5297,7 @@ function synthetic(directory, path) {
|
|
|
5088
5297
|
}
|
|
5089
5298
|
async function followLinks(fs, path) {
|
|
5090
5299
|
let current = path;
|
|
5091
|
-
for (let hops = 0; hops <
|
|
5300
|
+
for (let hops = 0; hops < MAX_LINKS6; hops++) {
|
|
5092
5301
|
const st = await fs.lstat(current).catch(() => void 0);
|
|
5093
5302
|
if (!st?.isSymbolicLink) return current;
|
|
5094
5303
|
const parent = current.slice(0, current.lastIndexOf("/")) || "/";
|
|
@@ -5135,7 +5344,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5135
5344
|
try {
|
|
5136
5345
|
return await real(path);
|
|
5137
5346
|
} catch (err) {
|
|
5138
|
-
const found =
|
|
5347
|
+
const found = missing3(err) ? await linked(path) : void 0;
|
|
5139
5348
|
if (found) return found;
|
|
5140
5349
|
throw err;
|
|
5141
5350
|
}
|
|
@@ -5147,7 +5356,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5147
5356
|
try {
|
|
5148
5357
|
return await fs.readFileBuffer(path);
|
|
5149
5358
|
} catch (err) {
|
|
5150
|
-
if (
|
|
5359
|
+
if (missing3(err) && (await linked(path))?.isFile) return new Uint8Array(0);
|
|
5151
5360
|
throw err;
|
|
5152
5361
|
}
|
|
5153
5362
|
},
|
|
@@ -5163,7 +5372,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5163
5372
|
const extra = await children2(path);
|
|
5164
5373
|
if (!extra) return fs.readdir(path);
|
|
5165
5374
|
const real = await fs.readdir(path).catch((err) => {
|
|
5166
|
-
if (
|
|
5375
|
+
if (missing3(err)) return [];
|
|
5167
5376
|
throw err;
|
|
5168
5377
|
});
|
|
5169
5378
|
return [.../* @__PURE__ */ new Set([...real, ...extra])].sort();
|
|
@@ -5172,7 +5381,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5172
5381
|
const extra = await children2(path);
|
|
5173
5382
|
if (!extra) return fs.readdirStat(path);
|
|
5174
5383
|
const real = await fs.readdirStat(path).catch((err) => {
|
|
5175
|
-
if (
|
|
5384
|
+
if (missing3(err)) return [];
|
|
5176
5385
|
throw err;
|
|
5177
5386
|
});
|
|
5178
5387
|
const seen = new Set(real.map(([name2]) => name2));
|
|
@@ -5688,7 +5897,7 @@ function checkIds(options) {
|
|
|
5688
5897
|
if (!ID.test(value) || Number(value) > MAX_ID2) throw errnoError("EINVAL", `${key}=${value}`);
|
|
5689
5898
|
}
|
|
5690
5899
|
}
|
|
5691
|
-
var
|
|
5900
|
+
var MAX_LINKS7 = 40;
|
|
5692
5901
|
var STALE_RETRIES = 3;
|
|
5693
5902
|
var SETTLE_ROUNDS = 4;
|
|
5694
5903
|
var DEFAULT_IO = 8 * 1024 * 1024;
|
|
@@ -5698,7 +5907,7 @@ function parseSize(text) {
|
|
|
5698
5907
|
if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
|
|
5699
5908
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
5700
5909
|
}
|
|
5701
|
-
var
|
|
5910
|
+
var within4 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
5702
5911
|
var HeldSet = class extends Set {
|
|
5703
5912
|
idle;
|
|
5704
5913
|
constructor(idle) {
|
|
@@ -5717,7 +5926,7 @@ var HeldSet = class extends Set {
|
|
|
5717
5926
|
}
|
|
5718
5927
|
};
|
|
5719
5928
|
function heldUnder(held, target) {
|
|
5720
|
-
for (const paths of held) for (const path of paths.keys()) if (
|
|
5929
|
+
for (const paths of held) for (const path of paths.keys()) if (within4(path, target)) return true;
|
|
5721
5930
|
return false;
|
|
5722
5931
|
}
|
|
5723
5932
|
var HeldPaths = class extends Map {
|
|
@@ -5828,24 +6037,24 @@ var HeldPaths = class extends Map {
|
|
|
5828
6037
|
return this.owning === path;
|
|
5829
6038
|
}
|
|
5830
6039
|
revoke(prefix) {
|
|
5831
|
-
for (const path of this.keys()) if (
|
|
6040
|
+
for (const path of this.keys()) if (within4(path, prefix)) this.revoked.add(path);
|
|
5832
6041
|
}
|
|
5833
6042
|
renamed(from, to) {
|
|
5834
6043
|
for (const [path, count] of [...this]) {
|
|
5835
|
-
if (!
|
|
6044
|
+
if (!within4(path, from)) continue;
|
|
5836
6045
|
const moved2 = to + path.slice(from.length);
|
|
5837
6046
|
this.delete(path);
|
|
5838
6047
|
this.set(moved2, (this.get(moved2) ?? 0) + count);
|
|
5839
6048
|
if (this.revoked.delete(path)) this.revoked.add(moved2);
|
|
5840
6049
|
}
|
|
5841
6050
|
for (const [path, count] of [...this.opens]) {
|
|
5842
|
-
if (!
|
|
6051
|
+
if (!within4(path, from)) continue;
|
|
5843
6052
|
const moved2 = to + path.slice(from.length);
|
|
5844
6053
|
this.opens.delete(path);
|
|
5845
6054
|
this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count);
|
|
5846
6055
|
}
|
|
5847
6056
|
for (const [id2, key] of this.handles) {
|
|
5848
|
-
if (
|
|
6057
|
+
if (within4(key, from)) this.handles.set(id2, to + key.slice(from.length));
|
|
5849
6058
|
}
|
|
5850
6059
|
}
|
|
5851
6060
|
isRevoked(path) {
|
|
@@ -5952,7 +6161,7 @@ var MountTable = class {
|
|
|
5952
6161
|
locate(path) {
|
|
5953
6162
|
let best;
|
|
5954
6163
|
for (const mount of this.mounts.values()) {
|
|
5955
|
-
if (
|
|
6164
|
+
if (within4(path, mount.target) && (!best || mount.target.length > best.target.length))
|
|
5956
6165
|
best = mount;
|
|
5957
6166
|
}
|
|
5958
6167
|
if (!best) return void 0;
|
|
@@ -6095,7 +6304,7 @@ var MountTable = class {
|
|
|
6095
6304
|
async commitUnder(prefix) {
|
|
6096
6305
|
const at = normalizePath(prefix);
|
|
6097
6306
|
await Promise.all(
|
|
6098
|
-
[...this.sessions.keys()].filter((p) =>
|
|
6307
|
+
[...this.sessions.keys()].filter((p) => within4(p, at)).map((p) => this.commit(p))
|
|
6099
6308
|
);
|
|
6100
6309
|
}
|
|
6101
6310
|
async commitOverlapping(real, offset, length2) {
|
|
@@ -6130,10 +6339,10 @@ var MountTable = class {
|
|
|
6130
6339
|
}
|
|
6131
6340
|
forget(mount, path) {
|
|
6132
6341
|
mount.epoch++;
|
|
6133
|
-
for (const key of [...mount.attrs.keys()]) if (
|
|
6342
|
+
for (const key of [...mount.attrs.keys()]) if (within4(key, path)) mount.attrs.delete(key);
|
|
6134
6343
|
mount.lists.delete(path);
|
|
6135
6344
|
mount.lists.delete(parentOf7(path));
|
|
6136
|
-
for (const key of [...mount.lists.keys()]) if (
|
|
6345
|
+
for (const key of [...mount.lists.keys()]) if (within4(key, path)) mount.lists.delete(key);
|
|
6137
6346
|
}
|
|
6138
6347
|
async getattr(mount, path, rel2, settled = false) {
|
|
6139
6348
|
for (let round = 1; ; round++) {
|
|
@@ -6206,7 +6415,7 @@ var MountFs = class {
|
|
|
6206
6415
|
throw err;
|
|
6207
6416
|
}
|
|
6208
6417
|
if (attr2.kind !== "symlink") return real;
|
|
6209
|
-
if (hops >=
|
|
6418
|
+
if (hops >= MAX_LINKS7) throw errnoError("ELOOP", path);
|
|
6210
6419
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
6211
6420
|
return this.follow(this.base.resolvePath(parentOf7(real), target), hops + 1, create);
|
|
6212
6421
|
}
|
|
@@ -8851,11 +9060,11 @@ function ipv6(host) {
|
|
|
8851
9060
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
8852
9061
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
8853
9062
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
8854
|
-
const
|
|
8855
|
-
if (halves.length === 2 ?
|
|
9063
|
+
const missing4 = 8 - words2.length - tail.length;
|
|
9064
|
+
if (halves.length === 2 ? missing4 < 1 : missing4 !== 0) return void 0;
|
|
8856
9065
|
const all = [
|
|
8857
9066
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
8858
|
-
...new Array(halves.length === 2 ?
|
|
9067
|
+
...new Array(halves.length === 2 ? missing4 : 0).fill(0),
|
|
8859
9068
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
8860
9069
|
...tail
|
|
8861
9070
|
];
|
|
@@ -9699,7 +9908,7 @@ function parsePrefix(text) {
|
|
|
9699
9908
|
if (length2 < 0 || length2 > max) return void 0;
|
|
9700
9909
|
return { ...parsed2, length: length2 };
|
|
9701
9910
|
}
|
|
9702
|
-
function
|
|
9911
|
+
function within5(prefix, addr) {
|
|
9703
9912
|
if (prefix.v6 !== addr.v6) return false;
|
|
9704
9913
|
const shift = BigInt((prefix.v6 ? 128 : 32) - prefix.length);
|
|
9705
9914
|
return addr.bits >> shift === prefix.bits >> shift;
|
|
@@ -9739,9 +9948,9 @@ var Routes = class {
|
|
|
9739
9948
|
if (!addr) return "unreachable";
|
|
9740
9949
|
if (addr.v6 && addr.bits === 1n) return "loopback";
|
|
9741
9950
|
if (!addr.v6 && addr.bits >> 24n === 127n) return "loopback";
|
|
9742
|
-
if (RESERVED.some((p) =>
|
|
9951
|
+
if (RESERVED.some((p) => within5(p, addr))) return "reserved";
|
|
9743
9952
|
if (addr.v6 && !this.ipv6) return "unreachable";
|
|
9744
|
-
if (this.exit || this.table.some((p) =>
|
|
9953
|
+
if (this.exit || this.table.some((p) => within5(p, addr))) return "uplink";
|
|
9745
9954
|
return "unreachable";
|
|
9746
9955
|
}
|
|
9747
9956
|
};
|
|
@@ -10588,7 +10797,7 @@ function isMissing(err) {
|
|
|
10588
10797
|
if (err?.code === "ENOENT") return true;
|
|
10589
10798
|
return err instanceof Error && err.message.startsWith("ENOENT");
|
|
10590
10799
|
}
|
|
10591
|
-
function
|
|
10800
|
+
function within6(path, root) {
|
|
10592
10801
|
return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
|
|
10593
10802
|
}
|
|
10594
10803
|
var VfsNode = class {
|
|
@@ -10909,12 +11118,12 @@ var VfsNodes = class {
|
|
|
10909
11118
|
return node;
|
|
10910
11119
|
}
|
|
10911
11120
|
holds(prefix) {
|
|
10912
|
-
for (const path of this.byPath.keys()) if (
|
|
11121
|
+
for (const path of this.byPath.keys()) if (within6(path, prefix)) return true;
|
|
10913
11122
|
return false;
|
|
10914
11123
|
}
|
|
10915
11124
|
writes(prefix) {
|
|
10916
11125
|
for (const [path, node] of this.byPath)
|
|
10917
|
-
if (node.writers > 0 &&
|
|
11126
|
+
if (node.writers > 0 && within6(path, prefix)) return true;
|
|
10918
11127
|
return false;
|
|
10919
11128
|
}
|
|
10920
11129
|
closed(node, writable2 = false) {
|
|
@@ -10958,11 +11167,11 @@ var VfsNodes = class {
|
|
|
10958
11167
|
this.kept.delete(node);
|
|
10959
11168
|
}
|
|
10960
11169
|
async flush(path) {
|
|
10961
|
-
for (const [p, node] of this.byPath) if (
|
|
11170
|
+
for (const [p, node] of this.byPath) if (within6(p, path)) await node.serial(() => node.flush());
|
|
10962
11171
|
}
|
|
10963
11172
|
async unlinking(path) {
|
|
10964
11173
|
for (const [held, node] of [...this.byPath]) {
|
|
10965
|
-
if (!
|
|
11174
|
+
if (!within6(held, path)) continue;
|
|
10966
11175
|
await node.serial(async () => {
|
|
10967
11176
|
await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
|
|
10968
11177
|
});
|
|
@@ -10970,14 +11179,14 @@ var VfsNodes = class {
|
|
|
10970
11179
|
}
|
|
10971
11180
|
revoke(prefix) {
|
|
10972
11181
|
for (const [path, node] of [...this.byPath]) {
|
|
10973
|
-
if (!
|
|
11182
|
+
if (!within6(path, prefix)) continue;
|
|
10974
11183
|
node.revoke();
|
|
10975
11184
|
this.forget(node);
|
|
10976
11185
|
}
|
|
10977
11186
|
}
|
|
10978
11187
|
unlinked(path) {
|
|
10979
11188
|
for (const [held, node] of [...this.byPath]) {
|
|
10980
|
-
if (!
|
|
11189
|
+
if (!within6(held, path) || this.byPath.get(held) !== node) continue;
|
|
10981
11190
|
if (!this.dropName(held, node)) this.orphan(node);
|
|
10982
11191
|
}
|
|
10983
11192
|
}
|
|
@@ -10985,8 +11194,8 @@ var VfsNodes = class {
|
|
|
10985
11194
|
if (from === to) return;
|
|
10986
11195
|
const moved2 = [];
|
|
10987
11196
|
for (const [p, node] of [...this.byPath]) {
|
|
10988
|
-
if (
|
|
10989
|
-
else if (
|
|
11197
|
+
if (within6(p, from)) moved2.push([p, node]);
|
|
11198
|
+
else if (within6(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
|
|
10990
11199
|
this.orphan(node);
|
|
10991
11200
|
}
|
|
10992
11201
|
}
|
|
@@ -11532,6 +11741,7 @@ var WasmProcess = class {
|
|
|
11532
11741
|
this.fds.installAt(fd, await this.procFile(req, path));
|
|
11533
11742
|
return fd;
|
|
11534
11743
|
}
|
|
11744
|
+
if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
|
|
11535
11745
|
const open = { ...req, path };
|
|
11536
11746
|
if (req.exclusive) {
|
|
11537
11747
|
await nodes.createExclusive(path, this.newOwner());
|
|
@@ -11577,6 +11787,9 @@ var WasmProcess = class {
|
|
|
11577
11787
|
};
|
|
11578
11788
|
return fs.exclusive ? fs.exclusive(first.path, look) : look();
|
|
11579
11789
|
}
|
|
11790
|
+
writesAt(req) {
|
|
11791
|
+
return (req.flags & WRITE_ACCESS) !== 0 || req.truncate === true || req.create === true || req.exclusive === true;
|
|
11792
|
+
}
|
|
11580
11793
|
async mayOpen(req) {
|
|
11581
11794
|
const { guard: guard2 } = this.options;
|
|
11582
11795
|
const inherited2 = req.orphan || req.contents !== void 0 || req.handle !== void 0;
|
|
@@ -12358,6 +12571,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
12358
12571
|
...inherited(opts),
|
|
12359
12572
|
...opts.owners ? { owners: true } : {},
|
|
12360
12573
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
12574
|
+
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
12361
12575
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
12362
12576
|
...opts.identity ? { identity: opts.identity } : {},
|
|
12363
12577
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
@@ -15187,13 +15401,13 @@ function interpreter(head) {
|
|
|
15187
15401
|
function expandDefaults(defaults, env) {
|
|
15188
15402
|
const out = {};
|
|
15189
15403
|
for (const [key, value] of Object.entries(defaults ?? {})) {
|
|
15190
|
-
let
|
|
15404
|
+
let missing4 = false;
|
|
15191
15405
|
const expanded = value.replace(ENV_REFERENCE, (_, name2) => {
|
|
15192
15406
|
const set2 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
15193
|
-
if (set2 === void 0)
|
|
15407
|
+
if (set2 === void 0) missing4 = true;
|
|
15194
15408
|
return set2 ?? "";
|
|
15195
15409
|
});
|
|
15196
|
-
if (!
|
|
15410
|
+
if (!missing4) out[key] = expanded;
|
|
15197
15411
|
}
|
|
15198
15412
|
return out;
|
|
15199
15413
|
}
|
|
@@ -15240,6 +15454,8 @@ function concat5(chunks2) {
|
|
|
15240
15454
|
}
|
|
15241
15455
|
var Launcher = class {
|
|
15242
15456
|
fs;
|
|
15457
|
+
processFs;
|
|
15458
|
+
prefixes;
|
|
15243
15459
|
base;
|
|
15244
15460
|
createWorker;
|
|
15245
15461
|
modulesDir;
|
|
@@ -15366,6 +15582,10 @@ var Launcher = class {
|
|
|
15366
15582
|
}
|
|
15367
15583
|
);
|
|
15368
15584
|
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
15585
|
+
if (options.protect?.writer) throw new Error(PROTECT_WRITER);
|
|
15586
|
+
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
15587
|
+
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
15588
|
+
options.fs.protect?.(this.prefixes);
|
|
15369
15589
|
this.users = new UserDb(this.fs, this.owners);
|
|
15370
15590
|
this.sudoer = new Sudo({
|
|
15371
15591
|
fs: this.fs,
|
|
@@ -15716,7 +15936,8 @@ var Launcher = class {
|
|
|
15716
15936
|
env: req.env,
|
|
15717
15937
|
cwd: req.cwd,
|
|
15718
15938
|
fds: req.fds,
|
|
15719
|
-
fs: this.
|
|
15939
|
+
fs: this.processFs,
|
|
15940
|
+
...this.prefixes.length > 0 ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
15720
15941
|
createWorker: this.createWorker,
|
|
15721
15942
|
onError: req.report,
|
|
15722
15943
|
spawner: this.spawner(pid, req.report),
|
|
@@ -16001,6 +16222,18 @@ var Launcher = class {
|
|
|
16001
16222
|
const keyed = () => this.jobs.fromKeyboard(send);
|
|
16002
16223
|
this.settling.deliver(sig, pgid, keyed, tty.reading ? void 0 : foreground);
|
|
16003
16224
|
}
|
|
16225
|
+
async resolvePrefixes() {
|
|
16226
|
+
for (const prefix of [...this.prefixes]) {
|
|
16227
|
+
const real = await this.base.realpath?.(prefix, true).catch(() => void 0);
|
|
16228
|
+
if (real !== void 0 && !this.prefixes.includes(real)) this.prefixes.push(real);
|
|
16229
|
+
}
|
|
16230
|
+
}
|
|
16231
|
+
guardMount(target) {
|
|
16232
|
+
const at = normalizePath(target);
|
|
16233
|
+
if (isProtected(this.prefixes, at) || holdsProtected(this.prefixes, at)) {
|
|
16234
|
+
throw fsError("EROFS", at);
|
|
16235
|
+
}
|
|
16236
|
+
}
|
|
16004
16237
|
umaskOf(pid) {
|
|
16005
16238
|
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
16006
16239
|
}
|
|
@@ -16135,6 +16368,7 @@ var Launcher = class {
|
|
|
16135
16368
|
};
|
|
16136
16369
|
}
|
|
16137
16370
|
async mount(spec) {
|
|
16371
|
+
this.guardMount(spec.target);
|
|
16138
16372
|
const fsa = spec.type === "fsa" && !spec.source.startsWith("fsa:");
|
|
16139
16373
|
const entry = await this.mounts.mount(
|
|
16140
16374
|
fsa ? { ...spec, source: `fsa:${crypto.randomUUID()}` } : spec,
|
|
@@ -16153,6 +16387,7 @@ var Launcher = class {
|
|
|
16153
16387
|
[`/${UNLINKED_DIR}`, 448]
|
|
16154
16388
|
];
|
|
16155
16389
|
for (const [path, mode] of layout) {
|
|
16390
|
+
if (isProtected(this.prefixes, normalizePath(path))) continue;
|
|
16156
16391
|
const real = await this.realLayoutPath(path);
|
|
16157
16392
|
const fresh2 = real !== void 0 && !await this.base.hasOwner?.(real);
|
|
16158
16393
|
if (fresh2) await this.base.chown?.(real, { uid: 0, gid: 0, mode, follow: false });
|
|
@@ -16215,6 +16450,7 @@ var Launcher = class {
|
|
|
16215
16450
|
}
|
|
16216
16451
|
async processMount(pid, call, signal) {
|
|
16217
16452
|
const spec = mountCall(call);
|
|
16453
|
+
this.guardMount(spec.target);
|
|
16218
16454
|
await this.permit({ op: "mount", pid, ...spec, options: { ...spec.options } });
|
|
16219
16455
|
await this.mountsOwn(
|
|
16220
16456
|
this.credOf(pid),
|
|
@@ -16231,6 +16467,7 @@ var Launcher = class {
|
|
|
16231
16467
|
}
|
|
16232
16468
|
async umountAs(cred, target) {
|
|
16233
16469
|
const at = normalizePath(target);
|
|
16470
|
+
this.guardMount(at);
|
|
16234
16471
|
await this.mountsOwn(cred, at, async () => Number(this.mounts.mounted(at)?.options.uid));
|
|
16235
16472
|
this.umount(at);
|
|
16236
16473
|
}
|
|
@@ -16244,6 +16481,7 @@ var Launcher = class {
|
|
|
16244
16481
|
async processUmount(pid, target, flags2) {
|
|
16245
16482
|
const call = umountCall(target, flags2);
|
|
16246
16483
|
let mounted;
|
|
16484
|
+
this.guardMount(call.target);
|
|
16247
16485
|
for (; ; ) {
|
|
16248
16486
|
mounted = this.mounts.mounted(call.target);
|
|
16249
16487
|
await this.permit({
|
|
@@ -16258,6 +16496,7 @@ var Launcher = class {
|
|
|
16258
16496
|
this.umount(call.target, call.detach);
|
|
16259
16497
|
}
|
|
16260
16498
|
async prepare() {
|
|
16499
|
+
await this.resolvePrefixes();
|
|
16261
16500
|
for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
|
|
16262
16501
|
if (this.owners) await this.base.chmod("/tmp", 1023);
|
|
16263
16502
|
await this.provisionPnpmHome();
|
|
@@ -16314,7 +16553,7 @@ var Launcher = class {
|
|
|
16314
16553
|
const start2 = dir ?? "/";
|
|
16315
16554
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
16316
16555
|
const [file = ""] = argv;
|
|
16317
|
-
await this.base.mkdir(cwd, { recursive: true });
|
|
16556
|
+
if (!await this.base.exists(cwd)) await this.processFs.mkdir(cwd, { recursive: true });
|
|
16318
16557
|
const planned = await this.plan(file, argv, cwd, scope);
|
|
16319
16558
|
await this.mayExec(credOf(account), { file, cwd, pid: 0 }, planned);
|
|
16320
16559
|
return { cwd, file, planned };
|
|
@@ -17554,6 +17793,7 @@ async function createNodeKernel(options = {}) {
|
|
|
17554
17793
|
...options.hostname !== void 0 ? { hostname: options.hostname } : {},
|
|
17555
17794
|
...options.users !== void 0 ? { users: options.users } : {},
|
|
17556
17795
|
...options.onDenial ? { onDenial: options.onDenial } : {},
|
|
17796
|
+
...options.protect ? { protect: options.protect } : {},
|
|
17557
17797
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
17558
17798
|
...options.approve ? { approve: options.approve } : {}
|
|
17559
17799
|
});
|