@ai-ecoverse/slicc-kernel 1.34.1 → 1.36.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 +19 -3
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js.map +2 -2
- package/dist/kernel-worker.js +358 -76
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +158 -8
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +358 -76
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +158 -8
- package/dist/process-worker.js.map +3 -3
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -1938,11 +1938,41 @@ var OpfsFs = class {
|
|
|
1938
1938
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
1939
1939
|
return (directory ? S_IFDIR : S_IFREG) | (meta?.mode ?? fallback);
|
|
1940
1940
|
}
|
|
1941
|
+
dirTimes = /* @__PURE__ */ new Map();
|
|
1942
|
+
dirDirty = /* @__PURE__ */ new Set();
|
|
1943
|
+
dirFlush;
|
|
1944
|
+
touch(...dirs) {
|
|
1945
|
+
const now = Date.now();
|
|
1946
|
+
for (const dir of dirs) {
|
|
1947
|
+
this.dirTimes.set(dir, now);
|
|
1948
|
+
this.dirDirty.add(dir);
|
|
1949
|
+
}
|
|
1950
|
+
this.dirFlush ??= Promise.resolve().then(() => this.flushDirTimes()).catch(() => void 0).finally(() => {
|
|
1951
|
+
this.dirFlush = void 0;
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
async flushDirTimes() {
|
|
1955
|
+
for (const path of this.dirDirty) {
|
|
1956
|
+
this.dirDirty.delete(path);
|
|
1957
|
+
const ms = this.dirTimes.get(path);
|
|
1958
|
+
if (ms === void 0) continue;
|
|
1959
|
+
await this.meta.update(path, (entry) => ({
|
|
1960
|
+
...entry,
|
|
1961
|
+
path,
|
|
1962
|
+
mtimeMs: ms,
|
|
1963
|
+
mtimeFor: 0,
|
|
1964
|
+
ctimeMs: ms
|
|
1965
|
+
}));
|
|
1966
|
+
if (this.dirTimes.get(path) === ms) this.dirTimes.delete(path);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1941
1969
|
async statOf(path, handle, meta) {
|
|
1942
1970
|
const directory = handle.kind === "directory";
|
|
1943
1971
|
const file = directory ? void 0 : await handle.getFile();
|
|
1944
1972
|
const modified = file?.lastModified ?? 0;
|
|
1945
|
-
const
|
|
1973
|
+
const touched = directory ? this.dirTimes.get(path) : void 0;
|
|
1974
|
+
const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
|
|
1975
|
+
const mtime = touched ?? kept;
|
|
1946
1976
|
return {
|
|
1947
1977
|
isFile: !directory,
|
|
1948
1978
|
isDirectory: directory,
|
|
@@ -1951,7 +1981,7 @@ var OpfsFs = class {
|
|
|
1951
1981
|
mode: this.mode(path, directory, meta),
|
|
1952
1982
|
mtime: new Date(mtime),
|
|
1953
1983
|
atime: new Date(meta?.atimeMs ?? mtime),
|
|
1954
|
-
ctime: new Date(Math.max(meta?.ctimeMs ?? mtime, modified)),
|
|
1984
|
+
ctime: new Date(Math.max(touched ?? meta?.ctimeMs ?? mtime, modified)),
|
|
1955
1985
|
ino: meta?.ino ?? inodeOf(path),
|
|
1956
1986
|
...this.ranged && !directory ? { ranged: true } : {}
|
|
1957
1987
|
};
|
|
@@ -2028,6 +2058,19 @@ var OpfsFs = class {
|
|
|
2028
2058
|
const handle = await this.existing(path);
|
|
2029
2059
|
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
2030
2060
|
}
|
|
2061
|
+
async writeSession(path, truncate) {
|
|
2062
|
+
const handle = (await this.fileFor(path))[0];
|
|
2063
|
+
const writable = await this.retrying(
|
|
2064
|
+
path,
|
|
2065
|
+
() => handle.createWritable({ keepExistingData: !truncate }),
|
|
2066
|
+
true
|
|
2067
|
+
);
|
|
2068
|
+
return {
|
|
2069
|
+
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes }),
|
|
2070
|
+
truncate: (size) => writable.truncate(size),
|
|
2071
|
+
close: () => writable.close()
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2031
2074
|
async readFile(path) {
|
|
2032
2075
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
2033
2076
|
}
|
|
@@ -2045,10 +2088,12 @@ var OpfsFs = class {
|
|
|
2045
2088
|
const [target, existed] = await this.writeTarget(path);
|
|
2046
2089
|
const [dir, name2] = await this.parent(target);
|
|
2047
2090
|
try {
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2091
|
+
const handle = await this.inDir(
|
|
2092
|
+
dir,
|
|
2093
|
+
(parent) => parent.getFileHandle(name2, { create: true })
|
|
2094
|
+
);
|
|
2095
|
+
if (!existed) this.touch(parentOf2(target));
|
|
2096
|
+
return [handle, existed];
|
|
2052
2097
|
} catch (err) {
|
|
2053
2098
|
const code = err?.name === "TypeMismatchError" ? "EISDIR" : null;
|
|
2054
2099
|
throw code ? fsError(code, path) : translate(err, path);
|
|
@@ -2106,6 +2151,7 @@ var OpfsFs = class {
|
|
|
2106
2151
|
const parent = await this.locate(parentOf2(path), true);
|
|
2107
2152
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
2108
2153
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
2154
|
+
this.touch(parent.path);
|
|
2109
2155
|
}
|
|
2110
2156
|
async rm(path, options = {}) {
|
|
2111
2157
|
let found;
|
|
@@ -2129,6 +2175,7 @@ var OpfsFs = class {
|
|
|
2129
2175
|
this.changed(found.path);
|
|
2130
2176
|
}
|
|
2131
2177
|
await this.meta.remove([found.path]);
|
|
2178
|
+
this.touch(parentOf2(found.path));
|
|
2132
2179
|
}
|
|
2133
2180
|
async rename(from, to) {
|
|
2134
2181
|
if (from === to) return;
|
|
@@ -2160,6 +2207,7 @@ var OpfsFs = class {
|
|
|
2160
2207
|
if (source.link) {
|
|
2161
2208
|
if (target?.handle) await this.rm(destination);
|
|
2162
2209
|
await this.meta.move(source.path, destination, carry);
|
|
2210
|
+
this.touch(parentOf2(source.path), parent.path);
|
|
2163
2211
|
return;
|
|
2164
2212
|
}
|
|
2165
2213
|
const dir = parent.handle;
|
|
@@ -2181,6 +2229,7 @@ var OpfsFs = class {
|
|
|
2181
2229
|
}
|
|
2182
2230
|
if (copied) await this.restamp(destination, timed);
|
|
2183
2231
|
this.changed(source.path, destination);
|
|
2232
|
+
this.touch(parentOf2(source.path), parent.path);
|
|
2184
2233
|
}
|
|
2185
2234
|
async modified(path) {
|
|
2186
2235
|
const handle = await this.handle(path);
|
|
@@ -2244,6 +2293,10 @@ var OpfsFs = class {
|
|
|
2244
2293
|
mtimeMs: now,
|
|
2245
2294
|
ctimeMs: now
|
|
2246
2295
|
}));
|
|
2296
|
+
this.touch(parent.path);
|
|
2297
|
+
}
|
|
2298
|
+
async realpath(path, follow) {
|
|
2299
|
+
return (await this.locate(path, follow)).path;
|
|
2247
2300
|
}
|
|
2248
2301
|
async readlink(path) {
|
|
2249
2302
|
const found = await this.locate(path, false);
|
|
@@ -2281,6 +2334,7 @@ var OpfsFs = class {
|
|
|
2281
2334
|
}
|
|
2282
2335
|
const handle = found.handle;
|
|
2283
2336
|
const file = handle.kind === "file" ? await handle.getFile() : void 0;
|
|
2337
|
+
this.dirTimes.delete(found.path);
|
|
2284
2338
|
const ctimeMs = Date.now();
|
|
2285
2339
|
await this.meta.update(found.path, (entry) => ({
|
|
2286
2340
|
...entry,
|
|
@@ -3303,6 +3357,7 @@ function withCommandDirs(fs, names) {
|
|
|
3303
3357
|
rename: (from, to) => fs.rename(from, to),
|
|
3304
3358
|
symlink: (target, path) => fs.symlink(target, path),
|
|
3305
3359
|
readlink: (path) => fs.readlink(path),
|
|
3360
|
+
...fs.realpath ? { realpath: fs.realpath.bind(fs) } : {},
|
|
3306
3361
|
chmod: (path, mode) => fs.chmod(path, mode),
|
|
3307
3362
|
utimes: (path, atime, mtime) => fs.utimes(path, atime, mtime),
|
|
3308
3363
|
lutimes: (path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -3699,18 +3754,36 @@ function parseSize(text) {
|
|
|
3699
3754
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
3700
3755
|
}
|
|
3701
3756
|
var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
3757
|
+
var HeldSet = class extends Set {
|
|
3758
|
+
idle;
|
|
3759
|
+
constructor(idle) {
|
|
3760
|
+
super();
|
|
3761
|
+
this.idle = idle;
|
|
3762
|
+
}
|
|
3763
|
+
add(holds) {
|
|
3764
|
+
holds.onIdle = this.idle;
|
|
3765
|
+
return super.add(holds);
|
|
3766
|
+
}
|
|
3767
|
+
delete(holds) {
|
|
3768
|
+
const removed = super.delete(holds);
|
|
3769
|
+
for (const path of holds.keys()) this.idle(path);
|
|
3770
|
+
return removed;
|
|
3771
|
+
}
|
|
3772
|
+
};
|
|
3702
3773
|
function heldUnder(held, target) {
|
|
3703
3774
|
for (const paths of held) for (const path of paths.keys()) if (within2(path, target)) return true;
|
|
3704
3775
|
return false;
|
|
3705
3776
|
}
|
|
3706
3777
|
var HeldPaths = class extends Map {
|
|
3707
3778
|
revoked = /* @__PURE__ */ new Set();
|
|
3779
|
+
onIdle;
|
|
3708
3780
|
hold(path, on) {
|
|
3709
3781
|
const count = (this.get(path) ?? 0) + (on ? 1 : -1);
|
|
3710
3782
|
if (count > 0) this.set(path, count);
|
|
3711
3783
|
else {
|
|
3712
3784
|
this.delete(path);
|
|
3713
3785
|
this.revoked.delete(path);
|
|
3786
|
+
this.onIdle?.(path);
|
|
3714
3787
|
}
|
|
3715
3788
|
}
|
|
3716
3789
|
revoke(prefix) {
|
|
@@ -3778,6 +3851,8 @@ function spliced(bytes, offset, part) {
|
|
|
3778
3851
|
}
|
|
3779
3852
|
var MountTable = class {
|
|
3780
3853
|
mounts = /* @__PURE__ */ new Map();
|
|
3854
|
+
sessions = /* @__PURE__ */ new Map();
|
|
3855
|
+
committing = /* @__PURE__ */ new Map();
|
|
3781
3856
|
devices = 0;
|
|
3782
3857
|
pending = /* @__PURE__ */ new Set();
|
|
3783
3858
|
notes = /* @__PURE__ */ new Map();
|
|
@@ -3902,8 +3977,69 @@ var MountTable = class {
|
|
|
3902
3977
|
if (!detach && this.deps.busy(at)) throw errnoError("EBUSY", `${at} has open files`);
|
|
3903
3978
|
this.notes.delete(at);
|
|
3904
3979
|
this.mounts.delete(at);
|
|
3905
|
-
mount.
|
|
3906
|
-
mount.
|
|
3980
|
+
const waits = [...this.sessions].filter(([, s]) => s.mount === mount).map(([real]) => this.commit(real));
|
|
3981
|
+
for (const c of this.committing.values()) if (c.mount === mount) waits.push(c.done);
|
|
3982
|
+
const close = () => {
|
|
3983
|
+
mount.conn.close();
|
|
3984
|
+
mount.dispose();
|
|
3985
|
+
};
|
|
3986
|
+
if (waits.length === 0) close();
|
|
3987
|
+
else void Promise.allSettled(waits).then(close);
|
|
3988
|
+
}
|
|
3989
|
+
session(mount, real, rel2) {
|
|
3990
|
+
let session = this.sessions.get(real);
|
|
3991
|
+
if (!session) {
|
|
3992
|
+
const open = () => mount.conn.call({
|
|
3993
|
+
op: "open",
|
|
3994
|
+
path: rel2,
|
|
3995
|
+
write: true,
|
|
3996
|
+
create: true,
|
|
3997
|
+
truncate: false,
|
|
3998
|
+
exclusive: false
|
|
3999
|
+
});
|
|
4000
|
+
const before = this.committing.get(real)?.done ?? Promise.resolve();
|
|
4001
|
+
const fh = before.then(open, open);
|
|
4002
|
+
session = { mount, fh, extents: [], truncated: false };
|
|
4003
|
+
this.sessions.set(real, session);
|
|
4004
|
+
fh.catch(() => this.sessions.delete(real));
|
|
4005
|
+
}
|
|
4006
|
+
return session;
|
|
4007
|
+
}
|
|
4008
|
+
writing(real) {
|
|
4009
|
+
return this.sessions.get(real);
|
|
4010
|
+
}
|
|
4011
|
+
async commit(real) {
|
|
4012
|
+
const session = this.sessions.get(real);
|
|
4013
|
+
if (!session) return this.committing.get(real)?.done;
|
|
4014
|
+
this.sessions.delete(real);
|
|
4015
|
+
const done4 = (async () => {
|
|
4016
|
+
try {
|
|
4017
|
+
await session.mount.conn.call({ op: "release", fh: await session.fh });
|
|
4018
|
+
} finally {
|
|
4019
|
+
this.forget(session.mount, real);
|
|
4020
|
+
}
|
|
4021
|
+
})();
|
|
4022
|
+
const entry = { mount: session.mount, done: done4 };
|
|
4023
|
+
this.committing.set(real, entry);
|
|
4024
|
+
const settle = () => {
|
|
4025
|
+
if (this.committing.get(real) === entry) this.committing.delete(real);
|
|
4026
|
+
};
|
|
4027
|
+
done4.then(settle, settle);
|
|
4028
|
+
return done4;
|
|
4029
|
+
}
|
|
4030
|
+
async commitUnder(prefix) {
|
|
4031
|
+
const at = normalizePath(prefix);
|
|
4032
|
+
await Promise.all(
|
|
4033
|
+
[...this.sessions.keys()].filter((p) => within2(p, at)).map((p) => this.commit(p))
|
|
4034
|
+
);
|
|
4035
|
+
}
|
|
4036
|
+
async commitOverlapping(real, offset, length2) {
|
|
4037
|
+
const session = this.sessions.get(real);
|
|
4038
|
+
if (!session) return;
|
|
4039
|
+
const end = offset + length2;
|
|
4040
|
+
if (session.truncated || session.extents.some(([a, b]) => a < end && offset < b)) {
|
|
4041
|
+
await this.commit(real);
|
|
4042
|
+
}
|
|
3907
4043
|
}
|
|
3908
4044
|
crashed(mount, error) {
|
|
3909
4045
|
mount.state = "failed";
|
|
@@ -3962,6 +4098,13 @@ var MountTable = class {
|
|
|
3962
4098
|
return new MountFs(this, base);
|
|
3963
4099
|
}
|
|
3964
4100
|
};
|
|
4101
|
+
function noteExtent(extents, from, to) {
|
|
4102
|
+
const last = extents.at(-1);
|
|
4103
|
+
if (last && from <= last[1] && to >= last[0]) {
|
|
4104
|
+
last[0] = Math.min(last[0], from);
|
|
4105
|
+
last[1] = Math.max(last[1], to);
|
|
4106
|
+
} else extents.push([from, to]);
|
|
4107
|
+
}
|
|
3965
4108
|
var MountFs = class {
|
|
3966
4109
|
table;
|
|
3967
4110
|
base;
|
|
@@ -4021,6 +4164,7 @@ var MountFs = class {
|
|
|
4021
4164
|
}
|
|
4022
4165
|
}
|
|
4023
4166
|
async readWhole(mount, real, rel2) {
|
|
4167
|
+
await this.table.commit(real);
|
|
4024
4168
|
const attr = await this.table.getattr(mount, real, rel2);
|
|
4025
4169
|
if (attr.kind === "directory") throw errnoError("EISDIR", real);
|
|
4026
4170
|
if (mount.maxFile > 0 && attr.size > mount.maxFile) {
|
|
@@ -4070,6 +4214,7 @@ var MountFs = class {
|
|
|
4070
4214
|
}
|
|
4071
4215
|
}
|
|
4072
4216
|
async writeWhole(mount, real, rel2, bytes) {
|
|
4217
|
+
await this.table.commit(real);
|
|
4073
4218
|
this.table.forget(mount, real);
|
|
4074
4219
|
const fh = await this.open(mount, rel2, true);
|
|
4075
4220
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
@@ -4092,6 +4237,7 @@ var MountFs = class {
|
|
|
4092
4237
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
4093
4238
|
throw errnoError("EISDIR", real);
|
|
4094
4239
|
}
|
|
4240
|
+
await this.table.commitOverlapping(real, offset, length2);
|
|
4095
4241
|
const fh = await mount.conn.call({
|
|
4096
4242
|
op: "open",
|
|
4097
4243
|
path: rel2,
|
|
@@ -4145,6 +4291,14 @@ var MountFs = class {
|
|
|
4145
4291
|
this.writable(mount, real);
|
|
4146
4292
|
this.fits(mount, real, offset + bytes.length);
|
|
4147
4293
|
this.table.forget(mount, real);
|
|
4294
|
+
if (mount.caps.sessions) {
|
|
4295
|
+
const session = this.table.session(mount, real, rel2);
|
|
4296
|
+
const end = offset + bytes.length;
|
|
4297
|
+
await this.writeRuns(mount, await session.fh, offset, bytes, transfer);
|
|
4298
|
+
noteExtent(session.extents, offset, end);
|
|
4299
|
+
this.table.forget(mount, real);
|
|
4300
|
+
return;
|
|
4301
|
+
}
|
|
4148
4302
|
const fh = await mount.conn.call({
|
|
4149
4303
|
op: "open",
|
|
4150
4304
|
path: rel2,
|
|
@@ -4153,17 +4307,20 @@ var MountFs = class {
|
|
|
4153
4307
|
truncate: false,
|
|
4154
4308
|
exclusive: false
|
|
4155
4309
|
});
|
|
4156
|
-
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
4157
4310
|
try {
|
|
4158
|
-
|
|
4159
|
-
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
4160
|
-
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
4161
|
-
}
|
|
4311
|
+
await this.writeRuns(mount, fh, offset, bytes, transfer);
|
|
4162
4312
|
} finally {
|
|
4163
4313
|
await mount.conn.call({ op: "release", fh });
|
|
4164
4314
|
this.table.forget(mount, real);
|
|
4165
4315
|
}
|
|
4166
4316
|
}
|
|
4317
|
+
async writeRuns(mount, fh, offset, bytes, transfer) {
|
|
4318
|
+
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
4319
|
+
for (let at = 0; at < bytes.length; at += chunk2) {
|
|
4320
|
+
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
4321
|
+
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4167
4324
|
async truncate(path, size) {
|
|
4168
4325
|
const real = await this.follow(path);
|
|
4169
4326
|
const found = this.at(real);
|
|
@@ -4175,6 +4332,8 @@ var MountFs = class {
|
|
|
4175
4332
|
this.writable(mount, real);
|
|
4176
4333
|
this.fits(mount, real, size);
|
|
4177
4334
|
this.table.forget(mount, real);
|
|
4335
|
+
const session = this.table.writing(real);
|
|
4336
|
+
if (session) session.truncated = true;
|
|
4178
4337
|
try {
|
|
4179
4338
|
await mount.conn.call({ op: "setattr", path: rel2, size });
|
|
4180
4339
|
} finally {
|
|
@@ -4196,7 +4355,16 @@ var MountFs = class {
|
|
|
4196
4355
|
const found = this.at(path);
|
|
4197
4356
|
if (!found) return this.base.lstat(path);
|
|
4198
4357
|
const real = normalizePath(path);
|
|
4199
|
-
|
|
4358
|
+
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
4359
|
+
return this.statWriting(
|
|
4360
|
+
await this.table.getattr(found.mount, real, found.rel),
|
|
4361
|
+
real,
|
|
4362
|
+
found.mount
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
statWriting(attr, real, mount) {
|
|
4366
|
+
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
4367
|
+
return statOf({ ...attr, size: Math.max(attr.size, ...ends) }, real, mount);
|
|
4200
4368
|
}
|
|
4201
4369
|
async stat(path) {
|
|
4202
4370
|
const real = await this.follow(path);
|
|
@@ -4223,7 +4391,7 @@ var MountFs = class {
|
|
|
4223
4391
|
list.map(async (entry) => {
|
|
4224
4392
|
const child = normalizePath(`${real}/${entry.name}`);
|
|
4225
4393
|
if (entry.attr && mount.caps.listingStats) {
|
|
4226
|
-
return [entry.name,
|
|
4394
|
+
return [entry.name, this.statWriting(entry.attr, child, mount)];
|
|
4227
4395
|
}
|
|
4228
4396
|
return [entry.name, await this.lstat(child).catch(() => null)];
|
|
4229
4397
|
})
|
|
@@ -4259,6 +4427,7 @@ var MountFs = class {
|
|
|
4259
4427
|
const real = normalizePath(path);
|
|
4260
4428
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
4261
4429
|
this.writable(mount, real);
|
|
4430
|
+
await this.table.commitUnder(real);
|
|
4262
4431
|
let attr;
|
|
4263
4432
|
try {
|
|
4264
4433
|
attr = await this.table.getattr(mount, real, rel2);
|
|
@@ -4282,6 +4451,8 @@ var MountFs = class {
|
|
|
4282
4451
|
if (!a && !b) return this.base.rename(from, to);
|
|
4283
4452
|
if (!a || !b || a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
4284
4453
|
this.writable(a.mount, normalizePath(to));
|
|
4454
|
+
await this.table.commitUnder(from);
|
|
4455
|
+
await this.table.commitUnder(to);
|
|
4285
4456
|
this.table.forget(a.mount, normalizePath(from));
|
|
4286
4457
|
this.table.forget(a.mount, normalizePath(to));
|
|
4287
4458
|
try {
|
|
@@ -4300,6 +4471,12 @@ var MountFs = class {
|
|
|
4300
4471
|
this.table.forget(found.mount, normalizePath(path));
|
|
4301
4472
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel });
|
|
4302
4473
|
}
|
|
4474
|
+
async realpath(path, follow) {
|
|
4475
|
+
if (this.at(path) || !this.base.realpath) throw errnoError("ENOSYS", path);
|
|
4476
|
+
const real = await this.base.realpath(path, follow);
|
|
4477
|
+
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
4478
|
+
return real;
|
|
4479
|
+
}
|
|
4303
4480
|
async readlink(path) {
|
|
4304
4481
|
const found = this.at(path);
|
|
4305
4482
|
if (!found) return this.base.readlink(path);
|
|
@@ -7084,6 +7261,7 @@ var VfsNode = class {
|
|
|
7084
7261
|
writeBack;
|
|
7085
7262
|
writeBackCost = 0;
|
|
7086
7263
|
opens = 0;
|
|
7264
|
+
writers = 0;
|
|
7087
7265
|
missing = false;
|
|
7088
7266
|
revoked = false;
|
|
7089
7267
|
fs;
|
|
@@ -7259,8 +7437,10 @@ var VfsNodes = class {
|
|
|
7259
7437
|
byPath = /* @__PURE__ */ new Map();
|
|
7260
7438
|
fs;
|
|
7261
7439
|
entries = /* @__PURE__ */ new Map();
|
|
7262
|
-
|
|
7440
|
+
onClosed;
|
|
7441
|
+
constructor(fs, onClosed) {
|
|
7263
7442
|
this.fs = fs;
|
|
7443
|
+
this.onClosed = onClosed;
|
|
7264
7444
|
}
|
|
7265
7445
|
async onEntry(path, op) {
|
|
7266
7446
|
const key = await this.entryKey(path);
|
|
@@ -7274,9 +7454,21 @@ var VfsNodes = class {
|
|
|
7274
7454
|
}
|
|
7275
7455
|
async entryKey(path) {
|
|
7276
7456
|
const parent = parentOf5(path);
|
|
7277
|
-
const dir = await
|
|
7278
|
-
|
|
7279
|
-
|
|
7457
|
+
const dir = await this.real(parent, true, () => realDir(this.fs, parent));
|
|
7458
|
+
return joinName(dir, path.slice(path.lastIndexOf("/") + 1));
|
|
7459
|
+
}
|
|
7460
|
+
targetKey(path) {
|
|
7461
|
+
return this.real(path, true, () => realTarget(this.fs, path));
|
|
7462
|
+
}
|
|
7463
|
+
async real(path, follow, walk) {
|
|
7464
|
+
if (this.fs.realpath) {
|
|
7465
|
+
try {
|
|
7466
|
+
return await this.fs.realpath(path, follow);
|
|
7467
|
+
} catch (err) {
|
|
7468
|
+
if (errCode(err) === "ELOOP") throw err;
|
|
7469
|
+
}
|
|
7470
|
+
}
|
|
7471
|
+
return walk();
|
|
7280
7472
|
}
|
|
7281
7473
|
createExclusive(path) {
|
|
7282
7474
|
return this.onEntry(path, async () => {
|
|
@@ -7286,16 +7478,17 @@ var VfsNodes = class {
|
|
|
7286
7478
|
await this.fs.writeFile(path, new Uint8Array(0));
|
|
7287
7479
|
});
|
|
7288
7480
|
}
|
|
7289
|
-
open(path, pin) {
|
|
7481
|
+
open(path, pin, writable = false) {
|
|
7290
7482
|
let node = this.byPath.get(path);
|
|
7291
7483
|
if (!node) {
|
|
7292
7484
|
node = new VfsNode(this.fs, path, void 0, false, false, pin);
|
|
7293
7485
|
this.byPath.set(path, node);
|
|
7294
7486
|
}
|
|
7295
7487
|
node.opens++;
|
|
7488
|
+
if (writable) node.writers++;
|
|
7296
7489
|
return node;
|
|
7297
7490
|
}
|
|
7298
|
-
adopt(path, contents2, dirty) {
|
|
7491
|
+
adopt(path, contents2, dirty, writable = false) {
|
|
7299
7492
|
let node = this.byPath.get(path);
|
|
7300
7493
|
if (!node) {
|
|
7301
7494
|
node = new VfsNode(this.fs, path, contents2, false, dirty);
|
|
@@ -7304,15 +7497,27 @@ var VfsNodes = class {
|
|
|
7304
7497
|
node.replace(contents2);
|
|
7305
7498
|
}
|
|
7306
7499
|
node.opens++;
|
|
7500
|
+
if (writable) node.writers++;
|
|
7307
7501
|
return node;
|
|
7308
7502
|
}
|
|
7309
7503
|
holds(prefix) {
|
|
7310
7504
|
for (const path of this.byPath.keys()) if (within4(path, prefix)) return true;
|
|
7311
7505
|
return false;
|
|
7312
7506
|
}
|
|
7313
|
-
|
|
7507
|
+
writes(prefix) {
|
|
7508
|
+
for (const [path, node] of this.byPath)
|
|
7509
|
+
if (node.writers > 0 && within4(path, prefix)) return true;
|
|
7510
|
+
return false;
|
|
7511
|
+
}
|
|
7512
|
+
closed(node, writable = false) {
|
|
7314
7513
|
node.opens--;
|
|
7315
|
-
if (
|
|
7514
|
+
if (writable) node.writers--;
|
|
7515
|
+
if (node.opens > 0) {
|
|
7516
|
+
if (writable && node.writers === 0) this.onClosed?.(node.path);
|
|
7517
|
+
return;
|
|
7518
|
+
}
|
|
7519
|
+
if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
|
|
7520
|
+
this.onClosed?.(node.path);
|
|
7316
7521
|
}
|
|
7317
7522
|
async flush(path) {
|
|
7318
7523
|
for (const [p, node] of this.byPath) if (within4(p, path)) await node.serial(() => node.flush());
|
|
@@ -7371,10 +7576,9 @@ function parentOf5(path) {
|
|
|
7371
7576
|
async function linkOf(fs, path) {
|
|
7372
7577
|
return fs.readlink?.(path).catch(() => void 0);
|
|
7373
7578
|
}
|
|
7374
|
-
async function realDir(fs, dir) {
|
|
7579
|
+
async function realDir(fs, dir, budget = { hops: 0 }) {
|
|
7375
7580
|
const queue = dir.split("/").filter(Boolean);
|
|
7376
7581
|
let at = "/";
|
|
7377
|
-
let hops = 0;
|
|
7378
7582
|
while (queue.length > 0) {
|
|
7379
7583
|
const part = queue.shift();
|
|
7380
7584
|
if (part === ".") continue;
|
|
@@ -7383,28 +7587,41 @@ async function realDir(fs, dir) {
|
|
|
7383
7587
|
continue;
|
|
7384
7588
|
}
|
|
7385
7589
|
const next = at === "/" ? `/${part}` : `${at}/${part}`;
|
|
7386
|
-
const link2 =
|
|
7590
|
+
const link2 = await linkOf(fs, next);
|
|
7387
7591
|
if (link2 === void 0) {
|
|
7388
7592
|
at = next;
|
|
7389
7593
|
continue;
|
|
7390
7594
|
}
|
|
7391
|
-
hops
|
|
7595
|
+
if (budget.hops >= MAX_LINKS5) throw fsError("ELOOP", dir);
|
|
7596
|
+
budget.hops++;
|
|
7392
7597
|
queue.unshift(...link2.split("/").filter(Boolean));
|
|
7393
7598
|
if (link2.startsWith("/")) at = "/";
|
|
7394
7599
|
}
|
|
7395
7600
|
return at;
|
|
7396
7601
|
}
|
|
7397
|
-
|
|
7398
|
-
|
|
7602
|
+
function errCode(err) {
|
|
7603
|
+
return err?.code;
|
|
7604
|
+
}
|
|
7605
|
+
function joinName(dir, name2) {
|
|
7606
|
+
return dir === "/" ? `/${name2}` : `${dir}/${name2}`;
|
|
7607
|
+
}
|
|
7608
|
+
async function realTarget(fs, path) {
|
|
7609
|
+
const budget = { hops: 0 };
|
|
7610
|
+
let dir = await realDir(fs, parentOf5(path), budget);
|
|
7399
7611
|
let name2 = path.slice(path.lastIndexOf("/") + 1);
|
|
7400
|
-
for (
|
|
7401
|
-
const link2 = await linkOf(fs, dir
|
|
7402
|
-
if (link2 === void 0)
|
|
7403
|
-
|
|
7404
|
-
|
|
7612
|
+
for (; ; ) {
|
|
7613
|
+
const link2 = await linkOf(fs, joinName(dir, name2));
|
|
7614
|
+
if (link2 === void 0) break;
|
|
7615
|
+
if (budget.hops >= MAX_LINKS5) throw fsError("ELOOP", path);
|
|
7616
|
+
budget.hops++;
|
|
7617
|
+
const target = link2.startsWith("/") ? link2 : joinName(dir, link2);
|
|
7618
|
+
dir = await realDir(fs, parentOf5(target), budget);
|
|
7405
7619
|
name2 = target.slice(target.lastIndexOf("/") + 1);
|
|
7406
7620
|
}
|
|
7407
|
-
return dir;
|
|
7621
|
+
return joinName(dir, name2);
|
|
7622
|
+
}
|
|
7623
|
+
async function targetDir(fs, path) {
|
|
7624
|
+
return parentOf5(await realTarget(fs, path).catch(() => path));
|
|
7408
7625
|
}
|
|
7409
7626
|
async function refuseReadonly(fs, path, flags, opts = {}) {
|
|
7410
7627
|
const writes = (flags & O_ACCMODE) !== 0 || opts.truncate === true;
|
|
@@ -7423,13 +7640,14 @@ function keepingOpen(fs, nodes) {
|
|
|
7423
7640
|
return {
|
|
7424
7641
|
...fs,
|
|
7425
7642
|
async rm(path, options) {
|
|
7426
|
-
const at = fs.resolvePath("/", path);
|
|
7643
|
+
const at = await nodes.entryKey(fs.resolvePath("/", path));
|
|
7427
7644
|
await nodes.unlinking(at);
|
|
7428
7645
|
await fs.rm(path, options);
|
|
7429
7646
|
nodes.unlinked(at);
|
|
7430
7647
|
},
|
|
7431
|
-
rename(from, to) {
|
|
7432
|
-
const
|
|
7648
|
+
async rename(from, to) {
|
|
7649
|
+
const a = await nodes.entryKey(fs.resolvePath("/", from));
|
|
7650
|
+
const b = await nodes.entryKey(fs.resolvePath("/", to));
|
|
7433
7651
|
return nodes.onEntry(b, async () => {
|
|
7434
7652
|
await nodes.unlinking(b);
|
|
7435
7653
|
await fs.rename(from, to);
|
|
@@ -7445,7 +7663,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7445
7663
|
const access = opts.flags & O_ACCMODE;
|
|
7446
7664
|
const readable = access !== O_WRONLY;
|
|
7447
7665
|
const writable = access === O_WRONLY || access === O_RDWR;
|
|
7448
|
-
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true) : nodes.open(opts.path, opts.pin);
|
|
7666
|
+
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true, writable) : nodes.open(opts.path, opts.pin, writable);
|
|
7449
7667
|
let openError;
|
|
7450
7668
|
const atOpen = (op) => {
|
|
7451
7669
|
void node.serial(op).catch((err) => {
|
|
@@ -7508,7 +7726,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7508
7726
|
takeOpenError();
|
|
7509
7727
|
await node.flush();
|
|
7510
7728
|
} finally {
|
|
7511
|
-
nodes?.closed(node);
|
|
7729
|
+
nodes?.closed(node, writable);
|
|
7512
7730
|
}
|
|
7513
7731
|
})
|
|
7514
7732
|
});
|
|
@@ -7575,10 +7793,12 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
7575
7793
|
"fd-cloexec",
|
|
7576
7794
|
"fd-list",
|
|
7577
7795
|
"proc-alarm",
|
|
7796
|
+
"proc-umask",
|
|
7578
7797
|
"dl-log",
|
|
7579
7798
|
"fd-renumber",
|
|
7580
7799
|
"fd-promote",
|
|
7581
7800
|
"fd-open-tty",
|
|
7801
|
+
"fd-tty-names",
|
|
7582
7802
|
"tty-get",
|
|
7583
7803
|
"tty-set",
|
|
7584
7804
|
"tty-winsz",
|
|
@@ -7612,6 +7832,7 @@ function isWasmSyscall(req) {
|
|
|
7612
7832
|
return typeof op === "string" && SYSCALL_OPS.has(op);
|
|
7613
7833
|
}
|
|
7614
7834
|
var MAX_READ = 1024 * 1024;
|
|
7835
|
+
var DEFAULT_UMASK = 18;
|
|
7615
7836
|
var DYING = { ok: false, errno: "EINTR", message: "the process is being killed" };
|
|
7616
7837
|
var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
7617
7838
|
var WasmProcess = class {
|
|
@@ -7622,6 +7843,7 @@ var WasmProcess = class {
|
|
|
7622
7843
|
inherited = 0;
|
|
7623
7844
|
interrupt = new AbortController();
|
|
7624
7845
|
dying = false;
|
|
7846
|
+
umask = DEFAULT_UMASK;
|
|
7625
7847
|
execChild;
|
|
7626
7848
|
execTermsig;
|
|
7627
7849
|
stopped = 0;
|
|
@@ -7639,6 +7861,7 @@ var WasmProcess = class {
|
|
|
7639
7861
|
this.fds = fds;
|
|
7640
7862
|
this.options = options;
|
|
7641
7863
|
this.inherited = options.ignored ?? 0;
|
|
7864
|
+
this.umask = options.umask ?? DEFAULT_UMASK;
|
|
7642
7865
|
this.children = new ChildTable(fds, options.spawner, options.forker);
|
|
7643
7866
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
7644
7867
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
@@ -7711,6 +7934,11 @@ var WasmProcess = class {
|
|
|
7711
7934
|
return result;
|
|
7712
7935
|
}
|
|
7713
7936
|
}
|
|
7937
|
+
setUmask(mask) {
|
|
7938
|
+
const old = this.umask;
|
|
7939
|
+
if (mask !== void 0) this.umask = mask & 511;
|
|
7940
|
+
return old;
|
|
7941
|
+
}
|
|
7714
7942
|
die() {
|
|
7715
7943
|
if (this.dying) return;
|
|
7716
7944
|
this.dying = true;
|
|
@@ -7781,9 +8009,21 @@ var WasmProcess = class {
|
|
|
7781
8009
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
7782
8010
|
const fd = this.fds.install(heldFile(), 3);
|
|
7783
8011
|
try {
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
8012
|
+
const nodes = this.nodes;
|
|
8013
|
+
const path = req.orphan ? req.path : req.exclusive ? await nodes.entryKey(req.path) : await nodes.targetKey(req.path);
|
|
8014
|
+
const open = { ...req, path };
|
|
8015
|
+
if (req.exclusive) {
|
|
8016
|
+
await nodes.createExclusive(path);
|
|
8017
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8018
|
+
} else if (req.create) {
|
|
8019
|
+
await nodes.onEntry(path, async () => {
|
|
8020
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8021
|
+
await this.fds.get(fd).file.stat?.();
|
|
8022
|
+
});
|
|
8023
|
+
} else {
|
|
8024
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8025
|
+
}
|
|
8026
|
+
if (req.existing && !await present(this.options.fs, path, true)) {
|
|
7787
8027
|
throw new KernelError("ENOENT");
|
|
7788
8028
|
}
|
|
7789
8029
|
} catch (err) {
|
|
@@ -7862,7 +8102,7 @@ var WasmProcess = class {
|
|
|
7862
8102
|
case "fd-reserve":
|
|
7863
8103
|
return { ok: true, kind: "json", json: this.reserve(req.fd, req.min, req.meta) };
|
|
7864
8104
|
case "fd-promote":
|
|
7865
|
-
this.promote(req);
|
|
8105
|
+
await this.promote(req);
|
|
7866
8106
|
return { ok: true, kind: "void" };
|
|
7867
8107
|
case "fd-renumber":
|
|
7868
8108
|
if (req.from !== req.to) {
|
|
@@ -7875,6 +8115,8 @@ var WasmProcess = class {
|
|
|
7875
8115
|
if (!tty) throw new KernelError("ENXIO");
|
|
7876
8116
|
return { ok: true, kind: "json", json: this.fds.install(tty.file(), 3) };
|
|
7877
8117
|
}
|
|
8118
|
+
case "fd-tty-names":
|
|
8119
|
+
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
7878
8120
|
case "fd-select": {
|
|
7879
8121
|
const { read, write, timeoutMs } = req;
|
|
7880
8122
|
const signal = this.blockingSignal();
|
|
@@ -7896,10 +8138,14 @@ var WasmProcess = class {
|
|
|
7896
8138
|
async vfsSyscall(req) {
|
|
7897
8139
|
if ("path" in req || "from" in req) {
|
|
7898
8140
|
const nodes = this.nodes;
|
|
7899
|
-
if (req.op === "fd-path-flush")
|
|
7900
|
-
|
|
7901
|
-
else if (req.op === "fd-path-
|
|
7902
|
-
|
|
8141
|
+
if (req.op === "fd-path-flush") {
|
|
8142
|
+
await nodes.flush(await nodes.targetKey(req.path).catch(() => req.path));
|
|
8143
|
+
} else if (req.op === "fd-path-unlinking")
|
|
8144
|
+
await nodes.unlinking(await nodes.entryKey(req.path));
|
|
8145
|
+
else if (req.op === "fd-path-unlinked") nodes.unlinked(await nodes.entryKey(req.path));
|
|
8146
|
+
else if (req.op === "fd-path-renamed") {
|
|
8147
|
+
nodes.renamed(await nodes.entryKey(req.from), await nodes.entryKey(req.to));
|
|
8148
|
+
}
|
|
7903
8149
|
return { ok: true, kind: "void" };
|
|
7904
8150
|
}
|
|
7905
8151
|
const file = this.fds.get(req.fd).file;
|
|
@@ -7920,17 +8166,19 @@ var WasmProcess = class {
|
|
|
7920
8166
|
return { ok: true, kind: "json", json: await file.stat() };
|
|
7921
8167
|
}
|
|
7922
8168
|
}
|
|
7923
|
-
promote(req) {
|
|
8169
|
+
async promote(req) {
|
|
7924
8170
|
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
7925
8171
|
if (req.share !== void 0) {
|
|
7926
8172
|
this.fds.dup2(req.share, req.fd);
|
|
7927
8173
|
return;
|
|
7928
8174
|
}
|
|
7929
8175
|
if (req.path === void 0) throw new KernelError("EINVAL");
|
|
8176
|
+
const path = req.orphan ? req.path : await this.nodes.targetKey(req.path);
|
|
8177
|
+
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
7930
8178
|
const file = vfsFile(
|
|
7931
8179
|
this.options.fs,
|
|
7932
8180
|
{
|
|
7933
|
-
path
|
|
8181
|
+
path,
|
|
7934
8182
|
flags: req.flags ?? 0,
|
|
7935
8183
|
position: req.position ?? 0,
|
|
7936
8184
|
...req.contents !== void 0 ? { contents: req.contents } : {},
|
|
@@ -8106,6 +8354,8 @@ var WasmProcess = class {
|
|
|
8106
8354
|
case "proc-alarm":
|
|
8107
8355
|
this.setAlarm(req.sig, req.firstMs ?? req.ms, req.repeat ? req.ms : 0, req.timer);
|
|
8108
8356
|
return { ok: true, kind: "void" };
|
|
8357
|
+
case "proc-umask":
|
|
8358
|
+
return { ok: true, kind: "json", json: this.setUmask(req.mask) };
|
|
8109
8359
|
case "dl-log":
|
|
8110
8360
|
if (req.append) this.dlLog.push(req.append);
|
|
8111
8361
|
return { ok: true, kind: "json", json: this.dlLog.slice(req.from) };
|
|
@@ -8255,7 +8505,7 @@ var Dying = class {
|
|
|
8255
8505
|
return [typeof reported === "number" ? reported : CRASHED, void 0];
|
|
8256
8506
|
}
|
|
8257
8507
|
};
|
|
8258
|
-
function processInit(opts, sab) {
|
|
8508
|
+
function processInit(opts, sab, umask) {
|
|
8259
8509
|
const base = {
|
|
8260
8510
|
type: WASM_PROCESS_INIT,
|
|
8261
8511
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -8264,6 +8514,7 @@ function processInit(opts, sab) {
|
|
|
8264
8514
|
env: opts.env,
|
|
8265
8515
|
cwd: opts.cwd,
|
|
8266
8516
|
sab,
|
|
8517
|
+
umask,
|
|
8267
8518
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
8268
8519
|
};
|
|
8269
8520
|
if (opts.program.abi === "js") {
|
|
@@ -8275,11 +8526,17 @@ function processInit(opts, sab) {
|
|
|
8275
8526
|
...opts.fork ? { fork: opts.fork } : { fds: inheritedFds(opts.fds) }
|
|
8276
8527
|
};
|
|
8277
8528
|
}
|
|
8529
|
+
function inherited(opts) {
|
|
8530
|
+
return {
|
|
8531
|
+
...opts.ignored ? { ignored: opts.ignored } : {},
|
|
8532
|
+
...opts.umask !== void 0 ? { umask: opts.umask } : {}
|
|
8533
|
+
};
|
|
8534
|
+
}
|
|
8278
8535
|
function spawnWasmProcess(opts) {
|
|
8279
8536
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
8280
8537
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
8281
8538
|
const process = new WasmProcess(opts.pid, opts.fds, {
|
|
8282
|
-
...opts
|
|
8539
|
+
...inherited(opts),
|
|
8283
8540
|
...opts.identity ? { identity: opts.identity } : {},
|
|
8284
8541
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
8285
8542
|
spawner: opts.spawner,
|
|
@@ -8413,7 +8670,7 @@ function spawnWasmProcess(opts) {
|
|
|
8413
8670
|
};
|
|
8414
8671
|
tw.postMessage(tinit);
|
|
8415
8672
|
};
|
|
8416
|
-
const init = processInit(opts, sab);
|
|
8673
|
+
const init = processInit(opts, sab, process.umask);
|
|
8417
8674
|
worker.postMessage(init, opts.fork ? [opts.fork.memory.buffer] : []);
|
|
8418
8675
|
const signal = (sig) => {
|
|
8419
8676
|
if (process.signal(sig) !== "terminate") return;
|
|
@@ -8431,6 +8688,7 @@ function spawnWasmProcess(opts) {
|
|
|
8431
8688
|
onState: (listener) => process.onState(listener),
|
|
8432
8689
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
8433
8690
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
8691
|
+
umask: () => process.umask,
|
|
8434
8692
|
writesBack: () => opts.program.abi === "wasi" && !done4
|
|
8435
8693
|
};
|
|
8436
8694
|
}
|
|
@@ -8536,8 +8794,13 @@ var JobTable = class {
|
|
|
8536
8794
|
return id;
|
|
8537
8795
|
}
|
|
8538
8796
|
terminalNamed(name2) {
|
|
8539
|
-
|
|
8540
|
-
|
|
8797
|
+
return this.knownTerminals().find((tty) => tty.name === name2);
|
|
8798
|
+
}
|
|
8799
|
+
terminalNames() {
|
|
8800
|
+
return this.knownTerminals().flatMap((tty) => tty.name ? [tty.name] : []);
|
|
8801
|
+
}
|
|
8802
|
+
knownTerminals() {
|
|
8803
|
+
return [.../* @__PURE__ */ new Set([...this.terminals.values(), ...this.foreground.keys()])];
|
|
8541
8804
|
}
|
|
8542
8805
|
controllingTerminal(pid) {
|
|
8543
8806
|
const member = this.members.get(pid);
|
|
@@ -8810,7 +9073,11 @@ function mediumSlot(lost, onLost) {
|
|
|
8810
9073
|
}
|
|
8811
9074
|
|
|
8812
9075
|
// src/mount/fsa.ts
|
|
8813
|
-
var FSA_CAPABILITIES = {
|
|
9076
|
+
var FSA_CAPABILITIES = {
|
|
9077
|
+
listingStats: true,
|
|
9078
|
+
ranges: true,
|
|
9079
|
+
sessions: true
|
|
9080
|
+
};
|
|
8814
9081
|
var codeOf2 = (err) => err?.code;
|
|
8815
9082
|
var denied = (err) => codeOf2(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
8816
9083
|
function attrOf(st) {
|
|
@@ -8850,30 +9117,20 @@ function kernelFsHandlers(fs) {
|
|
|
8850
9117
|
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
8851
9118
|
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
8852
9119
|
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
8853
|
-
|
|
8854
|
-
handles.set(++nextFh, { path
|
|
9120
|
+
if (!st || flags.truncate) await fs.writeFile(path, new Uint8Array(0));
|
|
9121
|
+
handles.set(++nextFh, { path });
|
|
8855
9122
|
return nextFh;
|
|
8856
9123
|
},
|
|
8857
|
-
async
|
|
8858
|
-
const h = handle(fh);
|
|
8859
|
-
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
8860
|
-
},
|
|
9124
|
+
read: async (fh, offset, size) => fs.pread(handle(fh).path, offset, size),
|
|
8861
9125
|
async write(fh, offset, bytes) {
|
|
8862
9126
|
const h = handle(fh);
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
const grown = new Uint8Array(Math.max(end, h.data.length * 2));
|
|
8866
|
-
grown.set(h.data.subarray(0, h.length));
|
|
8867
|
-
h.data = grown;
|
|
8868
|
-
}
|
|
8869
|
-
h.data.set(bytes, offset);
|
|
8870
|
-
h.length = Math.max(h.length, end);
|
|
8871
|
-
h.dirty = true;
|
|
9127
|
+
h.session ??= fs.writeSession(h.path, false);
|
|
9128
|
+
await (await h.session).write(offset, bytes);
|
|
8872
9129
|
},
|
|
8873
9130
|
async release(fh) {
|
|
8874
9131
|
const h = handle(fh);
|
|
8875
9132
|
handles.delete(fh);
|
|
8876
|
-
if (h.
|
|
9133
|
+
if (h.session !== void 0) await (await h.session).close();
|
|
8877
9134
|
},
|
|
8878
9135
|
mkdir: (path) => fs.mkdir(path),
|
|
8879
9136
|
async rmdir(path) {
|
|
@@ -8889,6 +9146,13 @@ function kernelFsHandlers(fs) {
|
|
|
8889
9146
|
symlink: (target, path) => fs.symlink(target, path),
|
|
8890
9147
|
readlink: (path) => fs.readlink(path),
|
|
8891
9148
|
async setattr(path, change) {
|
|
9149
|
+
if (change.size !== void 0) {
|
|
9150
|
+
const open = [...handles.values()].find(
|
|
9151
|
+
(h) => h.path === path && h.session !== void 0
|
|
9152
|
+
)?.session;
|
|
9153
|
+
if (open !== void 0) await (await open).truncate(change.size);
|
|
9154
|
+
else await fs.truncate?.(path, change.size);
|
|
9155
|
+
}
|
|
8892
9156
|
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
8893
9157
|
if (change.mtime !== void 0) {
|
|
8894
9158
|
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
@@ -9613,6 +9877,7 @@ function tmpfs() {
|
|
|
9613
9877
|
const { dir, name: name2 } = parent(path);
|
|
9614
9878
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
9615
9879
|
dir.children.set(name2, make("directory", 16877));
|
|
9880
|
+
dir.mtime = Date.now();
|
|
9616
9881
|
},
|
|
9617
9882
|
async rmdir(path) {
|
|
9618
9883
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9621,6 +9886,7 @@ function tmpfs() {
|
|
|
9621
9886
|
if (node.kind !== "directory") throw fsError2("ENOTDIR", path);
|
|
9622
9887
|
if (node.children.size > 0) throw fsError2("ENOTEMPTY", path);
|
|
9623
9888
|
dir.children.delete(name2);
|
|
9889
|
+
dir.mtime = Date.now();
|
|
9624
9890
|
},
|
|
9625
9891
|
async unlink(path) {
|
|
9626
9892
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9628,6 +9894,7 @@ function tmpfs() {
|
|
|
9628
9894
|
if (!node) throw fsError2("ENOENT", path);
|
|
9629
9895
|
if (node.kind === "directory") throw fsError2("EISDIR", path);
|
|
9630
9896
|
dir.children.delete(name2);
|
|
9897
|
+
dir.mtime = Date.now();
|
|
9631
9898
|
},
|
|
9632
9899
|
async rename(from, to) {
|
|
9633
9900
|
const a = `/${parts(from).join("/")}`;
|
|
@@ -9644,6 +9911,8 @@ function tmpfs() {
|
|
|
9644
9911
|
}
|
|
9645
9912
|
source.dir.children.delete(source.name);
|
|
9646
9913
|
target.dir.children.set(target.name, node);
|
|
9914
|
+
source.dir.mtime = Date.now();
|
|
9915
|
+
target.dir.mtime = source.dir.mtime;
|
|
9647
9916
|
},
|
|
9648
9917
|
async symlink(target, path) {
|
|
9649
9918
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9651,6 +9920,7 @@ function tmpfs() {
|
|
|
9651
9920
|
const node = make("symlink", 41471);
|
|
9652
9921
|
node.target = target;
|
|
9653
9922
|
dir.children.set(name2, node);
|
|
9923
|
+
dir.mtime = Date.now();
|
|
9654
9924
|
},
|
|
9655
9925
|
async readlink(path) {
|
|
9656
9926
|
const node = find(path);
|
|
@@ -9949,7 +10219,7 @@ var Launcher = class {
|
|
|
9949
10219
|
deciding = /* @__PURE__ */ new Map();
|
|
9950
10220
|
identities = { asked: 0, timedOut: 0 };
|
|
9951
10221
|
nodes;
|
|
9952
|
-
held =
|
|
10222
|
+
held = new HeldSet((path) => this.released(path));
|
|
9953
10223
|
processMounts;
|
|
9954
10224
|
booting = new AbortController();
|
|
9955
10225
|
fstab = Promise.resolve([]);
|
|
@@ -9991,7 +10261,7 @@ var Launcher = class {
|
|
|
9991
10261
|
});
|
|
9992
10262
|
enableCdp(this.net, this.cdp);
|
|
9993
10263
|
const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
9994
|
-
this.nodes = new VfsNodes(fs);
|
|
10264
|
+
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
9995
10265
|
this.openFiles.add(this.nodes);
|
|
9996
10266
|
this.fs = keepingOpen(fs, this.nodes);
|
|
9997
10267
|
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
@@ -10180,6 +10450,7 @@ var Launcher = class {
|
|
|
10180
10450
|
this.settling.syscall(pid, call.op);
|
|
10181
10451
|
},
|
|
10182
10452
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
10453
|
+
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
10183
10454
|
program: req.program,
|
|
10184
10455
|
argv0: req.argv0,
|
|
10185
10456
|
args: req.args,
|
|
@@ -10271,7 +10542,8 @@ var Launcher = class {
|
|
|
10271
10542
|
...described,
|
|
10272
10543
|
started: (this.described.get(root.pid) ?? described).started,
|
|
10273
10544
|
state: this.processes.has(member.pid) ? "S" : "Z",
|
|
10274
|
-
memory: this.processes.get(member.pid)?.memory() ?? 0
|
|
10545
|
+
memory: this.processes.get(member.pid)?.memory() ?? 0,
|
|
10546
|
+
umask: this.umaskOf(member.pid)
|
|
10275
10547
|
});
|
|
10276
10548
|
}
|
|
10277
10549
|
return listed;
|
|
@@ -10293,6 +10565,7 @@ var Launcher = class {
|
|
|
10293
10565
|
report,
|
|
10294
10566
|
ppid,
|
|
10295
10567
|
ignored: this.ignoredBy(ppid),
|
|
10568
|
+
umask: this.umaskOf(ppid),
|
|
10296
10569
|
...exec
|
|
10297
10570
|
});
|
|
10298
10571
|
deciding?.attach();
|
|
@@ -10337,7 +10610,8 @@ var Launcher = class {
|
|
|
10337
10610
|
fds,
|
|
10338
10611
|
ppid,
|
|
10339
10612
|
fork: state,
|
|
10340
|
-
ignored: this.ignoredBy(ppid, true)
|
|
10613
|
+
ignored: this.ignoredBy(ppid, true),
|
|
10614
|
+
umask: this.umaskOf(ppid)
|
|
10341
10615
|
})
|
|
10342
10616
|
);
|
|
10343
10617
|
}
|
|
@@ -10346,6 +10620,14 @@ var Launcher = class {
|
|
|
10346
10620
|
const foreground = () => this.jobs.tcgetpgrp(tty, fallback);
|
|
10347
10621
|
this.settling.deliver(sig, pgid, send, tty.reading ? void 0 : foreground);
|
|
10348
10622
|
}
|
|
10623
|
+
umaskOf(pid) {
|
|
10624
|
+
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
10625
|
+
}
|
|
10626
|
+
released(path) {
|
|
10627
|
+
const at = normalizePath(path);
|
|
10628
|
+
const open = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
10629
|
+
if (!open) void this.mounts.commit(at).catch(() => void 0);
|
|
10630
|
+
}
|
|
10349
10631
|
ignoredBy(pid, fork = false) {
|
|
10350
10632
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
10351
10633
|
}
|