@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/kernel-worker.js
CHANGED
|
@@ -448,11 +448,41 @@ var OpfsFs = class {
|
|
|
448
448
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
449
449
|
return (directory ? S_IFDIR : S_IFREG) | (meta?.mode ?? fallback);
|
|
450
450
|
}
|
|
451
|
+
dirTimes = /* @__PURE__ */ new Map();
|
|
452
|
+
dirDirty = /* @__PURE__ */ new Set();
|
|
453
|
+
dirFlush;
|
|
454
|
+
touch(...dirs) {
|
|
455
|
+
const now = Date.now();
|
|
456
|
+
for (const dir of dirs) {
|
|
457
|
+
this.dirTimes.set(dir, now);
|
|
458
|
+
this.dirDirty.add(dir);
|
|
459
|
+
}
|
|
460
|
+
this.dirFlush ??= Promise.resolve().then(() => this.flushDirTimes()).catch(() => void 0).finally(() => {
|
|
461
|
+
this.dirFlush = void 0;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
async flushDirTimes() {
|
|
465
|
+
for (const path of this.dirDirty) {
|
|
466
|
+
this.dirDirty.delete(path);
|
|
467
|
+
const ms = this.dirTimes.get(path);
|
|
468
|
+
if (ms === void 0) continue;
|
|
469
|
+
await this.meta.update(path, (entry) => ({
|
|
470
|
+
...entry,
|
|
471
|
+
path,
|
|
472
|
+
mtimeMs: ms,
|
|
473
|
+
mtimeFor: 0,
|
|
474
|
+
ctimeMs: ms
|
|
475
|
+
}));
|
|
476
|
+
if (this.dirTimes.get(path) === ms) this.dirTimes.delete(path);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
451
479
|
async statOf(path, handle, meta) {
|
|
452
480
|
const directory = handle.kind === "directory";
|
|
453
481
|
const file = directory ? void 0 : await handle.getFile();
|
|
454
482
|
const modified = file?.lastModified ?? 0;
|
|
455
|
-
const
|
|
483
|
+
const touched = directory ? this.dirTimes.get(path) : void 0;
|
|
484
|
+
const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
|
|
485
|
+
const mtime = touched ?? kept;
|
|
456
486
|
return {
|
|
457
487
|
isFile: !directory,
|
|
458
488
|
isDirectory: directory,
|
|
@@ -461,7 +491,7 @@ var OpfsFs = class {
|
|
|
461
491
|
mode: this.mode(path, directory, meta),
|
|
462
492
|
mtime: new Date(mtime),
|
|
463
493
|
atime: new Date(meta?.atimeMs ?? mtime),
|
|
464
|
-
ctime: new Date(Math.max(meta?.ctimeMs ?? mtime, modified)),
|
|
494
|
+
ctime: new Date(Math.max(touched ?? meta?.ctimeMs ?? mtime, modified)),
|
|
465
495
|
ino: meta?.ino ?? inodeOf(path),
|
|
466
496
|
...this.ranged && !directory ? { ranged: true } : {}
|
|
467
497
|
};
|
|
@@ -538,6 +568,19 @@ var OpfsFs = class {
|
|
|
538
568
|
const handle = await this.existing(path);
|
|
539
569
|
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
540
570
|
}
|
|
571
|
+
async writeSession(path, truncate) {
|
|
572
|
+
const handle = (await this.fileFor(path))[0];
|
|
573
|
+
const writable = await this.retrying(
|
|
574
|
+
path,
|
|
575
|
+
() => handle.createWritable({ keepExistingData: !truncate }),
|
|
576
|
+
true
|
|
577
|
+
);
|
|
578
|
+
return {
|
|
579
|
+
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes }),
|
|
580
|
+
truncate: (size) => writable.truncate(size),
|
|
581
|
+
close: () => writable.close()
|
|
582
|
+
};
|
|
583
|
+
}
|
|
541
584
|
async readFile(path) {
|
|
542
585
|
return new TextDecoder().decode(await this.readFileBuffer(path));
|
|
543
586
|
}
|
|
@@ -555,10 +598,12 @@ var OpfsFs = class {
|
|
|
555
598
|
const [target, existed] = await this.writeTarget(path);
|
|
556
599
|
const [dir, name2] = await this.parent(target);
|
|
557
600
|
try {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
601
|
+
const handle = await this.inDir(
|
|
602
|
+
dir,
|
|
603
|
+
(parent) => parent.getFileHandle(name2, { create: true })
|
|
604
|
+
);
|
|
605
|
+
if (!existed) this.touch(parentOf2(target));
|
|
606
|
+
return [handle, existed];
|
|
562
607
|
} catch (err) {
|
|
563
608
|
const code = err?.name === "TypeMismatchError" ? "EISDIR" : null;
|
|
564
609
|
throw code ? fsError(code, path) : translate(err, path);
|
|
@@ -616,6 +661,7 @@ var OpfsFs = class {
|
|
|
616
661
|
const parent = await this.locate(parentOf2(path), true);
|
|
617
662
|
if (parent.handle?.kind !== "directory") throw fsError("ENOTDIR", path);
|
|
618
663
|
await parent.handle.getDirectoryHandle(baseOf(path), { create: true });
|
|
664
|
+
this.touch(parent.path);
|
|
619
665
|
}
|
|
620
666
|
async rm(path, options = {}) {
|
|
621
667
|
let found;
|
|
@@ -639,6 +685,7 @@ var OpfsFs = class {
|
|
|
639
685
|
this.changed(found.path);
|
|
640
686
|
}
|
|
641
687
|
await this.meta.remove([found.path]);
|
|
688
|
+
this.touch(parentOf2(found.path));
|
|
642
689
|
}
|
|
643
690
|
async rename(from, to) {
|
|
644
691
|
if (from === to) return;
|
|
@@ -670,6 +717,7 @@ var OpfsFs = class {
|
|
|
670
717
|
if (source.link) {
|
|
671
718
|
if (target?.handle) await this.rm(destination);
|
|
672
719
|
await this.meta.move(source.path, destination, carry);
|
|
720
|
+
this.touch(parentOf2(source.path), parent.path);
|
|
673
721
|
return;
|
|
674
722
|
}
|
|
675
723
|
const dir = parent.handle;
|
|
@@ -691,6 +739,7 @@ var OpfsFs = class {
|
|
|
691
739
|
}
|
|
692
740
|
if (copied) await this.restamp(destination, timed);
|
|
693
741
|
this.changed(source.path, destination);
|
|
742
|
+
this.touch(parentOf2(source.path), parent.path);
|
|
694
743
|
}
|
|
695
744
|
async modified(path) {
|
|
696
745
|
const handle = await this.handle(path);
|
|
@@ -754,6 +803,7 @@ var OpfsFs = class {
|
|
|
754
803
|
mtimeMs: now,
|
|
755
804
|
ctimeMs: now
|
|
756
805
|
}));
|
|
806
|
+
this.touch(parent.path);
|
|
757
807
|
}
|
|
758
808
|
async realpath(path, follow) {
|
|
759
809
|
return (await this.locate(path, follow)).path;
|
|
@@ -794,6 +844,7 @@ var OpfsFs = class {
|
|
|
794
844
|
}
|
|
795
845
|
const handle = found.handle;
|
|
796
846
|
const file = handle.kind === "file" ? await handle.getFile() : void 0;
|
|
847
|
+
this.dirTimes.delete(found.path);
|
|
797
848
|
const ctimeMs = Date.now();
|
|
798
849
|
await this.meta.update(found.path, (entry) => ({
|
|
799
850
|
...entry,
|
|
@@ -5187,18 +5238,36 @@ function parseSize(text) {
|
|
|
5187
5238
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
5188
5239
|
}
|
|
5189
5240
|
var within3 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
5241
|
+
var HeldSet = class extends Set {
|
|
5242
|
+
idle;
|
|
5243
|
+
constructor(idle) {
|
|
5244
|
+
super();
|
|
5245
|
+
this.idle = idle;
|
|
5246
|
+
}
|
|
5247
|
+
add(holds) {
|
|
5248
|
+
holds.onIdle = this.idle;
|
|
5249
|
+
return super.add(holds);
|
|
5250
|
+
}
|
|
5251
|
+
delete(holds) {
|
|
5252
|
+
const removed = super.delete(holds);
|
|
5253
|
+
for (const path of holds.keys()) this.idle(path);
|
|
5254
|
+
return removed;
|
|
5255
|
+
}
|
|
5256
|
+
};
|
|
5190
5257
|
function heldUnder(held, target) {
|
|
5191
5258
|
for (const paths of held) for (const path of paths.keys()) if (within3(path, target)) return true;
|
|
5192
5259
|
return false;
|
|
5193
5260
|
}
|
|
5194
5261
|
var HeldPaths = class extends Map {
|
|
5195
5262
|
revoked = /* @__PURE__ */ new Set();
|
|
5263
|
+
onIdle;
|
|
5196
5264
|
hold(path, on) {
|
|
5197
5265
|
const count = (this.get(path) ?? 0) + (on ? 1 : -1);
|
|
5198
5266
|
if (count > 0) this.set(path, count);
|
|
5199
5267
|
else {
|
|
5200
5268
|
this.delete(path);
|
|
5201
5269
|
this.revoked.delete(path);
|
|
5270
|
+
this.onIdle?.(path);
|
|
5202
5271
|
}
|
|
5203
5272
|
}
|
|
5204
5273
|
revoke(prefix) {
|
|
@@ -5266,6 +5335,8 @@ function spliced(bytes, offset, part) {
|
|
|
5266
5335
|
}
|
|
5267
5336
|
var MountTable = class {
|
|
5268
5337
|
mounts = /* @__PURE__ */ new Map();
|
|
5338
|
+
sessions = /* @__PURE__ */ new Map();
|
|
5339
|
+
committing = /* @__PURE__ */ new Map();
|
|
5269
5340
|
devices = 0;
|
|
5270
5341
|
pending = /* @__PURE__ */ new Set();
|
|
5271
5342
|
notes = /* @__PURE__ */ new Map();
|
|
@@ -5390,8 +5461,69 @@ var MountTable = class {
|
|
|
5390
5461
|
if (!detach && this.deps.busy(at)) throw errnoError("EBUSY", `${at} has open files`);
|
|
5391
5462
|
this.notes.delete(at);
|
|
5392
5463
|
this.mounts.delete(at);
|
|
5393
|
-
mount.
|
|
5394
|
-
mount.
|
|
5464
|
+
const waits = [...this.sessions].filter(([, s]) => s.mount === mount).map(([real]) => this.commit(real));
|
|
5465
|
+
for (const c of this.committing.values()) if (c.mount === mount) waits.push(c.done);
|
|
5466
|
+
const close = () => {
|
|
5467
|
+
mount.conn.close();
|
|
5468
|
+
mount.dispose();
|
|
5469
|
+
};
|
|
5470
|
+
if (waits.length === 0) close();
|
|
5471
|
+
else void Promise.allSettled(waits).then(close);
|
|
5472
|
+
}
|
|
5473
|
+
session(mount, real, rel2) {
|
|
5474
|
+
let session = this.sessions.get(real);
|
|
5475
|
+
if (!session) {
|
|
5476
|
+
const open = () => mount.conn.call({
|
|
5477
|
+
op: "open",
|
|
5478
|
+
path: rel2,
|
|
5479
|
+
write: true,
|
|
5480
|
+
create: true,
|
|
5481
|
+
truncate: false,
|
|
5482
|
+
exclusive: false
|
|
5483
|
+
});
|
|
5484
|
+
const before = this.committing.get(real)?.done ?? Promise.resolve();
|
|
5485
|
+
const fh = before.then(open, open);
|
|
5486
|
+
session = { mount, fh, extents: [], truncated: false };
|
|
5487
|
+
this.sessions.set(real, session);
|
|
5488
|
+
fh.catch(() => this.sessions.delete(real));
|
|
5489
|
+
}
|
|
5490
|
+
return session;
|
|
5491
|
+
}
|
|
5492
|
+
writing(real) {
|
|
5493
|
+
return this.sessions.get(real);
|
|
5494
|
+
}
|
|
5495
|
+
async commit(real) {
|
|
5496
|
+
const session = this.sessions.get(real);
|
|
5497
|
+
if (!session) return this.committing.get(real)?.done;
|
|
5498
|
+
this.sessions.delete(real);
|
|
5499
|
+
const done4 = (async () => {
|
|
5500
|
+
try {
|
|
5501
|
+
await session.mount.conn.call({ op: "release", fh: await session.fh });
|
|
5502
|
+
} finally {
|
|
5503
|
+
this.forget(session.mount, real);
|
|
5504
|
+
}
|
|
5505
|
+
})();
|
|
5506
|
+
const entry = { mount: session.mount, done: done4 };
|
|
5507
|
+
this.committing.set(real, entry);
|
|
5508
|
+
const settle3 = () => {
|
|
5509
|
+
if (this.committing.get(real) === entry) this.committing.delete(real);
|
|
5510
|
+
};
|
|
5511
|
+
done4.then(settle3, settle3);
|
|
5512
|
+
return done4;
|
|
5513
|
+
}
|
|
5514
|
+
async commitUnder(prefix) {
|
|
5515
|
+
const at = normalizePath(prefix);
|
|
5516
|
+
await Promise.all(
|
|
5517
|
+
[...this.sessions.keys()].filter((p) => within3(p, at)).map((p) => this.commit(p))
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
async commitOverlapping(real, offset, length2) {
|
|
5521
|
+
const session = this.sessions.get(real);
|
|
5522
|
+
if (!session) return;
|
|
5523
|
+
const end = offset + length2;
|
|
5524
|
+
if (session.truncated || session.extents.some(([a, b]) => a < end && offset < b)) {
|
|
5525
|
+
await this.commit(real);
|
|
5526
|
+
}
|
|
5395
5527
|
}
|
|
5396
5528
|
crashed(mount, error) {
|
|
5397
5529
|
mount.state = "failed";
|
|
@@ -5450,6 +5582,13 @@ var MountTable = class {
|
|
|
5450
5582
|
return new MountFs(this, base);
|
|
5451
5583
|
}
|
|
5452
5584
|
};
|
|
5585
|
+
function noteExtent(extents, from, to) {
|
|
5586
|
+
const last = extents.at(-1);
|
|
5587
|
+
if (last && from <= last[1] && to >= last[0]) {
|
|
5588
|
+
last[0] = Math.min(last[0], from);
|
|
5589
|
+
last[1] = Math.max(last[1], to);
|
|
5590
|
+
} else extents.push([from, to]);
|
|
5591
|
+
}
|
|
5453
5592
|
var MountFs = class {
|
|
5454
5593
|
table;
|
|
5455
5594
|
base;
|
|
@@ -5509,6 +5648,7 @@ var MountFs = class {
|
|
|
5509
5648
|
}
|
|
5510
5649
|
}
|
|
5511
5650
|
async readWhole(mount, real, rel2) {
|
|
5651
|
+
await this.table.commit(real);
|
|
5512
5652
|
const attr = await this.table.getattr(mount, real, rel2);
|
|
5513
5653
|
if (attr.kind === "directory") throw errnoError("EISDIR", real);
|
|
5514
5654
|
if (mount.maxFile > 0 && attr.size > mount.maxFile) {
|
|
@@ -5558,6 +5698,7 @@ var MountFs = class {
|
|
|
5558
5698
|
}
|
|
5559
5699
|
}
|
|
5560
5700
|
async writeWhole(mount, real, rel2, bytes) {
|
|
5701
|
+
await this.table.commit(real);
|
|
5561
5702
|
this.table.forget(mount, real);
|
|
5562
5703
|
const fh = await this.open(mount, rel2, true);
|
|
5563
5704
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
@@ -5580,6 +5721,7 @@ var MountFs = class {
|
|
|
5580
5721
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
5581
5722
|
throw errnoError("EISDIR", real);
|
|
5582
5723
|
}
|
|
5724
|
+
await this.table.commitOverlapping(real, offset, length2);
|
|
5583
5725
|
const fh = await mount.conn.call({
|
|
5584
5726
|
op: "open",
|
|
5585
5727
|
path: rel2,
|
|
@@ -5633,6 +5775,14 @@ var MountFs = class {
|
|
|
5633
5775
|
this.writable(mount, real);
|
|
5634
5776
|
this.fits(mount, real, offset + bytes.length);
|
|
5635
5777
|
this.table.forget(mount, real);
|
|
5778
|
+
if (mount.caps.sessions) {
|
|
5779
|
+
const session = this.table.session(mount, real, rel2);
|
|
5780
|
+
const end = offset + bytes.length;
|
|
5781
|
+
await this.writeRuns(mount, await session.fh, offset, bytes, transfer);
|
|
5782
|
+
noteExtent(session.extents, offset, end);
|
|
5783
|
+
this.table.forget(mount, real);
|
|
5784
|
+
return;
|
|
5785
|
+
}
|
|
5636
5786
|
const fh = await mount.conn.call({
|
|
5637
5787
|
op: "open",
|
|
5638
5788
|
path: rel2,
|
|
@@ -5641,17 +5791,20 @@ var MountFs = class {
|
|
|
5641
5791
|
truncate: false,
|
|
5642
5792
|
exclusive: false
|
|
5643
5793
|
});
|
|
5644
|
-
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5645
5794
|
try {
|
|
5646
|
-
|
|
5647
|
-
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
5648
|
-
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
5649
|
-
}
|
|
5795
|
+
await this.writeRuns(mount, fh, offset, bytes, transfer);
|
|
5650
5796
|
} finally {
|
|
5651
5797
|
await mount.conn.call({ op: "release", fh });
|
|
5652
5798
|
this.table.forget(mount, real);
|
|
5653
5799
|
}
|
|
5654
5800
|
}
|
|
5801
|
+
async writeRuns(mount, fh, offset, bytes, transfer) {
|
|
5802
|
+
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5803
|
+
for (let at = 0; at < bytes.length; at += chunk2) {
|
|
5804
|
+
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
5805
|
+
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5655
5808
|
async truncate(path, size) {
|
|
5656
5809
|
const real = await this.follow(path);
|
|
5657
5810
|
const found = this.at(real);
|
|
@@ -5663,6 +5816,8 @@ var MountFs = class {
|
|
|
5663
5816
|
this.writable(mount, real);
|
|
5664
5817
|
this.fits(mount, real, size);
|
|
5665
5818
|
this.table.forget(mount, real);
|
|
5819
|
+
const session = this.table.writing(real);
|
|
5820
|
+
if (session) session.truncated = true;
|
|
5666
5821
|
try {
|
|
5667
5822
|
await mount.conn.call({ op: "setattr", path: rel2, size });
|
|
5668
5823
|
} finally {
|
|
@@ -5684,7 +5839,16 @@ var MountFs = class {
|
|
|
5684
5839
|
const found = this.at(path);
|
|
5685
5840
|
if (!found) return this.base.lstat(path);
|
|
5686
5841
|
const real = normalizePath(path);
|
|
5687
|
-
|
|
5842
|
+
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
5843
|
+
return this.statWriting(
|
|
5844
|
+
await this.table.getattr(found.mount, real, found.rel),
|
|
5845
|
+
real,
|
|
5846
|
+
found.mount
|
|
5847
|
+
);
|
|
5848
|
+
}
|
|
5849
|
+
statWriting(attr, real, mount) {
|
|
5850
|
+
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
5851
|
+
return statOf({ ...attr, size: Math.max(attr.size, ...ends) }, real, mount);
|
|
5688
5852
|
}
|
|
5689
5853
|
async stat(path) {
|
|
5690
5854
|
const real = await this.follow(path);
|
|
@@ -5711,7 +5875,7 @@ var MountFs = class {
|
|
|
5711
5875
|
list.map(async (entry) => {
|
|
5712
5876
|
const child = normalizePath(`${real}/${entry.name}`);
|
|
5713
5877
|
if (entry.attr && mount.caps.listingStats) {
|
|
5714
|
-
return [entry.name,
|
|
5878
|
+
return [entry.name, this.statWriting(entry.attr, child, mount)];
|
|
5715
5879
|
}
|
|
5716
5880
|
return [entry.name, await this.lstat(child).catch(() => null)];
|
|
5717
5881
|
})
|
|
@@ -5747,6 +5911,7 @@ var MountFs = class {
|
|
|
5747
5911
|
const real = normalizePath(path);
|
|
5748
5912
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
5749
5913
|
this.writable(mount, real);
|
|
5914
|
+
await this.table.commitUnder(real);
|
|
5750
5915
|
let attr;
|
|
5751
5916
|
try {
|
|
5752
5917
|
attr = await this.table.getattr(mount, real, rel2);
|
|
@@ -5770,6 +5935,8 @@ var MountFs = class {
|
|
|
5770
5935
|
if (!a && !b) return this.base.rename(from, to);
|
|
5771
5936
|
if (!a || !b || a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
5772
5937
|
this.writable(a.mount, normalizePath(to));
|
|
5938
|
+
await this.table.commitUnder(from);
|
|
5939
|
+
await this.table.commitUnder(to);
|
|
5773
5940
|
this.table.forget(a.mount, normalizePath(from));
|
|
5774
5941
|
this.table.forget(a.mount, normalizePath(to));
|
|
5775
5942
|
try {
|
|
@@ -7376,6 +7543,7 @@ var VfsNode = class {
|
|
|
7376
7543
|
writeBack;
|
|
7377
7544
|
writeBackCost = 0;
|
|
7378
7545
|
opens = 0;
|
|
7546
|
+
writers = 0;
|
|
7379
7547
|
missing = false;
|
|
7380
7548
|
revoked = false;
|
|
7381
7549
|
fs;
|
|
@@ -7551,8 +7719,10 @@ var VfsNodes = class {
|
|
|
7551
7719
|
byPath = /* @__PURE__ */ new Map();
|
|
7552
7720
|
fs;
|
|
7553
7721
|
entries = /* @__PURE__ */ new Map();
|
|
7554
|
-
|
|
7722
|
+
onClosed;
|
|
7723
|
+
constructor(fs, onClosed) {
|
|
7555
7724
|
this.fs = fs;
|
|
7725
|
+
this.onClosed = onClosed;
|
|
7556
7726
|
}
|
|
7557
7727
|
async onEntry(path, op) {
|
|
7558
7728
|
const key = await this.entryKey(path);
|
|
@@ -7590,16 +7760,17 @@ var VfsNodes = class {
|
|
|
7590
7760
|
await this.fs.writeFile(path, new Uint8Array(0));
|
|
7591
7761
|
});
|
|
7592
7762
|
}
|
|
7593
|
-
open(path, pin) {
|
|
7763
|
+
open(path, pin, writable = false) {
|
|
7594
7764
|
let node = this.byPath.get(path);
|
|
7595
7765
|
if (!node) {
|
|
7596
7766
|
node = new VfsNode(this.fs, path, void 0, false, false, pin);
|
|
7597
7767
|
this.byPath.set(path, node);
|
|
7598
7768
|
}
|
|
7599
7769
|
node.opens++;
|
|
7770
|
+
if (writable) node.writers++;
|
|
7600
7771
|
return node;
|
|
7601
7772
|
}
|
|
7602
|
-
adopt(path, contents2, dirty) {
|
|
7773
|
+
adopt(path, contents2, dirty, writable = false) {
|
|
7603
7774
|
let node = this.byPath.get(path);
|
|
7604
7775
|
if (!node) {
|
|
7605
7776
|
node = new VfsNode(this.fs, path, contents2, false, dirty);
|
|
@@ -7608,15 +7779,27 @@ var VfsNodes = class {
|
|
|
7608
7779
|
node.replace(contents2);
|
|
7609
7780
|
}
|
|
7610
7781
|
node.opens++;
|
|
7782
|
+
if (writable) node.writers++;
|
|
7611
7783
|
return node;
|
|
7612
7784
|
}
|
|
7613
7785
|
holds(prefix) {
|
|
7614
7786
|
for (const path of this.byPath.keys()) if (within4(path, prefix)) return true;
|
|
7615
7787
|
return false;
|
|
7616
7788
|
}
|
|
7617
|
-
|
|
7789
|
+
writes(prefix) {
|
|
7790
|
+
for (const [path, node] of this.byPath)
|
|
7791
|
+
if (node.writers > 0 && within4(path, prefix)) return true;
|
|
7792
|
+
return false;
|
|
7793
|
+
}
|
|
7794
|
+
closed(node, writable = false) {
|
|
7618
7795
|
node.opens--;
|
|
7619
|
-
if (
|
|
7796
|
+
if (writable) node.writers--;
|
|
7797
|
+
if (node.opens > 0) {
|
|
7798
|
+
if (writable && node.writers === 0) this.onClosed?.(node.path);
|
|
7799
|
+
return;
|
|
7800
|
+
}
|
|
7801
|
+
if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
|
|
7802
|
+
this.onClosed?.(node.path);
|
|
7620
7803
|
}
|
|
7621
7804
|
async flush(path) {
|
|
7622
7805
|
for (const [p, node] of this.byPath) if (within4(p, path)) await node.serial(() => node.flush());
|
|
@@ -7762,7 +7945,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7762
7945
|
const access = opts.flags & O_ACCMODE;
|
|
7763
7946
|
const readable = access !== O_WRONLY;
|
|
7764
7947
|
const writable = access === O_WRONLY || access === O_RDWR;
|
|
7765
|
-
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);
|
|
7948
|
+
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);
|
|
7766
7949
|
let openError;
|
|
7767
7950
|
const atOpen = (op) => {
|
|
7768
7951
|
void node.serial(op).catch((err) => {
|
|
@@ -7825,7 +8008,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7825
8008
|
takeOpenError();
|
|
7826
8009
|
await node.flush();
|
|
7827
8010
|
} finally {
|
|
7828
|
-
nodes?.closed(node);
|
|
8011
|
+
nodes?.closed(node, writable);
|
|
7829
8012
|
}
|
|
7830
8013
|
})
|
|
7831
8014
|
});
|
|
@@ -9172,7 +9355,11 @@ function mediumSlot(lost, onLost) {
|
|
|
9172
9355
|
}
|
|
9173
9356
|
|
|
9174
9357
|
// src/mount/fsa.ts
|
|
9175
|
-
var FSA_CAPABILITIES = {
|
|
9358
|
+
var FSA_CAPABILITIES = {
|
|
9359
|
+
listingStats: true,
|
|
9360
|
+
ranges: true,
|
|
9361
|
+
sessions: true
|
|
9362
|
+
};
|
|
9176
9363
|
var codeOf2 = (err) => err?.code;
|
|
9177
9364
|
var denied = (err) => codeOf2(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
9178
9365
|
function attrOf(st) {
|
|
@@ -9212,30 +9399,20 @@ function kernelFsHandlers(fs) {
|
|
|
9212
9399
|
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
9213
9400
|
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
9214
9401
|
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
9215
|
-
|
|
9216
|
-
handles.set(++nextFh, { path
|
|
9402
|
+
if (!st || flags.truncate) await fs.writeFile(path, new Uint8Array(0));
|
|
9403
|
+
handles.set(++nextFh, { path });
|
|
9217
9404
|
return nextFh;
|
|
9218
9405
|
},
|
|
9219
|
-
async
|
|
9220
|
-
const h = handle(fh);
|
|
9221
|
-
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
9222
|
-
},
|
|
9406
|
+
read: async (fh, offset, size) => fs.pread(handle(fh).path, offset, size),
|
|
9223
9407
|
async write(fh, offset, bytes) {
|
|
9224
9408
|
const h = handle(fh);
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
const grown = new Uint8Array(Math.max(end, h.data.length * 2));
|
|
9228
|
-
grown.set(h.data.subarray(0, h.length));
|
|
9229
|
-
h.data = grown;
|
|
9230
|
-
}
|
|
9231
|
-
h.data.set(bytes, offset);
|
|
9232
|
-
h.length = Math.max(h.length, end);
|
|
9233
|
-
h.dirty = true;
|
|
9409
|
+
h.session ??= fs.writeSession(h.path, false);
|
|
9410
|
+
await (await h.session).write(offset, bytes);
|
|
9234
9411
|
},
|
|
9235
9412
|
async release(fh) {
|
|
9236
9413
|
const h = handle(fh);
|
|
9237
9414
|
handles.delete(fh);
|
|
9238
|
-
if (h.
|
|
9415
|
+
if (h.session !== void 0) await (await h.session).close();
|
|
9239
9416
|
},
|
|
9240
9417
|
mkdir: (path) => fs.mkdir(path),
|
|
9241
9418
|
async rmdir(path) {
|
|
@@ -9251,6 +9428,13 @@ function kernelFsHandlers(fs) {
|
|
|
9251
9428
|
symlink: (target, path) => fs.symlink(target, path),
|
|
9252
9429
|
readlink: (path) => fs.readlink(path),
|
|
9253
9430
|
async setattr(path, change) {
|
|
9431
|
+
if (change.size !== void 0) {
|
|
9432
|
+
const open = [...handles.values()].find(
|
|
9433
|
+
(h) => h.path === path && h.session !== void 0
|
|
9434
|
+
)?.session;
|
|
9435
|
+
if (open !== void 0) await (await open).truncate(change.size);
|
|
9436
|
+
else await fs.truncate?.(path, change.size);
|
|
9437
|
+
}
|
|
9254
9438
|
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
9255
9439
|
if (change.mtime !== void 0) {
|
|
9256
9440
|
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
@@ -9966,6 +10150,7 @@ function tmpfs() {
|
|
|
9966
10150
|
const { dir, name: name2 } = parent(path);
|
|
9967
10151
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
9968
10152
|
dir.children.set(name2, make("directory", 16877));
|
|
10153
|
+
dir.mtime = Date.now();
|
|
9969
10154
|
},
|
|
9970
10155
|
async rmdir(path) {
|
|
9971
10156
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9974,6 +10159,7 @@ function tmpfs() {
|
|
|
9974
10159
|
if (node.kind !== "directory") throw fsError2("ENOTDIR", path);
|
|
9975
10160
|
if (node.children.size > 0) throw fsError2("ENOTEMPTY", path);
|
|
9976
10161
|
dir.children.delete(name2);
|
|
10162
|
+
dir.mtime = Date.now();
|
|
9977
10163
|
},
|
|
9978
10164
|
async unlink(path) {
|
|
9979
10165
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9981,6 +10167,7 @@ function tmpfs() {
|
|
|
9981
10167
|
if (!node) throw fsError2("ENOENT", path);
|
|
9982
10168
|
if (node.kind === "directory") throw fsError2("EISDIR", path);
|
|
9983
10169
|
dir.children.delete(name2);
|
|
10170
|
+
dir.mtime = Date.now();
|
|
9984
10171
|
},
|
|
9985
10172
|
async rename(from, to) {
|
|
9986
10173
|
const a = `/${parts(from).join("/")}`;
|
|
@@ -9997,6 +10184,8 @@ function tmpfs() {
|
|
|
9997
10184
|
}
|
|
9998
10185
|
source.dir.children.delete(source.name);
|
|
9999
10186
|
target.dir.children.set(target.name, node);
|
|
10187
|
+
source.dir.mtime = Date.now();
|
|
10188
|
+
target.dir.mtime = source.dir.mtime;
|
|
10000
10189
|
},
|
|
10001
10190
|
async symlink(target, path) {
|
|
10002
10191
|
const { dir, name: name2 } = parent(path);
|
|
@@ -10004,6 +10193,7 @@ function tmpfs() {
|
|
|
10004
10193
|
const node = make("symlink", 41471);
|
|
10005
10194
|
node.target = target;
|
|
10006
10195
|
dir.children.set(name2, node);
|
|
10196
|
+
dir.mtime = Date.now();
|
|
10007
10197
|
},
|
|
10008
10198
|
async readlink(path) {
|
|
10009
10199
|
const node = find(path);
|
|
@@ -10302,7 +10492,7 @@ var Launcher = class {
|
|
|
10302
10492
|
deciding = /* @__PURE__ */ new Map();
|
|
10303
10493
|
identities = { asked: 0, timedOut: 0 };
|
|
10304
10494
|
nodes;
|
|
10305
|
-
held =
|
|
10495
|
+
held = new HeldSet((path) => this.released(path));
|
|
10306
10496
|
processMounts;
|
|
10307
10497
|
booting = new AbortController();
|
|
10308
10498
|
fstab = Promise.resolve([]);
|
|
@@ -10344,7 +10534,7 @@ var Launcher = class {
|
|
|
10344
10534
|
});
|
|
10345
10535
|
enableCdp(this.net, this.cdp);
|
|
10346
10536
|
const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
10347
|
-
this.nodes = new VfsNodes(fs);
|
|
10537
|
+
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
10348
10538
|
this.openFiles.add(this.nodes);
|
|
10349
10539
|
this.fs = keepingOpen(fs, this.nodes);
|
|
10350
10540
|
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
@@ -10706,6 +10896,11 @@ var Launcher = class {
|
|
|
10706
10896
|
umaskOf(pid) {
|
|
10707
10897
|
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
10708
10898
|
}
|
|
10899
|
+
released(path) {
|
|
10900
|
+
const at = normalizePath(path);
|
|
10901
|
+
const open = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
10902
|
+
if (!open) void this.mounts.commit(at).catch(() => void 0);
|
|
10903
|
+
}
|
|
10709
10904
|
ignoredBy(pid, fork = false) {
|
|
10710
10905
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
10711
10906
|
}
|