@ai-ecoverse/slicc-kernel 1.35.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 +3 -3
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js.map +2 -2
- package/dist/kernel-worker.js +236 -41
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node.js +236 -41
- package/dist/node.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,7 @@ var OpfsFs = class {
|
|
|
2244
2293
|
mtimeMs: now,
|
|
2245
2294
|
ctimeMs: now
|
|
2246
2295
|
}));
|
|
2296
|
+
this.touch(parent.path);
|
|
2247
2297
|
}
|
|
2248
2298
|
async realpath(path, follow) {
|
|
2249
2299
|
return (await this.locate(path, follow)).path;
|
|
@@ -2284,6 +2334,7 @@ var OpfsFs = class {
|
|
|
2284
2334
|
}
|
|
2285
2335
|
const handle = found.handle;
|
|
2286
2336
|
const file = handle.kind === "file" ? await handle.getFile() : void 0;
|
|
2337
|
+
this.dirTimes.delete(found.path);
|
|
2287
2338
|
const ctimeMs = Date.now();
|
|
2288
2339
|
await this.meta.update(found.path, (entry) => ({
|
|
2289
2340
|
...entry,
|
|
@@ -3703,18 +3754,36 @@ function parseSize(text) {
|
|
|
3703
3754
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
3704
3755
|
}
|
|
3705
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
|
+
};
|
|
3706
3773
|
function heldUnder(held, target) {
|
|
3707
3774
|
for (const paths of held) for (const path of paths.keys()) if (within2(path, target)) return true;
|
|
3708
3775
|
return false;
|
|
3709
3776
|
}
|
|
3710
3777
|
var HeldPaths = class extends Map {
|
|
3711
3778
|
revoked = /* @__PURE__ */ new Set();
|
|
3779
|
+
onIdle;
|
|
3712
3780
|
hold(path, on) {
|
|
3713
3781
|
const count = (this.get(path) ?? 0) + (on ? 1 : -1);
|
|
3714
3782
|
if (count > 0) this.set(path, count);
|
|
3715
3783
|
else {
|
|
3716
3784
|
this.delete(path);
|
|
3717
3785
|
this.revoked.delete(path);
|
|
3786
|
+
this.onIdle?.(path);
|
|
3718
3787
|
}
|
|
3719
3788
|
}
|
|
3720
3789
|
revoke(prefix) {
|
|
@@ -3782,6 +3851,8 @@ function spliced(bytes, offset, part) {
|
|
|
3782
3851
|
}
|
|
3783
3852
|
var MountTable = class {
|
|
3784
3853
|
mounts = /* @__PURE__ */ new Map();
|
|
3854
|
+
sessions = /* @__PURE__ */ new Map();
|
|
3855
|
+
committing = /* @__PURE__ */ new Map();
|
|
3785
3856
|
devices = 0;
|
|
3786
3857
|
pending = /* @__PURE__ */ new Set();
|
|
3787
3858
|
notes = /* @__PURE__ */ new Map();
|
|
@@ -3906,8 +3977,69 @@ var MountTable = class {
|
|
|
3906
3977
|
if (!detach && this.deps.busy(at)) throw errnoError("EBUSY", `${at} has open files`);
|
|
3907
3978
|
this.notes.delete(at);
|
|
3908
3979
|
this.mounts.delete(at);
|
|
3909
|
-
mount.
|
|
3910
|
-
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
|
+
}
|
|
3911
4043
|
}
|
|
3912
4044
|
crashed(mount, error) {
|
|
3913
4045
|
mount.state = "failed";
|
|
@@ -3966,6 +4098,13 @@ var MountTable = class {
|
|
|
3966
4098
|
return new MountFs(this, base);
|
|
3967
4099
|
}
|
|
3968
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
|
+
}
|
|
3969
4108
|
var MountFs = class {
|
|
3970
4109
|
table;
|
|
3971
4110
|
base;
|
|
@@ -4025,6 +4164,7 @@ var MountFs = class {
|
|
|
4025
4164
|
}
|
|
4026
4165
|
}
|
|
4027
4166
|
async readWhole(mount, real, rel2) {
|
|
4167
|
+
await this.table.commit(real);
|
|
4028
4168
|
const attr = await this.table.getattr(mount, real, rel2);
|
|
4029
4169
|
if (attr.kind === "directory") throw errnoError("EISDIR", real);
|
|
4030
4170
|
if (mount.maxFile > 0 && attr.size > mount.maxFile) {
|
|
@@ -4074,6 +4214,7 @@ var MountFs = class {
|
|
|
4074
4214
|
}
|
|
4075
4215
|
}
|
|
4076
4216
|
async writeWhole(mount, real, rel2, bytes) {
|
|
4217
|
+
await this.table.commit(real);
|
|
4077
4218
|
this.table.forget(mount, real);
|
|
4078
4219
|
const fh = await this.open(mount, rel2, true);
|
|
4079
4220
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
@@ -4096,6 +4237,7 @@ var MountFs = class {
|
|
|
4096
4237
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
4097
4238
|
throw errnoError("EISDIR", real);
|
|
4098
4239
|
}
|
|
4240
|
+
await this.table.commitOverlapping(real, offset, length2);
|
|
4099
4241
|
const fh = await mount.conn.call({
|
|
4100
4242
|
op: "open",
|
|
4101
4243
|
path: rel2,
|
|
@@ -4149,6 +4291,14 @@ var MountFs = class {
|
|
|
4149
4291
|
this.writable(mount, real);
|
|
4150
4292
|
this.fits(mount, real, offset + bytes.length);
|
|
4151
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
|
+
}
|
|
4152
4302
|
const fh = await mount.conn.call({
|
|
4153
4303
|
op: "open",
|
|
4154
4304
|
path: rel2,
|
|
@@ -4157,17 +4307,20 @@ var MountFs = class {
|
|
|
4157
4307
|
truncate: false,
|
|
4158
4308
|
exclusive: false
|
|
4159
4309
|
});
|
|
4160
|
-
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
4161
4310
|
try {
|
|
4162
|
-
|
|
4163
|
-
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
4164
|
-
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
4165
|
-
}
|
|
4311
|
+
await this.writeRuns(mount, fh, offset, bytes, transfer);
|
|
4166
4312
|
} finally {
|
|
4167
4313
|
await mount.conn.call({ op: "release", fh });
|
|
4168
4314
|
this.table.forget(mount, real);
|
|
4169
4315
|
}
|
|
4170
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
|
+
}
|
|
4171
4324
|
async truncate(path, size) {
|
|
4172
4325
|
const real = await this.follow(path);
|
|
4173
4326
|
const found = this.at(real);
|
|
@@ -4179,6 +4332,8 @@ var MountFs = class {
|
|
|
4179
4332
|
this.writable(mount, real);
|
|
4180
4333
|
this.fits(mount, real, size);
|
|
4181
4334
|
this.table.forget(mount, real);
|
|
4335
|
+
const session = this.table.writing(real);
|
|
4336
|
+
if (session) session.truncated = true;
|
|
4182
4337
|
try {
|
|
4183
4338
|
await mount.conn.call({ op: "setattr", path: rel2, size });
|
|
4184
4339
|
} finally {
|
|
@@ -4200,7 +4355,16 @@ var MountFs = class {
|
|
|
4200
4355
|
const found = this.at(path);
|
|
4201
4356
|
if (!found) return this.base.lstat(path);
|
|
4202
4357
|
const real = normalizePath(path);
|
|
4203
|
-
|
|
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);
|
|
4204
4368
|
}
|
|
4205
4369
|
async stat(path) {
|
|
4206
4370
|
const real = await this.follow(path);
|
|
@@ -4227,7 +4391,7 @@ var MountFs = class {
|
|
|
4227
4391
|
list.map(async (entry) => {
|
|
4228
4392
|
const child = normalizePath(`${real}/${entry.name}`);
|
|
4229
4393
|
if (entry.attr && mount.caps.listingStats) {
|
|
4230
|
-
return [entry.name,
|
|
4394
|
+
return [entry.name, this.statWriting(entry.attr, child, mount)];
|
|
4231
4395
|
}
|
|
4232
4396
|
return [entry.name, await this.lstat(child).catch(() => null)];
|
|
4233
4397
|
})
|
|
@@ -4263,6 +4427,7 @@ var MountFs = class {
|
|
|
4263
4427
|
const real = normalizePath(path);
|
|
4264
4428
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
4265
4429
|
this.writable(mount, real);
|
|
4430
|
+
await this.table.commitUnder(real);
|
|
4266
4431
|
let attr;
|
|
4267
4432
|
try {
|
|
4268
4433
|
attr = await this.table.getattr(mount, real, rel2);
|
|
@@ -4286,6 +4451,8 @@ var MountFs = class {
|
|
|
4286
4451
|
if (!a && !b) return this.base.rename(from, to);
|
|
4287
4452
|
if (!a || !b || a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
4288
4453
|
this.writable(a.mount, normalizePath(to));
|
|
4454
|
+
await this.table.commitUnder(from);
|
|
4455
|
+
await this.table.commitUnder(to);
|
|
4289
4456
|
this.table.forget(a.mount, normalizePath(from));
|
|
4290
4457
|
this.table.forget(a.mount, normalizePath(to));
|
|
4291
4458
|
try {
|
|
@@ -7094,6 +7261,7 @@ var VfsNode = class {
|
|
|
7094
7261
|
writeBack;
|
|
7095
7262
|
writeBackCost = 0;
|
|
7096
7263
|
opens = 0;
|
|
7264
|
+
writers = 0;
|
|
7097
7265
|
missing = false;
|
|
7098
7266
|
revoked = false;
|
|
7099
7267
|
fs;
|
|
@@ -7269,8 +7437,10 @@ var VfsNodes = class {
|
|
|
7269
7437
|
byPath = /* @__PURE__ */ new Map();
|
|
7270
7438
|
fs;
|
|
7271
7439
|
entries = /* @__PURE__ */ new Map();
|
|
7272
|
-
|
|
7440
|
+
onClosed;
|
|
7441
|
+
constructor(fs, onClosed) {
|
|
7273
7442
|
this.fs = fs;
|
|
7443
|
+
this.onClosed = onClosed;
|
|
7274
7444
|
}
|
|
7275
7445
|
async onEntry(path, op) {
|
|
7276
7446
|
const key = await this.entryKey(path);
|
|
@@ -7308,16 +7478,17 @@ var VfsNodes = class {
|
|
|
7308
7478
|
await this.fs.writeFile(path, new Uint8Array(0));
|
|
7309
7479
|
});
|
|
7310
7480
|
}
|
|
7311
|
-
open(path, pin) {
|
|
7481
|
+
open(path, pin, writable = false) {
|
|
7312
7482
|
let node = this.byPath.get(path);
|
|
7313
7483
|
if (!node) {
|
|
7314
7484
|
node = new VfsNode(this.fs, path, void 0, false, false, pin);
|
|
7315
7485
|
this.byPath.set(path, node);
|
|
7316
7486
|
}
|
|
7317
7487
|
node.opens++;
|
|
7488
|
+
if (writable) node.writers++;
|
|
7318
7489
|
return node;
|
|
7319
7490
|
}
|
|
7320
|
-
adopt(path, contents2, dirty) {
|
|
7491
|
+
adopt(path, contents2, dirty, writable = false) {
|
|
7321
7492
|
let node = this.byPath.get(path);
|
|
7322
7493
|
if (!node) {
|
|
7323
7494
|
node = new VfsNode(this.fs, path, contents2, false, dirty);
|
|
@@ -7326,15 +7497,27 @@ var VfsNodes = class {
|
|
|
7326
7497
|
node.replace(contents2);
|
|
7327
7498
|
}
|
|
7328
7499
|
node.opens++;
|
|
7500
|
+
if (writable) node.writers++;
|
|
7329
7501
|
return node;
|
|
7330
7502
|
}
|
|
7331
7503
|
holds(prefix) {
|
|
7332
7504
|
for (const path of this.byPath.keys()) if (within4(path, prefix)) return true;
|
|
7333
7505
|
return false;
|
|
7334
7506
|
}
|
|
7335
|
-
|
|
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) {
|
|
7336
7513
|
node.opens--;
|
|
7337
|
-
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);
|
|
7338
7521
|
}
|
|
7339
7522
|
async flush(path) {
|
|
7340
7523
|
for (const [p, node] of this.byPath) if (within4(p, path)) await node.serial(() => node.flush());
|
|
@@ -7480,7 +7663,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7480
7663
|
const access = opts.flags & O_ACCMODE;
|
|
7481
7664
|
const readable = access !== O_WRONLY;
|
|
7482
7665
|
const writable = access === O_WRONLY || access === O_RDWR;
|
|
7483
|
-
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);
|
|
7484
7667
|
let openError;
|
|
7485
7668
|
const atOpen = (op) => {
|
|
7486
7669
|
void node.serial(op).catch((err) => {
|
|
@@ -7543,7 +7726,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7543
7726
|
takeOpenError();
|
|
7544
7727
|
await node.flush();
|
|
7545
7728
|
} finally {
|
|
7546
|
-
nodes?.closed(node);
|
|
7729
|
+
nodes?.closed(node, writable);
|
|
7547
7730
|
}
|
|
7548
7731
|
})
|
|
7549
7732
|
});
|
|
@@ -8890,7 +9073,11 @@ function mediumSlot(lost, onLost) {
|
|
|
8890
9073
|
}
|
|
8891
9074
|
|
|
8892
9075
|
// src/mount/fsa.ts
|
|
8893
|
-
var FSA_CAPABILITIES = {
|
|
9076
|
+
var FSA_CAPABILITIES = {
|
|
9077
|
+
listingStats: true,
|
|
9078
|
+
ranges: true,
|
|
9079
|
+
sessions: true
|
|
9080
|
+
};
|
|
8894
9081
|
var codeOf2 = (err) => err?.code;
|
|
8895
9082
|
var denied = (err) => codeOf2(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
8896
9083
|
function attrOf(st) {
|
|
@@ -8930,30 +9117,20 @@ function kernelFsHandlers(fs) {
|
|
|
8930
9117
|
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
8931
9118
|
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
8932
9119
|
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
8933
|
-
|
|
8934
|
-
handles.set(++nextFh, { path
|
|
9120
|
+
if (!st || flags.truncate) await fs.writeFile(path, new Uint8Array(0));
|
|
9121
|
+
handles.set(++nextFh, { path });
|
|
8935
9122
|
return nextFh;
|
|
8936
9123
|
},
|
|
8937
|
-
async
|
|
8938
|
-
const h = handle(fh);
|
|
8939
|
-
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
8940
|
-
},
|
|
9124
|
+
read: async (fh, offset, size) => fs.pread(handle(fh).path, offset, size),
|
|
8941
9125
|
async write(fh, offset, bytes) {
|
|
8942
9126
|
const h = handle(fh);
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
const grown = new Uint8Array(Math.max(end, h.data.length * 2));
|
|
8946
|
-
grown.set(h.data.subarray(0, h.length));
|
|
8947
|
-
h.data = grown;
|
|
8948
|
-
}
|
|
8949
|
-
h.data.set(bytes, offset);
|
|
8950
|
-
h.length = Math.max(h.length, end);
|
|
8951
|
-
h.dirty = true;
|
|
9127
|
+
h.session ??= fs.writeSession(h.path, false);
|
|
9128
|
+
await (await h.session).write(offset, bytes);
|
|
8952
9129
|
},
|
|
8953
9130
|
async release(fh) {
|
|
8954
9131
|
const h = handle(fh);
|
|
8955
9132
|
handles.delete(fh);
|
|
8956
|
-
if (h.
|
|
9133
|
+
if (h.session !== void 0) await (await h.session).close();
|
|
8957
9134
|
},
|
|
8958
9135
|
mkdir: (path) => fs.mkdir(path),
|
|
8959
9136
|
async rmdir(path) {
|
|
@@ -8969,6 +9146,13 @@ function kernelFsHandlers(fs) {
|
|
|
8969
9146
|
symlink: (target, path) => fs.symlink(target, path),
|
|
8970
9147
|
readlink: (path) => fs.readlink(path),
|
|
8971
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
|
+
}
|
|
8972
9156
|
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
8973
9157
|
if (change.mtime !== void 0) {
|
|
8974
9158
|
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
@@ -9693,6 +9877,7 @@ function tmpfs() {
|
|
|
9693
9877
|
const { dir, name: name2 } = parent(path);
|
|
9694
9878
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
9695
9879
|
dir.children.set(name2, make("directory", 16877));
|
|
9880
|
+
dir.mtime = Date.now();
|
|
9696
9881
|
},
|
|
9697
9882
|
async rmdir(path) {
|
|
9698
9883
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9701,6 +9886,7 @@ function tmpfs() {
|
|
|
9701
9886
|
if (node.kind !== "directory") throw fsError2("ENOTDIR", path);
|
|
9702
9887
|
if (node.children.size > 0) throw fsError2("ENOTEMPTY", path);
|
|
9703
9888
|
dir.children.delete(name2);
|
|
9889
|
+
dir.mtime = Date.now();
|
|
9704
9890
|
},
|
|
9705
9891
|
async unlink(path) {
|
|
9706
9892
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9708,6 +9894,7 @@ function tmpfs() {
|
|
|
9708
9894
|
if (!node) throw fsError2("ENOENT", path);
|
|
9709
9895
|
if (node.kind === "directory") throw fsError2("EISDIR", path);
|
|
9710
9896
|
dir.children.delete(name2);
|
|
9897
|
+
dir.mtime = Date.now();
|
|
9711
9898
|
},
|
|
9712
9899
|
async rename(from, to) {
|
|
9713
9900
|
const a = `/${parts(from).join("/")}`;
|
|
@@ -9724,6 +9911,8 @@ function tmpfs() {
|
|
|
9724
9911
|
}
|
|
9725
9912
|
source.dir.children.delete(source.name);
|
|
9726
9913
|
target.dir.children.set(target.name, node);
|
|
9914
|
+
source.dir.mtime = Date.now();
|
|
9915
|
+
target.dir.mtime = source.dir.mtime;
|
|
9727
9916
|
},
|
|
9728
9917
|
async symlink(target, path) {
|
|
9729
9918
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9731,6 +9920,7 @@ function tmpfs() {
|
|
|
9731
9920
|
const node = make("symlink", 41471);
|
|
9732
9921
|
node.target = target;
|
|
9733
9922
|
dir.children.set(name2, node);
|
|
9923
|
+
dir.mtime = Date.now();
|
|
9734
9924
|
},
|
|
9735
9925
|
async readlink(path) {
|
|
9736
9926
|
const node = find(path);
|
|
@@ -10029,7 +10219,7 @@ var Launcher = class {
|
|
|
10029
10219
|
deciding = /* @__PURE__ */ new Map();
|
|
10030
10220
|
identities = { asked: 0, timedOut: 0 };
|
|
10031
10221
|
nodes;
|
|
10032
|
-
held =
|
|
10222
|
+
held = new HeldSet((path) => this.released(path));
|
|
10033
10223
|
processMounts;
|
|
10034
10224
|
booting = new AbortController();
|
|
10035
10225
|
fstab = Promise.resolve([]);
|
|
@@ -10071,7 +10261,7 @@ var Launcher = class {
|
|
|
10071
10261
|
});
|
|
10072
10262
|
enableCdp(this.net, this.cdp);
|
|
10073
10263
|
const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
10074
|
-
this.nodes = new VfsNodes(fs);
|
|
10264
|
+
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
10075
10265
|
this.openFiles.add(this.nodes);
|
|
10076
10266
|
this.fs = keepingOpen(fs, this.nodes);
|
|
10077
10267
|
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
@@ -10433,6 +10623,11 @@ var Launcher = class {
|
|
|
10433
10623
|
umaskOf(pid) {
|
|
10434
10624
|
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
10435
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
|
+
}
|
|
10436
10631
|
ignoredBy(pid, fork = false) {
|
|
10437
10632
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
10438
10633
|
}
|