@ai-ecoverse/slicc-kernel 1.58.1 → 1.59.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 +19 -11
- package/dist/driver-worker.js +30 -11
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js +30 -11
- package/dist/driver.js.map +2 -2
- package/dist/index.js +25 -7
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +271 -111
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js +30 -11
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +87 -13
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +367 -133
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +85 -11
- package/dist/process-worker.js.map +3 -3
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -1323,6 +1323,11 @@ function blockedReason(url, e) {
|
|
|
1323
1323
|
}
|
|
1324
1324
|
return `${url}: ${e instanceof Error ? e.message : String(e)}`;
|
|
1325
1325
|
}
|
|
1326
|
+
function unopened(url, code) {
|
|
1327
|
+
return Object.assign(new Error(`${url}: the WebSocket closed (${code}) before it opened`), {
|
|
1328
|
+
status: 502
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1326
1331
|
function openWebSocket(Socket, request, withHeaders) {
|
|
1327
1332
|
const { url, protocols, signal } = request;
|
|
1328
1333
|
signal.throwIfAborted();
|
|
@@ -1336,13 +1341,22 @@ function openWebSocket(Socket, request, withHeaders) {
|
|
|
1336
1341
|
const queue = new MessageQueue(() => socket.close(1e3, "too many waiting messages"));
|
|
1337
1342
|
return new Promise((resolve, reject) => {
|
|
1338
1343
|
let open = false;
|
|
1344
|
+
let settled = false;
|
|
1345
|
+
const fail3 = (error) => {
|
|
1346
|
+
if (settled) return;
|
|
1347
|
+
settled = true;
|
|
1348
|
+
signal.removeEventListener("abort", abort);
|
|
1349
|
+
reject(error);
|
|
1350
|
+
};
|
|
1339
1351
|
const abort = () => {
|
|
1340
1352
|
socket.close(1e3, "aborted");
|
|
1341
|
-
|
|
1353
|
+
fail3(signal.reason);
|
|
1342
1354
|
};
|
|
1343
1355
|
signal.addEventListener("abort", abort, { once: true });
|
|
1344
1356
|
socket.addEventListener("open", () => {
|
|
1357
|
+
if (settled) return;
|
|
1345
1358
|
open = true;
|
|
1359
|
+
settled = true;
|
|
1346
1360
|
signal.removeEventListener("abort", abort);
|
|
1347
1361
|
resolve({
|
|
1348
1362
|
protocol: socket.protocol,
|
|
@@ -1358,15 +1372,19 @@ function openWebSocket(Socket, request, withHeaders) {
|
|
|
1358
1372
|
socket.addEventListener("message", (event) => {
|
|
1359
1373
|
queue.push(typeof event.data === "string" ? event.data : new Uint8Array(event.data));
|
|
1360
1374
|
});
|
|
1375
|
+
socket.addEventListener("error", () => {
|
|
1376
|
+
if (open || settled) return;
|
|
1377
|
+
try {
|
|
1378
|
+
socket.close();
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
queue.end({ code: 1006, reason: "" });
|
|
1382
|
+
fail3(unopened(url, 1006));
|
|
1383
|
+
});
|
|
1361
1384
|
socket.addEventListener("close", (event) => {
|
|
1362
1385
|
queue.end({ code: event.code, reason: event.reason });
|
|
1363
1386
|
if (open) return;
|
|
1364
|
-
|
|
1365
|
-
reject(
|
|
1366
|
-
Object.assign(new Error(`${url}: the WebSocket closed (${event.code}) before it opened`), {
|
|
1367
|
-
status: 502
|
|
1368
|
-
})
|
|
1369
|
-
);
|
|
1387
|
+
fail3(unopened(url, event.code));
|
|
1370
1388
|
});
|
|
1371
1389
|
});
|
|
1372
1390
|
}
|
|
@@ -1774,12 +1792,22 @@ var UserDb = class {
|
|
|
1774
1792
|
async stampHome(row, shared) {
|
|
1775
1793
|
const home = this.fs.resolvePath("/", row.home);
|
|
1776
1794
|
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
1777
|
-
if (await this.
|
|
1778
|
-
if (!(await this.fs.lstat(home)).isDirectory) return;
|
|
1795
|
+
if (!await this.realDir(home)) return;
|
|
1779
1796
|
const gid = shared?.gid ?? row.gid;
|
|
1780
1797
|
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
1781
|
-
const
|
|
1782
|
-
await this.fs.chmod(home,
|
|
1798
|
+
const scoop = row.name.startsWith("scoop-");
|
|
1799
|
+
await this.fs.chmod(home, shared ? 1512 : scoop ? 488 : 448);
|
|
1800
|
+
const pnpm = `${home}/.local/share/pnpm`;
|
|
1801
|
+
if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
|
|
1802
|
+
}
|
|
1803
|
+
async realDir(path) {
|
|
1804
|
+
const parts = path.split("/").filter(Boolean);
|
|
1805
|
+
for (let n = 1; n <= parts.length; n++) {
|
|
1806
|
+
const at = `/${parts.slice(0, n).join("/")}`;
|
|
1807
|
+
const st = await this.fs.lstat(at).catch(() => void 0);
|
|
1808
|
+
if (!st?.isDirectory) return false;
|
|
1809
|
+
}
|
|
1810
|
+
return true;
|
|
1783
1811
|
}
|
|
1784
1812
|
async read(path, fallback) {
|
|
1785
1813
|
try {
|
|
@@ -1796,15 +1824,17 @@ var UserDb = class {
|
|
|
1796
1824
|
};
|
|
1797
1825
|
}
|
|
1798
1826
|
async provision(row) {
|
|
1827
|
+
const owner = this.owners ? { uid: row.uid, gid: row.gid } : void 0;
|
|
1828
|
+
const made2 = owner ? { recursive: true, owner } : { recursive: true };
|
|
1799
1829
|
const pnpm = `${row.home}/.local/share/pnpm`;
|
|
1800
1830
|
if (!await this.fs.exists(pnpm)) {
|
|
1801
|
-
await this.fs.mkdir(pnpm,
|
|
1831
|
+
await this.fs.mkdir(pnpm, made2);
|
|
1802
1832
|
await this.fs.chmod(pnpm, row.name.startsWith("scoop-") ? 488 : 448);
|
|
1803
1833
|
}
|
|
1804
1834
|
const config = `${row.home}/.config/pnpm/config.yaml`;
|
|
1805
1835
|
if (!await this.fs.exists(config)) {
|
|
1806
|
-
await this.fs.mkdir(`${row.home}/.config/pnpm`,
|
|
1807
|
-
await this.fs.writeFile(config, PNPM_CONFIG);
|
|
1836
|
+
await this.fs.mkdir(`${row.home}/.config/pnpm`, made2);
|
|
1837
|
+
await this.fs.writeFile(config, PNPM_CONFIG, owner);
|
|
1808
1838
|
}
|
|
1809
1839
|
}
|
|
1810
1840
|
async commit(passwd, group, then) {
|
|
@@ -2008,7 +2038,7 @@ async function fsCall(fs, method, args, owner) {
|
|
|
2008
2038
|
return { result: bytes, transfer: [bytes.buffer] };
|
|
2009
2039
|
}
|
|
2010
2040
|
case "writeFile":
|
|
2011
|
-
await fs.writeFile(path(0), args[1], owner);
|
|
2041
|
+
await fs.writeFile(path(0), args[1], created(owner, 438));
|
|
2012
2042
|
return { result: true };
|
|
2013
2043
|
case "stat":
|
|
2014
2044
|
return { result: await fs.stat(path(0)) };
|
|
@@ -2017,7 +2047,10 @@ async function fsCall(fs, method, args, owner) {
|
|
|
2017
2047
|
case "readdir":
|
|
2018
2048
|
return { result: await fs.readdir(path(0)) };
|
|
2019
2049
|
case "mkdir":
|
|
2020
|
-
await fs.mkdir(
|
|
2050
|
+
await fs.mkdir(
|
|
2051
|
+
path(0),
|
|
2052
|
+
owner ? { recursive: true, owner: made(owner) } : { recursive: true }
|
|
2053
|
+
);
|
|
2021
2054
|
return { result: true };
|
|
2022
2055
|
case "rm":
|
|
2023
2056
|
await fs.rm(path(0), { recursive: true, force: args[1] === true });
|
|
@@ -2028,7 +2061,7 @@ async function fsCall(fs, method, args, owner) {
|
|
|
2028
2061
|
case "realpath":
|
|
2029
2062
|
return { result: await realpath(fs, String(args[0])) };
|
|
2030
2063
|
case "symlink":
|
|
2031
|
-
await fs.symlink(String(args[0]), path(1), owner);
|
|
2064
|
+
await fs.symlink(String(args[0]), path(1), owner && { uid: owner.uid, gid: owner.gid });
|
|
2032
2065
|
return { result: true };
|
|
2033
2066
|
case "readlink":
|
|
2034
2067
|
return { result: await fs.readlink(path(0)) };
|
|
@@ -2050,8 +2083,16 @@ function dialFor(l, req, open) {
|
|
|
2050
2083
|
);
|
|
2051
2084
|
return { result: port2, transfer: [port2] };
|
|
2052
2085
|
}
|
|
2086
|
+
function created(owner, mode) {
|
|
2087
|
+
return owner && { uid: owner.uid, gid: owner.gid, mode: mode & ~owner.umask };
|
|
2088
|
+
}
|
|
2089
|
+
function made(owner) {
|
|
2090
|
+
const mode = 511 & ~owner.umask;
|
|
2091
|
+
return { uid: owner.uid, gid: owner.gid, mode, parents: mode | 192 };
|
|
2092
|
+
}
|
|
2053
2093
|
function ownerFor(l, self) {
|
|
2054
|
-
|
|
2094
|
+
if (!l.owners || !self) return void 0;
|
|
2095
|
+
return { uid: self.uid, gid: self.gid, umask: self.umask ?? 18 };
|
|
2055
2096
|
}
|
|
2056
2097
|
async function accountOf(l, user) {
|
|
2057
2098
|
const found = await l.users.lookup(user);
|
|
@@ -2925,12 +2966,12 @@ var OpfsFs = class {
|
|
|
2925
2966
|
const base = dir === "/" ? "" : dir;
|
|
2926
2967
|
const metas = await this.meta.get(children2.map(([name2]) => `${base}/${name2}`));
|
|
2927
2968
|
const handed2 = this.owners ? await this.handedTo(dir) : void 0;
|
|
2928
|
-
const
|
|
2969
|
+
const owned3 = (stat, entry) => handed2 ? { ...stat, ...ownOf(entry) ?? handed2 } : stat;
|
|
2929
2970
|
return Promise.all(
|
|
2930
2971
|
children2.map(async ([name2, child], i) => {
|
|
2931
|
-
if (!isHandle(child)) return [name2,
|
|
2972
|
+
if (!isHandle(child)) return [name2, owned3(this.linkStat(child), child)];
|
|
2932
2973
|
const stat = await this.statOf(`${base}/${name2}`, child, metas[i]).catch(() => null);
|
|
2933
|
-
return [name2, stat &&
|
|
2974
|
+
return [name2, stat && owned3(stat, metas[i])];
|
|
2934
2975
|
})
|
|
2935
2976
|
);
|
|
2936
2977
|
}
|
|
@@ -2961,9 +3002,9 @@ var OpfsFs = class {
|
|
|
2961
3002
|
const parent = await this.locate(parentOf2(path), true);
|
|
2962
3003
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
2963
3004
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
2964
|
-
const
|
|
2965
|
-
await this.stampNew(
|
|
2966
|
-
this.touch(parent.path,
|
|
3005
|
+
const made2 = `${parent.path === "/" ? "" : parent.path}/${baseOf(path)}`;
|
|
3006
|
+
await this.stampNew(made2, owner, true);
|
|
3007
|
+
this.touch(parent.path, made2);
|
|
2967
3008
|
}
|
|
2968
3009
|
async rm(path, options = {}) {
|
|
2969
3010
|
let found;
|
|
@@ -4408,7 +4449,17 @@ async function followLinks(fs, path) {
|
|
|
4408
4449
|
}
|
|
4409
4450
|
return current;
|
|
4410
4451
|
}
|
|
4411
|
-
function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
4452
|
+
function withCommandDirs(fs, names, userDir = async () => void 0, owners = false) {
|
|
4453
|
+
async function nearest(path) {
|
|
4454
|
+
const st = await fs.stat(path).catch(() => void 0);
|
|
4455
|
+
if (st || path === "/") return st ?? {};
|
|
4456
|
+
return nearest(path.slice(0, path.lastIndexOf("/")) || "/");
|
|
4457
|
+
}
|
|
4458
|
+
async function owned3(stat2, dir) {
|
|
4459
|
+
if (!owners) return stat2;
|
|
4460
|
+
const { uid = 0, gid = 0 } = dir === void 0 ? {} : await nearest(dir);
|
|
4461
|
+
return { ...stat2, uid, gid };
|
|
4462
|
+
}
|
|
4412
4463
|
async function children2(path) {
|
|
4413
4464
|
if (path === "/") return ["bin", "usr"];
|
|
4414
4465
|
if (path === "/usr") return ["bin"];
|
|
@@ -4417,13 +4468,18 @@ function withCommandDirs(fs, names, userDir = async () => void 0) {
|
|
|
4417
4468
|
return own?.size ? [...own] : void 0;
|
|
4418
4469
|
}
|
|
4419
4470
|
async function virtual(path) {
|
|
4420
|
-
if (path === "/usr" || path === "/bin" || path === "/usr/bin")
|
|
4471
|
+
if (path === "/usr" || path === "/bin" || path === "/usr/bin") {
|
|
4472
|
+
return owned3(synthetic(true, path));
|
|
4473
|
+
}
|
|
4421
4474
|
const name2 = COMMAND.exec(path)?.[1];
|
|
4422
|
-
if (name2 !== void 0)
|
|
4423
|
-
|
|
4475
|
+
if (name2 !== void 0) {
|
|
4476
|
+
return (await names()).has(name2) ? owned3(synthetic(false, path)) : void 0;
|
|
4477
|
+
}
|
|
4478
|
+
if ((await userDir(path))?.size) return owned3(synthetic(true, path), path);
|
|
4424
4479
|
const slash = path.lastIndexOf("/");
|
|
4425
|
-
const
|
|
4426
|
-
|
|
4480
|
+
const dir = path.slice(0, slash);
|
|
4481
|
+
const own = await userDir(dir);
|
|
4482
|
+
return own?.has(path.slice(slash + 1)) ? owned3(synthetic(false, path), dir) : void 0;
|
|
4427
4483
|
}
|
|
4428
4484
|
async function linked(path) {
|
|
4429
4485
|
return await virtual(path) ?? virtual(await followLinks(fs, path));
|
|
@@ -4599,18 +4655,18 @@ var FsWatchers = class {
|
|
|
4599
4655
|
const overrides = {
|
|
4600
4656
|
writeFile: after(fs.writeFile.bind(fs), (path) => [path]),
|
|
4601
4657
|
mkdir: async (path, options) => {
|
|
4602
|
-
const
|
|
4658
|
+
const created3 = [];
|
|
4603
4659
|
if (options?.recursive) {
|
|
4604
4660
|
const parts = normalizePath(path).split("/").filter(Boolean);
|
|
4605
4661
|
for (let at = 1; at < parts.length; at++) {
|
|
4606
4662
|
const ancestor = `/${parts.slice(0, at).join("/")}`;
|
|
4607
|
-
if (
|
|
4663
|
+
if (created3.length > 0 || !await fs.exists(ancestor)) created3.push(ancestor);
|
|
4608
4664
|
}
|
|
4609
4665
|
}
|
|
4610
4666
|
try {
|
|
4611
4667
|
await fs.mkdir(path, options);
|
|
4612
4668
|
} finally {
|
|
4613
|
-
this.changed(...
|
|
4669
|
+
this.changed(...created3, path);
|
|
4614
4670
|
}
|
|
4615
4671
|
},
|
|
4616
4672
|
rm: after(fs.rm.bind(fs), (path) => [path]),
|
|
@@ -4889,7 +4945,7 @@ async function realTarget(fs, path) {
|
|
|
4889
4945
|
}
|
|
4890
4946
|
|
|
4891
4947
|
// src/mount/protocol.ts
|
|
4892
|
-
var DRIVER_PROTOCOL = [1,
|
|
4948
|
+
var DRIVER_PROTOCOL = [1, 2];
|
|
4893
4949
|
function driverVersionError(theirs) {
|
|
4894
4950
|
const major = Array.isArray(theirs) ? theirs[0] : void 0;
|
|
4895
4951
|
if (major === DRIVER_PROTOCOL[0]) return void 0;
|
|
@@ -4991,6 +5047,19 @@ var DriverConnection = class _DriverConnection {
|
|
|
4991
5047
|
};
|
|
4992
5048
|
|
|
4993
5049
|
// src/mount/mount-fs.ts
|
|
5050
|
+
var S_ISGID3 = 1024;
|
|
5051
|
+
var ID = /^\d{1,10}$/;
|
|
5052
|
+
var MAX_ID2 = 4294967294;
|
|
5053
|
+
function idOption(value) {
|
|
5054
|
+
return value === void 0 ? 0 : Number(value);
|
|
5055
|
+
}
|
|
5056
|
+
function checkIds(options) {
|
|
5057
|
+
for (const key of ["uid", "gid"]) {
|
|
5058
|
+
const value = options[key];
|
|
5059
|
+
if (value === void 0) continue;
|
|
5060
|
+
if (!ID.test(value) || Number(value) > MAX_ID2) throw errnoError("EINVAL", `${key}=${value}`);
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
4994
5063
|
var MAX_LINKS5 = 40;
|
|
4995
5064
|
var STALE_RETRIES = 3;
|
|
4996
5065
|
var SETTLE_ROUNDS = 4;
|
|
@@ -5157,31 +5226,35 @@ var HeldPaths = class extends Map {
|
|
|
5157
5226
|
};
|
|
5158
5227
|
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
5159
5228
|
var readonly = (mount) => mount.caps.readonly === true || mount.options.ro !== void 0;
|
|
5160
|
-
function inodeless(mount,
|
|
5161
|
-
if (
|
|
5229
|
+
function inodeless(mount, attr2) {
|
|
5230
|
+
if (attr2.ino !== void 0) return false;
|
|
5162
5231
|
if (mount.caps.links) mount.caps = { ...mount.caps, links: false };
|
|
5163
5232
|
return true;
|
|
5164
5233
|
}
|
|
5165
|
-
function statOf(
|
|
5166
|
-
const mtime = new Date(
|
|
5167
|
-
const fallback =
|
|
5234
|
+
function statOf(attr2, path, mount) {
|
|
5235
|
+
const mtime = new Date(attr2.mtime);
|
|
5236
|
+
const fallback = attr2.kind === "directory" ? 16877 : attr2.kind === "symlink" ? 41471 : 33188;
|
|
5168
5237
|
return {
|
|
5169
|
-
isFile:
|
|
5170
|
-
isDirectory:
|
|
5171
|
-
isSymbolicLink:
|
|
5172
|
-
size:
|
|
5173
|
-
mode:
|
|
5238
|
+
isFile: attr2.kind === "file",
|
|
5239
|
+
isDirectory: attr2.kind === "directory",
|
|
5240
|
+
isSymbolicLink: attr2.kind === "symlink",
|
|
5241
|
+
size: attr2.size,
|
|
5242
|
+
mode: attr2.mode ?? fallback,
|
|
5174
5243
|
mtime,
|
|
5175
5244
|
atime: mtime,
|
|
5176
5245
|
ctime: mtime,
|
|
5177
|
-
ino:
|
|
5178
|
-
...!inodeless(mount,
|
|
5246
|
+
ino: attr2.ino ?? inodeOf(path),
|
|
5247
|
+
...!inodeless(mount, attr2) && attr2.nlink !== void 0 ? { nlink: attr2.nlink } : {},
|
|
5179
5248
|
dev: mount.dev,
|
|
5180
5249
|
...readonly(mount) ? { readonly: true } : {},
|
|
5181
5250
|
...mount.maxFile > 0 ? { maxFile: mount.maxFile } : {},
|
|
5182
5251
|
...mount.caps.ranges ? { ranged: true } : {},
|
|
5183
5252
|
...mount.caps.links ? { linkable: true } : {},
|
|
5184
|
-
...
|
|
5253
|
+
...attr2.etag !== void 0 ? { version: attr2.etag } : {},
|
|
5254
|
+
...mount.owners ? {
|
|
5255
|
+
uid: (mount.caps.owners ? attr2.uid : void 0) ?? idOption(mount.options.uid),
|
|
5256
|
+
gid: (mount.caps.owners ? attr2.gid : void 0) ?? idOption(mount.options.gid)
|
|
5257
|
+
} : {}
|
|
5185
5258
|
};
|
|
5186
5259
|
}
|
|
5187
5260
|
function concat3(chunks2, total) {
|
|
@@ -5274,6 +5347,7 @@ var MountTable = class {
|
|
|
5274
5347
|
const st = await fs.stat(target);
|
|
5275
5348
|
if (!st.isDirectory) throw errnoError("ENOTDIR", target);
|
|
5276
5349
|
const options = { ...spec.options };
|
|
5350
|
+
if (this.deps.owners) checkIds(options);
|
|
5277
5351
|
const maxFile = options.maxfile !== void 0 ? parseSize(options.maxfile) : void 0;
|
|
5278
5352
|
const opened2 = await this.deps.open(spec.type, { ...spec, target, options });
|
|
5279
5353
|
let mounted;
|
|
@@ -5319,6 +5393,7 @@ var MountTable = class {
|
|
|
5319
5393
|
attrs: /* @__PURE__ */ new Map(),
|
|
5320
5394
|
lists: /* @__PURE__ */ new Map(),
|
|
5321
5395
|
epoch: 0,
|
|
5396
|
+
owners: this.deps.owners === true,
|
|
5322
5397
|
dispose: () => opened2.dispose(),
|
|
5323
5398
|
...opened2.present ? { present: opened2.present } : {}
|
|
5324
5399
|
};
|
|
@@ -5440,15 +5515,15 @@ var MountTable = class {
|
|
|
5440
5515
|
if (cached && cached.expires > Date.now()) return cached.value;
|
|
5441
5516
|
const seen = mount.epoch;
|
|
5442
5517
|
const session = this.sessions.get(path);
|
|
5443
|
-
const
|
|
5518
|
+
const attr2 = await mount.conn.call({ op: "getattr", path: rel2 });
|
|
5444
5519
|
if (mount.epoch !== seen) {
|
|
5445
5520
|
const moved2 = this.sessions.get(path) !== session || this.committing.has(path);
|
|
5446
5521
|
if (settled && moved2 && round < SETTLE_ROUNDS) continue;
|
|
5447
|
-
return
|
|
5522
|
+
return attr2;
|
|
5448
5523
|
}
|
|
5449
5524
|
const ttl = mount.caps.attrTtl ?? 1e3;
|
|
5450
|
-
if (ttl > 0) mount.attrs.set(path, { value:
|
|
5451
|
-
return
|
|
5525
|
+
if (ttl > 0) mount.attrs.set(path, { value: attr2, expires: Date.now() + ttl });
|
|
5526
|
+
return attr2;
|
|
5452
5527
|
}
|
|
5453
5528
|
}
|
|
5454
5529
|
async readdir(mount, path, rel2) {
|
|
@@ -5495,28 +5570,43 @@ var MountFs = class {
|
|
|
5495
5570
|
const found = this.at(path);
|
|
5496
5571
|
if (!found) return path;
|
|
5497
5572
|
const real = normalizePath(path);
|
|
5498
|
-
let
|
|
5573
|
+
let attr2;
|
|
5499
5574
|
try {
|
|
5500
|
-
|
|
5575
|
+
attr2 = await this.table.getattr(found.mount, real, found.rel);
|
|
5501
5576
|
} catch (err) {
|
|
5502
5577
|
if (create && err.code === "ENOENT") return real;
|
|
5503
5578
|
throw err;
|
|
5504
5579
|
}
|
|
5505
|
-
if (
|
|
5580
|
+
if (attr2.kind !== "symlink") return real;
|
|
5506
5581
|
if (hops >= MAX_LINKS5) throw errnoError("ELOOP", path);
|
|
5507
5582
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
5508
5583
|
return this.follow(this.base.resolvePath(parentOf6(real), target), hops + 1, create);
|
|
5509
5584
|
}
|
|
5510
|
-
async open(mount, rel2, write) {
|
|
5585
|
+
async open(mount, rel2, write, owner) {
|
|
5511
5586
|
return await mount.conn.call({
|
|
5512
5587
|
op: "open",
|
|
5513
5588
|
path: rel2,
|
|
5514
5589
|
write,
|
|
5515
5590
|
create: write,
|
|
5516
5591
|
truncate: write,
|
|
5517
|
-
exclusive: false
|
|
5592
|
+
exclusive: false,
|
|
5593
|
+
...owner
|
|
5518
5594
|
});
|
|
5519
5595
|
}
|
|
5596
|
+
async driverOwner(found, real, owner, directory) {
|
|
5597
|
+
const { mount, rel: rel2 } = found;
|
|
5598
|
+
if (!owner || !mount.owners || !mount.caps.owners) return void 0;
|
|
5599
|
+
const dir = parentOf6(real);
|
|
5600
|
+
const above = statOf(await this.table.getattr(mount, dir, parentOf6(rel2)), dir, mount);
|
|
5601
|
+
const setgid = (above.mode & S_ISGID3) !== 0;
|
|
5602
|
+
let mode = owner.mode;
|
|
5603
|
+
if (directory && setgid) mode = (mode ?? 493) | S_ISGID3;
|
|
5604
|
+
return {
|
|
5605
|
+
uid: owner.uid,
|
|
5606
|
+
gid: setgid ? above.gid : owner.gid,
|
|
5607
|
+
...mode !== void 0 ? { mode } : {}
|
|
5608
|
+
};
|
|
5609
|
+
}
|
|
5520
5610
|
resolvePath(base, path) {
|
|
5521
5611
|
return this.base.resolvePath(base, path);
|
|
5522
5612
|
}
|
|
@@ -5538,9 +5628,9 @@ var MountFs = class {
|
|
|
5538
5628
|
}
|
|
5539
5629
|
async readWhole(mount, real, rel2) {
|
|
5540
5630
|
await this.table.commit(real);
|
|
5541
|
-
const
|
|
5542
|
-
if (
|
|
5543
|
-
if (mount.maxFile > 0 &&
|
|
5631
|
+
const attr2 = await this.table.getattr(mount, real, rel2);
|
|
5632
|
+
if (attr2.kind === "directory") throw errnoError("EISDIR", real);
|
|
5633
|
+
if (mount.maxFile > 0 && attr2.size > mount.maxFile) {
|
|
5544
5634
|
throw errnoError("EFBIG", `${real} is larger than this mount's maxfile (${mount.maxFile})`);
|
|
5545
5635
|
}
|
|
5546
5636
|
const fh = await this.open(mount, rel2, false);
|
|
@@ -5558,7 +5648,7 @@ var MountFs = class {
|
|
|
5558
5648
|
if (bytes.length === 0) break;
|
|
5559
5649
|
chunks2.push(bytes);
|
|
5560
5650
|
total += bytes.length;
|
|
5561
|
-
if (bytes.length < chunk2 && total >=
|
|
5651
|
+
if (bytes.length < chunk2 && total >= attr2.size) break;
|
|
5562
5652
|
}
|
|
5563
5653
|
} finally {
|
|
5564
5654
|
await mount.conn.call({ op: "release", fh });
|
|
@@ -5578,18 +5668,19 @@ var MountFs = class {
|
|
|
5578
5668
|
`${real} would be larger than this mount's maxfile (${mount.maxFile})`
|
|
5579
5669
|
);
|
|
5580
5670
|
}
|
|
5671
|
+
const made2 = await this.driverOwner(found, real, owner, false);
|
|
5581
5672
|
for (let attempt = 1; ; attempt++) {
|
|
5582
5673
|
try {
|
|
5583
|
-
return await this.writeWhole(mount, real, rel2, bytes);
|
|
5674
|
+
return await this.writeWhole(mount, real, rel2, bytes, made2);
|
|
5584
5675
|
} catch (err) {
|
|
5585
5676
|
if (err.code !== "ESTALE" || attempt >= STALE_RETRIES) throw err;
|
|
5586
5677
|
}
|
|
5587
5678
|
}
|
|
5588
5679
|
}
|
|
5589
|
-
async writeWhole(mount, real, rel2, bytes) {
|
|
5680
|
+
async writeWhole(mount, real, rel2, bytes, owner) {
|
|
5590
5681
|
await this.table.commit(real);
|
|
5591
5682
|
this.table.forget(mount, real);
|
|
5592
|
-
const fh = await this.open(mount, rel2, true);
|
|
5683
|
+
const fh = await this.open(mount, rel2, true, owner);
|
|
5593
5684
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5594
5685
|
try {
|
|
5595
5686
|
for (let offset = 0; offset < bytes.length; offset += chunk2) {
|
|
@@ -5735,9 +5826,9 @@ var MountFs = class {
|
|
|
5735
5826
|
found.mount
|
|
5736
5827
|
);
|
|
5737
5828
|
}
|
|
5738
|
-
statWriting(
|
|
5829
|
+
statWriting(attr2, real, mount) {
|
|
5739
5830
|
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
5740
|
-
return statOf({ ...
|
|
5831
|
+
return statOf({ ...attr2, size: Math.max(attr2.size, ...ends) }, real, mount);
|
|
5741
5832
|
}
|
|
5742
5833
|
async stat(path) {
|
|
5743
5834
|
const real = await this.follow(path);
|
|
@@ -5776,10 +5867,12 @@ var MountFs = class {
|
|
|
5776
5867
|
const { mount, rel: rel2 } = found;
|
|
5777
5868
|
const real = normalizePath(path);
|
|
5778
5869
|
this.writable(mount, real);
|
|
5870
|
+
const { owner } = options;
|
|
5779
5871
|
if (!options.recursive) {
|
|
5780
5872
|
if (rel2 === "/") throw errnoError("EEXIST", real);
|
|
5873
|
+
const made2 = await this.driverOwner(found, real, owner, true);
|
|
5781
5874
|
this.table.forget(mount, real);
|
|
5782
|
-
await mount.conn.call({ op: "mkdir", path: rel2 });
|
|
5875
|
+
await mount.conn.call({ op: "mkdir", path: rel2, ...made2 });
|
|
5783
5876
|
return;
|
|
5784
5877
|
}
|
|
5785
5878
|
const parts = rel2.split("/").filter(Boolean);
|
|
@@ -5789,8 +5882,10 @@ var MountFs = class {
|
|
|
5789
5882
|
const exists = await this.table.getattr(mount, full, sub).catch(() => void 0);
|
|
5790
5883
|
if (exists?.kind === "directory") continue;
|
|
5791
5884
|
if (exists) throw errnoError("ENOTDIR", full);
|
|
5885
|
+
const own = n === parts.length ? owner : owner && { ...owner, mode: owner.parents };
|
|
5886
|
+
const made2 = await this.driverOwner({ mount, rel: sub }, full, own, true);
|
|
5792
5887
|
this.table.forget(mount, full);
|
|
5793
|
-
await mount.conn.call({ op: "mkdir", path: sub });
|
|
5888
|
+
await mount.conn.call({ op: "mkdir", path: sub, ...made2 });
|
|
5794
5889
|
}
|
|
5795
5890
|
}
|
|
5796
5891
|
async rm(path, options = {}) {
|
|
@@ -5801,21 +5896,21 @@ var MountFs = class {
|
|
|
5801
5896
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
5802
5897
|
this.writable(mount, real);
|
|
5803
5898
|
await this.table.commitUnder(real);
|
|
5804
|
-
let
|
|
5899
|
+
let attr2;
|
|
5805
5900
|
try {
|
|
5806
|
-
|
|
5901
|
+
attr2 = await this.table.getattr(mount, real, rel2);
|
|
5807
5902
|
} catch (err) {
|
|
5808
5903
|
if (options.force && err.code === "ENOENT") return;
|
|
5809
5904
|
throw err;
|
|
5810
5905
|
}
|
|
5811
5906
|
this.table.forget(mount, real);
|
|
5812
|
-
if (
|
|
5907
|
+
if (attr2.kind === "directory" && options.recursive) {
|
|
5813
5908
|
for (const entry of await this.table.readdir(mount, real, rel2)) {
|
|
5814
5909
|
await this.rm(`${real}/${entry.name}`, { recursive: true, force: options.force ?? false });
|
|
5815
5910
|
}
|
|
5816
5911
|
this.table.forget(mount, real);
|
|
5817
5912
|
}
|
|
5818
|
-
await mount.conn.call({ op:
|
|
5913
|
+
await mount.conn.call({ op: attr2.kind === "directory" ? "rmdir" : "unlink", path: rel2 });
|
|
5819
5914
|
this.table.forget(mount, real);
|
|
5820
5915
|
}
|
|
5821
5916
|
async rename(from, to) {
|
|
@@ -5869,8 +5964,10 @@ var MountFs = class {
|
|
|
5869
5964
|
this.writable(found.mount, normalizePath(path));
|
|
5870
5965
|
if (!found.mount.caps.symlinks)
|
|
5871
5966
|
throw errnoError("EPERM", `${path}: this file system has no symlinks`);
|
|
5967
|
+
const link2 = owner && { uid: owner.uid, gid: owner.gid };
|
|
5968
|
+
const made2 = await this.driverOwner(found, normalizePath(path), link2, false);
|
|
5872
5969
|
this.table.forget(found.mount, normalizePath(path));
|
|
5873
|
-
await found.mount.conn.call({ op: "symlink", target, path: found.rel });
|
|
5970
|
+
await found.mount.conn.call({ op: "symlink", target, path: found.rel, ...made2 });
|
|
5874
5971
|
}
|
|
5875
5972
|
async realpath(path, follow2) {
|
|
5876
5973
|
if (this.at(path) || !this.base.realpath) throw errnoError("ENOSYS", path);
|
|
@@ -5885,13 +5982,29 @@ var MountFs = class {
|
|
|
5885
5982
|
}
|
|
5886
5983
|
async chown(path, change) {
|
|
5887
5984
|
const real = change.follow === false || change.kind === "new" ? path : await this.follow(path);
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
throw errnoError("EPERM", `${path}: this file system keeps no owners`);
|
|
5891
|
-
}
|
|
5985
|
+
const found = this.at(real);
|
|
5986
|
+
if (found) return this.chownMounted(found, normalizePath(real), change);
|
|
5892
5987
|
if (!this.base.chown) throw errnoError("EPERM", path);
|
|
5893
5988
|
return this.base.chown(real, change);
|
|
5894
5989
|
}
|
|
5990
|
+
async chownMounted(found, real, change) {
|
|
5991
|
+
const { mount, rel: rel2 } = found;
|
|
5992
|
+
if (!mount.owners || !mount.caps.owners) {
|
|
5993
|
+
if (change.kind === "new") return;
|
|
5994
|
+
throw errnoError("EPERM", `${real}: this file system keeps no owners`);
|
|
5995
|
+
}
|
|
5996
|
+
this.writable(mount, real);
|
|
5997
|
+
const { uid, gid, mode } = change;
|
|
5998
|
+
const fresh = change.kind === "new" && { uid, gid, mode };
|
|
5999
|
+
const set2 = fresh ? await this.driverOwner(found, real, fresh, false) : change;
|
|
6000
|
+
this.table.forget(mount, real);
|
|
6001
|
+
const attrs = Object.entries({ uid: set2.uid, gid: set2.gid, mode: set2.mode });
|
|
6002
|
+
await mount.conn.call({
|
|
6003
|
+
op: "setattr",
|
|
6004
|
+
path: rel2,
|
|
6005
|
+
...Object.fromEntries(attrs.filter(([, value]) => value !== void 0))
|
|
6006
|
+
});
|
|
6007
|
+
}
|
|
5895
6008
|
async chmod(path, mode) {
|
|
5896
6009
|
const found = this.at(path);
|
|
5897
6010
|
if (!found) return this.base.chmod(path, mode);
|
|
@@ -5998,7 +6111,10 @@ function mkdirOptions(entry, mode = 511) {
|
|
|
5998
6111
|
}
|
|
5999
6112
|
async function chown(entry, path, req) {
|
|
6000
6113
|
const cred = entry.cred?.();
|
|
6001
|
-
if (!cred)
|
|
6114
|
+
if (!cred) {
|
|
6115
|
+
await (req.op === "chown" ? entry.fs.stat(path) : entry.fs.lstat(path));
|
|
6116
|
+
return done;
|
|
6117
|
+
}
|
|
6002
6118
|
await chownAs(entry.fs, cred, path, {
|
|
6003
6119
|
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
6004
6120
|
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
@@ -8301,7 +8417,7 @@ function enableNetwork(net, options) {
|
|
|
8301
8417
|
let proxy;
|
|
8302
8418
|
const transport = options.transport ?? missingTransport();
|
|
8303
8419
|
net.activate({ family: "inet", host: "127.0.0.1", port: REALM_PROXY_PORT }, () => {
|
|
8304
|
-
const
|
|
8420
|
+
const tls2 = new TlsTerminator({
|
|
8305
8421
|
ca: options.ca,
|
|
8306
8422
|
engine: options.engine,
|
|
8307
8423
|
...options.now ? { now: options.now } : {}
|
|
@@ -8309,7 +8425,7 @@ function enableNetwork(net, options) {
|
|
|
8309
8425
|
const started = new RealmProxy({
|
|
8310
8426
|
net,
|
|
8311
8427
|
transport,
|
|
8312
|
-
tunnel:
|
|
8428
|
+
tunnel: tls2.handler,
|
|
8313
8429
|
tunnelReady: async () => {
|
|
8314
8430
|
await options.engine();
|
|
8315
8431
|
}
|
|
@@ -8317,7 +8433,7 @@ function enableNetwork(net, options) {
|
|
|
8317
8433
|
proxy = started;
|
|
8318
8434
|
void started.closed.then(async () => {
|
|
8319
8435
|
if (proxy === started) proxy = void 0;
|
|
8320
|
-
await
|
|
8436
|
+
await tls2.close();
|
|
8321
8437
|
});
|
|
8322
8438
|
});
|
|
8323
8439
|
return () => proxy;
|
|
@@ -8336,6 +8452,11 @@ var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
|
8336
8452
|
function message(e) {
|
|
8337
8453
|
return e instanceof Error ? e.message : String(e);
|
|
8338
8454
|
}
|
|
8455
|
+
var ERRNO = /^E[A-Z]+$|^EAI_[A-Z]+$/;
|
|
8456
|
+
function errnoOf(e) {
|
|
8457
|
+
const code = e?.code;
|
|
8458
|
+
return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
|
|
8459
|
+
}
|
|
8339
8460
|
function fail(errno, text) {
|
|
8340
8461
|
return { ok: false, errno, message: text };
|
|
8341
8462
|
}
|
|
@@ -8379,13 +8500,13 @@ var WsHandles = class {
|
|
|
8379
8500
|
let socket;
|
|
8380
8501
|
try {
|
|
8381
8502
|
socket = await transport.websocket({
|
|
8382
|
-
url: req.url,
|
|
8503
|
+
url: toHostLoopback(req.url),
|
|
8383
8504
|
protocols: req.protocols,
|
|
8384
8505
|
headers: req.headers,
|
|
8385
8506
|
signal: entry.abort.signal
|
|
8386
8507
|
});
|
|
8387
8508
|
} catch (e) {
|
|
8388
|
-
return fail(
|
|
8509
|
+
return fail(errnoOf(e), message(e));
|
|
8389
8510
|
}
|
|
8390
8511
|
if (!this.open.has(handle)) {
|
|
8391
8512
|
socket.close(1001, "the program went away");
|
|
@@ -8740,14 +8861,14 @@ var Resolver = class {
|
|
|
8740
8861
|
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
8741
8862
|
const signal = blocking?.();
|
|
8742
8863
|
if (signal?.aborted) throw new KernelError("EINTR");
|
|
8743
|
-
let
|
|
8744
|
-
if (!
|
|
8864
|
+
let lookup2 = this.pending.get(id2);
|
|
8865
|
+
if (!lookup2) {
|
|
8745
8866
|
const abort = new AbortController();
|
|
8746
|
-
|
|
8747
|
-
this.pending.set(id2,
|
|
8748
|
-
void
|
|
8867
|
+
lookup2 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
|
|
8868
|
+
this.pending.set(id2, lookup2);
|
|
8869
|
+
void lookup2.work.then(() => this.pending.delete(id2));
|
|
8749
8870
|
}
|
|
8750
|
-
return waitFor(
|
|
8871
|
+
return waitFor(lookup2, signal);
|
|
8751
8872
|
}
|
|
8752
8873
|
async lookup(name2, family, id2, abandoned) {
|
|
8753
8874
|
const uplink = this.uplink;
|
|
@@ -8788,17 +8909,17 @@ var Resolver = class {
|
|
|
8788
8909
|
}
|
|
8789
8910
|
}
|
|
8790
8911
|
};
|
|
8791
|
-
function waitFor(
|
|
8792
|
-
|
|
8912
|
+
function waitFor(lookup2, signal) {
|
|
8913
|
+
lookup2.waiters++;
|
|
8793
8914
|
return new Promise((resolve, reject) => {
|
|
8794
8915
|
const abort = () => {
|
|
8795
|
-
if (--
|
|
8916
|
+
if (--lookup2.waiters === 0) lookup2.abort.abort(new KernelError("EINTR"));
|
|
8796
8917
|
reject(new KernelError("EINTR"));
|
|
8797
8918
|
};
|
|
8798
8919
|
signal?.addEventListener("abort", abort, { once: true });
|
|
8799
|
-
void
|
|
8920
|
+
void lookup2.work.then((value) => {
|
|
8800
8921
|
if (signal?.aborted) return;
|
|
8801
|
-
|
|
8922
|
+
lookup2.waiters--;
|
|
8802
8923
|
signal?.removeEventListener("abort", abort);
|
|
8803
8924
|
resolve(value);
|
|
8804
8925
|
});
|
|
@@ -11170,6 +11291,7 @@ function spawnWasmProcess(opts) {
|
|
|
11170
11291
|
cwd: opts.cwd,
|
|
11171
11292
|
sab: tsab,
|
|
11172
11293
|
cred: copyCred(process2.cred),
|
|
11294
|
+
owners: opts.owners === true,
|
|
11173
11295
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
11174
11296
|
thread
|
|
11175
11297
|
};
|
|
@@ -11563,6 +11685,17 @@ var SettlingChildren = class {
|
|
|
11563
11685
|
};
|
|
11564
11686
|
|
|
11565
11687
|
// src/mount/driver.ts
|
|
11688
|
+
function ownerOf2(req) {
|
|
11689
|
+
const owner = {
|
|
11690
|
+
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
11691
|
+
...req.gid !== void 0 ? { gid: req.gid } : {},
|
|
11692
|
+
...req.mode !== void 0 ? { mode: req.mode } : {}
|
|
11693
|
+
};
|
|
11694
|
+
return Object.keys(owner).length > 0 ? owner : void 0;
|
|
11695
|
+
}
|
|
11696
|
+
function withOwner(base, owner) {
|
|
11697
|
+
return owner ? { ...base, owner } : base;
|
|
11698
|
+
}
|
|
11566
11699
|
function fsError2(code, message3 = code) {
|
|
11567
11700
|
return Object.assign(new Error(message3), { code });
|
|
11568
11701
|
}
|
|
@@ -11573,13 +11706,19 @@ async function dispatch(h, req) {
|
|
|
11573
11706
|
case "readdir":
|
|
11574
11707
|
return h.readdir(req.path);
|
|
11575
11708
|
case "open":
|
|
11576
|
-
return h.open(
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11709
|
+
return h.open(
|
|
11710
|
+
req.path,
|
|
11711
|
+
withOwner(
|
|
11712
|
+
{
|
|
11713
|
+
write: req.write,
|
|
11714
|
+
create: req.create,
|
|
11715
|
+
truncate: req.truncate,
|
|
11716
|
+
exclusive: req.exclusive,
|
|
11717
|
+
...req.ifMatch !== void 0 ? { ifMatch: req.ifMatch } : {}
|
|
11718
|
+
},
|
|
11719
|
+
ownerOf2(req)
|
|
11720
|
+
)
|
|
11721
|
+
);
|
|
11583
11722
|
case "read":
|
|
11584
11723
|
return h.read(req.fh, req.offset, req.size);
|
|
11585
11724
|
case "write":
|
|
@@ -11587,7 +11726,7 @@ async function dispatch(h, req) {
|
|
|
11587
11726
|
case "release":
|
|
11588
11727
|
return h.release(req.fh);
|
|
11589
11728
|
case "mkdir":
|
|
11590
|
-
return h.mkdir(req.path);
|
|
11729
|
+
return ownerOf2(req) ? h.mkdir(req.path, ownerOf2(req)) : h.mkdir(req.path);
|
|
11591
11730
|
case "rmdir":
|
|
11592
11731
|
return h.rmdir(req.path);
|
|
11593
11732
|
case "unlink":
|
|
@@ -11599,7 +11738,7 @@ async function dispatch(h, req) {
|
|
|
11599
11738
|
return h.link(req.from, req.to);
|
|
11600
11739
|
case "symlink":
|
|
11601
11740
|
if (!h.symlink) throw fsError2("EPERM", "this file system has no symlinks");
|
|
11602
|
-
return h.symlink(req.target, req.path);
|
|
11741
|
+
return ownerOf2(req) ? h.symlink(req.target, req.path, ownerOf2(req)) : h.symlink(req.target, req.path);
|
|
11603
11742
|
case "readlink":
|
|
11604
11743
|
if (!h.readlink) throw fsError2("EINVAL", `${req.path} is not a symlink`);
|
|
11605
11744
|
return h.readlink(req.path);
|
|
@@ -11607,7 +11746,9 @@ async function dispatch(h, req) {
|
|
|
11607
11746
|
return h.setattr?.(req.path, {
|
|
11608
11747
|
...req.mode !== void 0 ? { mode: req.mode } : {},
|
|
11609
11748
|
...req.mtime !== void 0 ? { mtime: req.mtime } : {},
|
|
11610
|
-
...req.size !== void 0 ? { size: req.size } : {}
|
|
11749
|
+
...req.size !== void 0 ? { size: req.size } : {},
|
|
11750
|
+
...req.uid !== void 0 ? { uid: req.uid } : {},
|
|
11751
|
+
...req.gid !== void 0 ? { gid: req.gid } : {}
|
|
11611
11752
|
});
|
|
11612
11753
|
case "statfs":
|
|
11613
11754
|
return h.statfs?.() ?? null;
|
|
@@ -11758,8 +11899,8 @@ function kernelFsHandlers(fs) {
|
|
|
11758
11899
|
getattr: async (path) => attrOf(await fs.lstat(path)),
|
|
11759
11900
|
readdir: async (path) => (await fs.readdirStat(path)).flatMap(([name2, st]) => {
|
|
11760
11901
|
if (!st) return [];
|
|
11761
|
-
const
|
|
11762
|
-
return [{ name: name2, kind:
|
|
11902
|
+
const attr2 = attrOf(st);
|
|
11903
|
+
return [{ name: name2, kind: attr2.kind, attr: attr2 }];
|
|
11763
11904
|
}),
|
|
11764
11905
|
async open(path, flags) {
|
|
11765
11906
|
const st = await existing(path);
|
|
@@ -12189,7 +12330,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
12189
12330
|
"list",
|
|
12190
12331
|
{ path: rel(path) }
|
|
12191
12332
|
);
|
|
12192
|
-
return entries.map(({ name: name2, attr }) => ({ name: name2, kind:
|
|
12333
|
+
return entries.map(({ name: name2, attr: attr2 }) => ({ name: name2, kind: attr2.kind, attr: attr2 }));
|
|
12193
12334
|
},
|
|
12194
12335
|
async open(path, flags) {
|
|
12195
12336
|
const client = current();
|
|
@@ -12782,8 +12923,8 @@ var ChunkedBytes = class {
|
|
|
12782
12923
|
}
|
|
12783
12924
|
return out;
|
|
12784
12925
|
}
|
|
12785
|
-
write(offset, bytes,
|
|
12786
|
-
const whole =
|
|
12926
|
+
write(offset, bytes, owned3 = false) {
|
|
12927
|
+
const whole = owned3 && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength;
|
|
12787
12928
|
for (let done4 = 0; done4 < bytes.length; ) {
|
|
12788
12929
|
const at = offset + done4;
|
|
12789
12930
|
const index = Math.floor(at / CHUNK3);
|
|
@@ -12816,18 +12957,42 @@ var ChunkedBytes = class {
|
|
|
12816
12957
|
};
|
|
12817
12958
|
|
|
12818
12959
|
// src/mount/tmpfs.ts
|
|
12819
|
-
function
|
|
12820
|
-
|
|
12821
|
-
|
|
12960
|
+
function idOption2(value) {
|
|
12961
|
+
return value !== void 0 && /^\d+$/.test(value) ? Number(value) : 0;
|
|
12962
|
+
}
|
|
12963
|
+
function created2(ino, kind, mode, from, owner) {
|
|
12964
|
+
return {
|
|
12822
12965
|
kind,
|
|
12823
|
-
ino
|
|
12824
|
-
mode,
|
|
12966
|
+
ino,
|
|
12967
|
+
mode: owner?.mode === void 0 ? mode : mode & ~4095 | owner.mode & 4095,
|
|
12825
12968
|
mtime: Date.now(),
|
|
12826
12969
|
data: new ChunkedBytes(),
|
|
12827
12970
|
target: "",
|
|
12828
12971
|
children: /* @__PURE__ */ new Map(),
|
|
12829
|
-
links: 1
|
|
12830
|
-
|
|
12972
|
+
links: 1,
|
|
12973
|
+
uid: owner?.uid ?? from?.uid ?? 0,
|
|
12974
|
+
gid: owner?.gid ?? from?.gid ?? 0
|
|
12975
|
+
};
|
|
12976
|
+
}
|
|
12977
|
+
function owned2(node, change) {
|
|
12978
|
+
if (change.uid !== void 0) node.uid = change.uid;
|
|
12979
|
+
if (change.gid !== void 0) node.gid = change.gid;
|
|
12980
|
+
}
|
|
12981
|
+
function attr(node) {
|
|
12982
|
+
return {
|
|
12983
|
+
kind: node.kind,
|
|
12984
|
+
size: node.kind === "file" ? node.data.size : node.kind === "symlink" ? node.target.length : 4096,
|
|
12985
|
+
mtime: node.mtime,
|
|
12986
|
+
mode: node.mode,
|
|
12987
|
+
ino: node.ino,
|
|
12988
|
+
...node.kind === "directory" ? {} : { nlink: node.links },
|
|
12989
|
+
uid: node.uid,
|
|
12990
|
+
gid: node.gid
|
|
12991
|
+
};
|
|
12992
|
+
}
|
|
12993
|
+
function tmpfs() {
|
|
12994
|
+
let inodes = 0;
|
|
12995
|
+
const make = (kind, mode, from, owner) => created2(++inodes, kind, mode, from, owner);
|
|
12831
12996
|
const root = make("directory", 16877);
|
|
12832
12997
|
const handles = /* @__PURE__ */ new Map();
|
|
12833
12998
|
let nextFh = 0;
|
|
@@ -12854,14 +13019,6 @@ function tmpfs() {
|
|
|
12854
13019
|
if (dir.kind !== "directory") throw fsError2("ENOTDIR", path);
|
|
12855
13020
|
return { dir, name: name2 };
|
|
12856
13021
|
}
|
|
12857
|
-
const attr = (node) => ({
|
|
12858
|
-
kind: node.kind,
|
|
12859
|
-
size: node.kind === "file" ? node.data.size : node.kind === "symlink" ? node.target.length : 4096,
|
|
12860
|
-
mtime: node.mtime,
|
|
12861
|
-
mode: node.mode,
|
|
12862
|
-
ino: node.ino,
|
|
12863
|
-
...node.kind === "directory" ? {} : { nlink: node.links }
|
|
12864
|
-
});
|
|
12865
13022
|
const handle = (fh) => {
|
|
12866
13023
|
const found = handles.get(fh);
|
|
12867
13024
|
if (!found) throw fsError2("EBADF", `handle ${fh}`);
|
|
@@ -12874,11 +13031,16 @@ function tmpfs() {
|
|
|
12874
13031
|
if (existing?.kind === "directory" && flags.write) throw fsError2("EISDIR", path);
|
|
12875
13032
|
if (existing) return existing;
|
|
12876
13033
|
if (!flags.create) throw fsError2("ENOENT", path);
|
|
12877
|
-
const node = make("file", 33188);
|
|
13034
|
+
const node = make("file", 33188, dir, flags.owner);
|
|
12878
13035
|
place(dir, name2, node);
|
|
12879
13036
|
return node;
|
|
12880
13037
|
}
|
|
12881
13038
|
return {
|
|
13039
|
+
mount(info) {
|
|
13040
|
+
root.uid = idOption2(info.options.uid);
|
|
13041
|
+
root.gid = idOption2(info.options.gid);
|
|
13042
|
+
return void 0;
|
|
13043
|
+
},
|
|
12882
13044
|
async getattr(path) {
|
|
12883
13045
|
return attr(find(path));
|
|
12884
13046
|
},
|
|
@@ -12911,10 +13073,10 @@ function tmpfs() {
|
|
|
12911
13073
|
handle(fh);
|
|
12912
13074
|
handles.delete(fh);
|
|
12913
13075
|
},
|
|
12914
|
-
async mkdir(path) {
|
|
13076
|
+
async mkdir(path, owner) {
|
|
12915
13077
|
const { dir, name: name2 } = parent(path);
|
|
12916
13078
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
12917
|
-
place(dir, name2, make("directory", 16877));
|
|
13079
|
+
place(dir, name2, make("directory", 16877, dir, owner));
|
|
12918
13080
|
},
|
|
12919
13081
|
async rmdir(path) {
|
|
12920
13082
|
const { dir, name: name2 } = parent(path);
|
|
@@ -12961,10 +13123,10 @@ function tmpfs() {
|
|
|
12961
13123
|
place(dir, name2, node);
|
|
12962
13124
|
node.links++;
|
|
12963
13125
|
},
|
|
12964
|
-
async symlink(target, path) {
|
|
13126
|
+
async symlink(target, path, owner) {
|
|
12965
13127
|
const { dir, name: name2 } = parent(path);
|
|
12966
13128
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
12967
|
-
const node = make("symlink", 41471);
|
|
13129
|
+
const node = make("symlink", 41471, dir, owner && { ...owner, mode: 511 });
|
|
12968
13130
|
node.target = target;
|
|
12969
13131
|
place(dir, name2, node);
|
|
12970
13132
|
},
|
|
@@ -12983,6 +13145,7 @@ function tmpfs() {
|
|
|
12983
13145
|
node.mtime = Date.now();
|
|
12984
13146
|
}
|
|
12985
13147
|
if (change.mtime !== void 0) node.mtime = change.mtime;
|
|
13148
|
+
owned2(node, change);
|
|
12986
13149
|
},
|
|
12987
13150
|
async statfs() {
|
|
12988
13151
|
return { bsize: 4096, blocks: 262144, bfree: 262144 };
|
|
@@ -13303,7 +13466,8 @@ var Launcher = class {
|
|
|
13303
13466
|
this.mounts = new MountTable({
|
|
13304
13467
|
open: (type, spec) => this.driver(type, spec),
|
|
13305
13468
|
busy: (target) => [...this.openFiles].some((nodes) => nodes.holds(target)) || heldUnder(this.held, target),
|
|
13306
|
-
changed: this.watchers.changed.bind(this.watchers)
|
|
13469
|
+
changed: this.watchers.changed.bind(this.watchers),
|
|
13470
|
+
owners: this.owners
|
|
13307
13471
|
});
|
|
13308
13472
|
this.base = this.watchers.wrap(this.mounts.wrap(options.fs));
|
|
13309
13473
|
this.createWorker = options.createWorker;
|
|
@@ -13336,7 +13500,8 @@ var Launcher = class {
|
|
|
13336
13500
|
const fs = withCommandDirs(
|
|
13337
13501
|
this.base,
|
|
13338
13502
|
async () => new Set((await this.commands()).keys()),
|
|
13339
|
-
(dir) => this.userCommandDir(dir)
|
|
13503
|
+
(dir) => this.userCommandDir(dir),
|
|
13504
|
+
this.owners
|
|
13340
13505
|
);
|
|
13341
13506
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
13342
13507
|
this.nodes.keepsOnDisk = true;
|
|
@@ -13866,7 +14031,15 @@ var Launcher = class {
|
|
|
13866
14031
|
serveFilesystem(
|
|
13867
14032
|
port2,
|
|
13868
14033
|
tmpfs(),
|
|
13869
|
-
{
|
|
14034
|
+
{
|
|
14035
|
+
symlinks: true,
|
|
14036
|
+
links: true,
|
|
14037
|
+
chmod: true,
|
|
14038
|
+
owners: true,
|
|
14039
|
+
linkTimes: true,
|
|
14040
|
+
ranges: true,
|
|
14041
|
+
attrTtl: 0
|
|
14042
|
+
},
|
|
13870
14043
|
{ owned: true }
|
|
13871
14044
|
);
|
|
13872
14045
|
return {
|
|
@@ -13939,6 +14112,11 @@ var Launcher = class {
|
|
|
13939
14112
|
void this.unlinked.sweep(entry.target);
|
|
13940
14113
|
return entry;
|
|
13941
14114
|
}
|
|
14115
|
+
mountedBy(spec, cred) {
|
|
14116
|
+
if (!this.owners || cred.euid === 0 && cred.egid === 0) return spec;
|
|
14117
|
+
const ids = { uid: String(cred.euid), gid: String(cred.egid) };
|
|
14118
|
+
return { ...spec, options: { ...ids, ...spec.options } };
|
|
14119
|
+
}
|
|
13942
14120
|
mountRoot(path) {
|
|
13943
14121
|
let root = "/";
|
|
13944
14122
|
for (const { target } of this.mounts.list()) {
|
|
@@ -13982,7 +14160,7 @@ var Launcher = class {
|
|
|
13982
14160
|
async processMount(pid, call, signal) {
|
|
13983
14161
|
const spec = mountCall(call);
|
|
13984
14162
|
await this.permit({ op: "mount", pid, ...spec, options: { ...spec.options } });
|
|
13985
|
-
const entry = await this.mount(spec);
|
|
14163
|
+
const entry = await this.mount(this.mountedBy(spec, this.credOf(pid)));
|
|
13986
14164
|
if (signal.aborted) this.umount(entry.target, true);
|
|
13987
14165
|
}
|
|
13988
14166
|
async processUmount(pid, target, flags) {
|
|
@@ -14335,6 +14513,62 @@ function isMemoryRoot(handle) {
|
|
|
14335
14513
|
return handle instanceof MemoryDirectory;
|
|
14336
14514
|
}
|
|
14337
14515
|
|
|
14516
|
+
// src/node/ws-diagnose.ts
|
|
14517
|
+
import { lookup } from "node:dns/promises";
|
|
14518
|
+
import { isIP, connect as tcp } from "node:net";
|
|
14519
|
+
import { connect as tls } from "node:tls";
|
|
14520
|
+
var PROBE_MS = 3e3;
|
|
14521
|
+
var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
|
|
14522
|
+
var NO_NAME = /* @__PURE__ */ new Set(["ENOTFOUND", "EAI_AGAIN", "EAI_NONAME", "EAI_FAIL", "ENODATA"]);
|
|
14523
|
+
function codeOf5(e) {
|
|
14524
|
+
const code = e?.code;
|
|
14525
|
+
return typeof code === "string" ? code : void 0;
|
|
14526
|
+
}
|
|
14527
|
+
function probe(secure, host, port, ms) {
|
|
14528
|
+
return new Promise((resolve) => {
|
|
14529
|
+
const socket = secure ? tls({ host, port, ...isIP(host) ? {} : { servername: host } }) : tcp({ host, port });
|
|
14530
|
+
const done4 = (code) => {
|
|
14531
|
+
clearTimeout(timer);
|
|
14532
|
+
socket.destroy();
|
|
14533
|
+
resolve(code);
|
|
14534
|
+
};
|
|
14535
|
+
const timer = setTimeout(() => done4("ETIMEDOUT"), ms);
|
|
14536
|
+
socket.once(secure ? "secureConnect" : "connect", () => done4("EPROTO"));
|
|
14537
|
+
socket.once("error", (e) => {
|
|
14538
|
+
const code = codeOf5(e) ?? "";
|
|
14539
|
+
done4(PASSED.has(code) ? code : "EPROTO");
|
|
14540
|
+
});
|
|
14541
|
+
});
|
|
14542
|
+
}
|
|
14543
|
+
async function diagnose(url, ms = PROBE_MS) {
|
|
14544
|
+
const at = new URL(url);
|
|
14545
|
+
const host = at.hostname.replace(/^\[(.*)\]$/, "$1");
|
|
14546
|
+
const secure = at.protocol === "wss:";
|
|
14547
|
+
const port = Number(at.port) || (secure ? 443 : 80);
|
|
14548
|
+
try {
|
|
14549
|
+
await lookup(host);
|
|
14550
|
+
} catch (e) {
|
|
14551
|
+
return NO_NAME.has(codeOf5(e) ?? "") ? "EAI_NONAME" : void 0;
|
|
14552
|
+
}
|
|
14553
|
+
return probe(secure, host, port, ms);
|
|
14554
|
+
}
|
|
14555
|
+
function diagnosing(transport, check = diagnose) {
|
|
14556
|
+
const open = transport.websocket;
|
|
14557
|
+
if (!open) return transport;
|
|
14558
|
+
return {
|
|
14559
|
+
...transport,
|
|
14560
|
+
websocket: async (request) => {
|
|
14561
|
+
try {
|
|
14562
|
+
return await open(request);
|
|
14563
|
+
} catch (e) {
|
|
14564
|
+
if (request.signal.aborted || !(e instanceof Error) || codeOf5(e)) throw e;
|
|
14565
|
+
const code = await check(request.url).catch(() => void 0);
|
|
14566
|
+
throw code ? Object.assign(e, { code }) : e;
|
|
14567
|
+
}
|
|
14568
|
+
}
|
|
14569
|
+
};
|
|
14570
|
+
}
|
|
14571
|
+
|
|
14338
14572
|
// src/kernel/net/remote-transport.ts
|
|
14339
14573
|
var TransportError = class extends Error {
|
|
14340
14574
|
status;
|
|
@@ -15129,7 +15363,7 @@ function hostfsFetchOf(options) {
|
|
|
15129
15363
|
}
|
|
15130
15364
|
function nodeTransport() {
|
|
15131
15365
|
const transport = fetchTransport({ webSocket: true, webSocketHeaders: true, redirect: "manual" });
|
|
15132
|
-
return { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
|
|
15366
|
+
return diagnosing({ ...transport, traits: { ...transport.traits, crossOrigin: "any" } });
|
|
15133
15367
|
}
|
|
15134
15368
|
var TERMINATED = "the kernel is terminated";
|
|
15135
15369
|
var EXIT_GRACE_MS = 50;
|