@ai-ecoverse/slicc-kernel 1.35.1 → 1.37.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 +5 -3
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js.map +2 -2
- package/dist/kernel-worker.js +304 -61
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node.js +304 -61
- 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,
|
|
@@ -4682,6 +4733,35 @@ async function scanFilesystems(fs, modules) {
|
|
|
4682
4733
|
}
|
|
4683
4734
|
return found;
|
|
4684
4735
|
}
|
|
4736
|
+
var SUFFIX = /^\.[A-Za-z0-9_+-][A-Za-z0-9._+-]*$/;
|
|
4737
|
+
async function scanBinfmts(fs, modules) {
|
|
4738
|
+
const found = /* @__PURE__ */ new Map();
|
|
4739
|
+
for (const pkg of await packagesIn(fs, modules)) {
|
|
4740
|
+
let manifest;
|
|
4741
|
+
try {
|
|
4742
|
+
manifest = JSON.parse(await fs.readFile(`${pkg}/package.json`));
|
|
4743
|
+
} catch {
|
|
4744
|
+
continue;
|
|
4745
|
+
}
|
|
4746
|
+
const declared = manifest.slicc?.binfmt;
|
|
4747
|
+
if (!declared || typeof declared !== "object") continue;
|
|
4748
|
+
for (const [suffix, command] of Object.entries(declared)) {
|
|
4749
|
+
if (!SUFFIX.test(suffix) || typeof command !== "string" || !NAME.test(command)) continue;
|
|
4750
|
+
if (!found.has(suffix)) found.set(suffix, command);
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
return found;
|
|
4754
|
+
}
|
|
4755
|
+
function binfmtOf(binfmts, path) {
|
|
4756
|
+
const name2 = path.slice(path.lastIndexOf("/") + 1);
|
|
4757
|
+
let best;
|
|
4758
|
+
for (const suffix of binfmts.keys()) {
|
|
4759
|
+
if (name2.length > suffix.length && name2.endsWith(suffix)) {
|
|
4760
|
+
if (best === void 0 || suffix.length > best.length) best = suffix;
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
return best === void 0 ? void 0 : binfmts.get(best);
|
|
4764
|
+
}
|
|
4685
4765
|
|
|
4686
4766
|
// src/fs/commands.ts
|
|
4687
4767
|
var S_IFDIR2 = 16384;
|
|
@@ -5187,18 +5267,36 @@ function parseSize(text) {
|
|
|
5187
5267
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
5188
5268
|
}
|
|
5189
5269
|
var within3 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
5270
|
+
var HeldSet = class extends Set {
|
|
5271
|
+
idle;
|
|
5272
|
+
constructor(idle) {
|
|
5273
|
+
super();
|
|
5274
|
+
this.idle = idle;
|
|
5275
|
+
}
|
|
5276
|
+
add(holds) {
|
|
5277
|
+
holds.onIdle = this.idle;
|
|
5278
|
+
return super.add(holds);
|
|
5279
|
+
}
|
|
5280
|
+
delete(holds) {
|
|
5281
|
+
const removed = super.delete(holds);
|
|
5282
|
+
for (const path of holds.keys()) this.idle(path);
|
|
5283
|
+
return removed;
|
|
5284
|
+
}
|
|
5285
|
+
};
|
|
5190
5286
|
function heldUnder(held, target) {
|
|
5191
5287
|
for (const paths of held) for (const path of paths.keys()) if (within3(path, target)) return true;
|
|
5192
5288
|
return false;
|
|
5193
5289
|
}
|
|
5194
5290
|
var HeldPaths = class extends Map {
|
|
5195
5291
|
revoked = /* @__PURE__ */ new Set();
|
|
5292
|
+
onIdle;
|
|
5196
5293
|
hold(path, on) {
|
|
5197
5294
|
const count = (this.get(path) ?? 0) + (on ? 1 : -1);
|
|
5198
5295
|
if (count > 0) this.set(path, count);
|
|
5199
5296
|
else {
|
|
5200
5297
|
this.delete(path);
|
|
5201
5298
|
this.revoked.delete(path);
|
|
5299
|
+
this.onIdle?.(path);
|
|
5202
5300
|
}
|
|
5203
5301
|
}
|
|
5204
5302
|
revoke(prefix) {
|
|
@@ -5266,6 +5364,8 @@ function spliced(bytes, offset, part) {
|
|
|
5266
5364
|
}
|
|
5267
5365
|
var MountTable = class {
|
|
5268
5366
|
mounts = /* @__PURE__ */ new Map();
|
|
5367
|
+
sessions = /* @__PURE__ */ new Map();
|
|
5368
|
+
committing = /* @__PURE__ */ new Map();
|
|
5269
5369
|
devices = 0;
|
|
5270
5370
|
pending = /* @__PURE__ */ new Set();
|
|
5271
5371
|
notes = /* @__PURE__ */ new Map();
|
|
@@ -5390,8 +5490,69 @@ var MountTable = class {
|
|
|
5390
5490
|
if (!detach && this.deps.busy(at)) throw errnoError("EBUSY", `${at} has open files`);
|
|
5391
5491
|
this.notes.delete(at);
|
|
5392
5492
|
this.mounts.delete(at);
|
|
5393
|
-
mount.
|
|
5394
|
-
mount.
|
|
5493
|
+
const waits = [...this.sessions].filter(([, s]) => s.mount === mount).map(([real]) => this.commit(real));
|
|
5494
|
+
for (const c of this.committing.values()) if (c.mount === mount) waits.push(c.done);
|
|
5495
|
+
const close = () => {
|
|
5496
|
+
mount.conn.close();
|
|
5497
|
+
mount.dispose();
|
|
5498
|
+
};
|
|
5499
|
+
if (waits.length === 0) close();
|
|
5500
|
+
else void Promise.allSettled(waits).then(close);
|
|
5501
|
+
}
|
|
5502
|
+
session(mount, real, rel2) {
|
|
5503
|
+
let session = this.sessions.get(real);
|
|
5504
|
+
if (!session) {
|
|
5505
|
+
const open = () => mount.conn.call({
|
|
5506
|
+
op: "open",
|
|
5507
|
+
path: rel2,
|
|
5508
|
+
write: true,
|
|
5509
|
+
create: true,
|
|
5510
|
+
truncate: false,
|
|
5511
|
+
exclusive: false
|
|
5512
|
+
});
|
|
5513
|
+
const before = this.committing.get(real)?.done ?? Promise.resolve();
|
|
5514
|
+
const fh = before.then(open, open);
|
|
5515
|
+
session = { mount, fh, extents: [], truncated: false };
|
|
5516
|
+
this.sessions.set(real, session);
|
|
5517
|
+
fh.catch(() => this.sessions.delete(real));
|
|
5518
|
+
}
|
|
5519
|
+
return session;
|
|
5520
|
+
}
|
|
5521
|
+
writing(real) {
|
|
5522
|
+
return this.sessions.get(real);
|
|
5523
|
+
}
|
|
5524
|
+
async commit(real) {
|
|
5525
|
+
const session = this.sessions.get(real);
|
|
5526
|
+
if (!session) return this.committing.get(real)?.done;
|
|
5527
|
+
this.sessions.delete(real);
|
|
5528
|
+
const done4 = (async () => {
|
|
5529
|
+
try {
|
|
5530
|
+
await session.mount.conn.call({ op: "release", fh: await session.fh });
|
|
5531
|
+
} finally {
|
|
5532
|
+
this.forget(session.mount, real);
|
|
5533
|
+
}
|
|
5534
|
+
})();
|
|
5535
|
+
const entry = { mount: session.mount, done: done4 };
|
|
5536
|
+
this.committing.set(real, entry);
|
|
5537
|
+
const settle3 = () => {
|
|
5538
|
+
if (this.committing.get(real) === entry) this.committing.delete(real);
|
|
5539
|
+
};
|
|
5540
|
+
done4.then(settle3, settle3);
|
|
5541
|
+
return done4;
|
|
5542
|
+
}
|
|
5543
|
+
async commitUnder(prefix) {
|
|
5544
|
+
const at = normalizePath(prefix);
|
|
5545
|
+
await Promise.all(
|
|
5546
|
+
[...this.sessions.keys()].filter((p) => within3(p, at)).map((p) => this.commit(p))
|
|
5547
|
+
);
|
|
5548
|
+
}
|
|
5549
|
+
async commitOverlapping(real, offset, length2) {
|
|
5550
|
+
const session = this.sessions.get(real);
|
|
5551
|
+
if (!session) return;
|
|
5552
|
+
const end = offset + length2;
|
|
5553
|
+
if (session.truncated || session.extents.some(([a, b]) => a < end && offset < b)) {
|
|
5554
|
+
await this.commit(real);
|
|
5555
|
+
}
|
|
5395
5556
|
}
|
|
5396
5557
|
crashed(mount, error) {
|
|
5397
5558
|
mount.state = "failed";
|
|
@@ -5450,6 +5611,13 @@ var MountTable = class {
|
|
|
5450
5611
|
return new MountFs(this, base);
|
|
5451
5612
|
}
|
|
5452
5613
|
};
|
|
5614
|
+
function noteExtent(extents, from, to) {
|
|
5615
|
+
const last = extents.at(-1);
|
|
5616
|
+
if (last && from <= last[1] && to >= last[0]) {
|
|
5617
|
+
last[0] = Math.min(last[0], from);
|
|
5618
|
+
last[1] = Math.max(last[1], to);
|
|
5619
|
+
} else extents.push([from, to]);
|
|
5620
|
+
}
|
|
5453
5621
|
var MountFs = class {
|
|
5454
5622
|
table;
|
|
5455
5623
|
base;
|
|
@@ -5509,6 +5677,7 @@ var MountFs = class {
|
|
|
5509
5677
|
}
|
|
5510
5678
|
}
|
|
5511
5679
|
async readWhole(mount, real, rel2) {
|
|
5680
|
+
await this.table.commit(real);
|
|
5512
5681
|
const attr = await this.table.getattr(mount, real, rel2);
|
|
5513
5682
|
if (attr.kind === "directory") throw errnoError("EISDIR", real);
|
|
5514
5683
|
if (mount.maxFile > 0 && attr.size > mount.maxFile) {
|
|
@@ -5558,6 +5727,7 @@ var MountFs = class {
|
|
|
5558
5727
|
}
|
|
5559
5728
|
}
|
|
5560
5729
|
async writeWhole(mount, real, rel2, bytes) {
|
|
5730
|
+
await this.table.commit(real);
|
|
5561
5731
|
this.table.forget(mount, real);
|
|
5562
5732
|
const fh = await this.open(mount, rel2, true);
|
|
5563
5733
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
@@ -5580,6 +5750,7 @@ var MountFs = class {
|
|
|
5580
5750
|
if ((await this.table.getattr(mount, real, rel2)).kind === "directory") {
|
|
5581
5751
|
throw errnoError("EISDIR", real);
|
|
5582
5752
|
}
|
|
5753
|
+
await this.table.commitOverlapping(real, offset, length2);
|
|
5583
5754
|
const fh = await mount.conn.call({
|
|
5584
5755
|
op: "open",
|
|
5585
5756
|
path: rel2,
|
|
@@ -5633,6 +5804,14 @@ var MountFs = class {
|
|
|
5633
5804
|
this.writable(mount, real);
|
|
5634
5805
|
this.fits(mount, real, offset + bytes.length);
|
|
5635
5806
|
this.table.forget(mount, real);
|
|
5807
|
+
if (mount.caps.sessions) {
|
|
5808
|
+
const session = this.table.session(mount, real, rel2);
|
|
5809
|
+
const end = offset + bytes.length;
|
|
5810
|
+
await this.writeRuns(mount, await session.fh, offset, bytes, transfer);
|
|
5811
|
+
noteExtent(session.extents, offset, end);
|
|
5812
|
+
this.table.forget(mount, real);
|
|
5813
|
+
return;
|
|
5814
|
+
}
|
|
5636
5815
|
const fh = await mount.conn.call({
|
|
5637
5816
|
op: "open",
|
|
5638
5817
|
path: rel2,
|
|
@@ -5641,17 +5820,20 @@ var MountFs = class {
|
|
|
5641
5820
|
truncate: false,
|
|
5642
5821
|
exclusive: false
|
|
5643
5822
|
});
|
|
5644
|
-
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5645
5823
|
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
|
-
}
|
|
5824
|
+
await this.writeRuns(mount, fh, offset, bytes, transfer);
|
|
5650
5825
|
} finally {
|
|
5651
5826
|
await mount.conn.call({ op: "release", fh });
|
|
5652
5827
|
this.table.forget(mount, real);
|
|
5653
5828
|
}
|
|
5654
5829
|
}
|
|
5830
|
+
async writeRuns(mount, fh, offset, bytes, transfer) {
|
|
5831
|
+
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5832
|
+
for (let at = 0; at < bytes.length; at += chunk2) {
|
|
5833
|
+
const part = handed(bytes, transfer, chunk2) ? bytes : bytes.slice(at, at + chunk2);
|
|
5834
|
+
await mount.conn.call({ op: "write", fh, offset: offset + at, bytes: part }, [part.buffer]);
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5655
5837
|
async truncate(path, size) {
|
|
5656
5838
|
const real = await this.follow(path);
|
|
5657
5839
|
const found = this.at(real);
|
|
@@ -5663,6 +5845,8 @@ var MountFs = class {
|
|
|
5663
5845
|
this.writable(mount, real);
|
|
5664
5846
|
this.fits(mount, real, size);
|
|
5665
5847
|
this.table.forget(mount, real);
|
|
5848
|
+
const session = this.table.writing(real);
|
|
5849
|
+
if (session) session.truncated = true;
|
|
5666
5850
|
try {
|
|
5667
5851
|
await mount.conn.call({ op: "setattr", path: rel2, size });
|
|
5668
5852
|
} finally {
|
|
@@ -5684,7 +5868,16 @@ var MountFs = class {
|
|
|
5684
5868
|
const found = this.at(path);
|
|
5685
5869
|
if (!found) return this.base.lstat(path);
|
|
5686
5870
|
const real = normalizePath(path);
|
|
5687
|
-
|
|
5871
|
+
if (this.table.writing(real)?.truncated) await this.table.commit(real);
|
|
5872
|
+
return this.statWriting(
|
|
5873
|
+
await this.table.getattr(found.mount, real, found.rel),
|
|
5874
|
+
real,
|
|
5875
|
+
found.mount
|
|
5876
|
+
);
|
|
5877
|
+
}
|
|
5878
|
+
statWriting(attr, real, mount) {
|
|
5879
|
+
const ends = (this.table.writing(real)?.extents ?? []).map(([, end]) => end);
|
|
5880
|
+
return statOf({ ...attr, size: Math.max(attr.size, ...ends) }, real, mount);
|
|
5688
5881
|
}
|
|
5689
5882
|
async stat(path) {
|
|
5690
5883
|
const real = await this.follow(path);
|
|
@@ -5711,7 +5904,7 @@ var MountFs = class {
|
|
|
5711
5904
|
list.map(async (entry) => {
|
|
5712
5905
|
const child = normalizePath(`${real}/${entry.name}`);
|
|
5713
5906
|
if (entry.attr && mount.caps.listingStats) {
|
|
5714
|
-
return [entry.name,
|
|
5907
|
+
return [entry.name, this.statWriting(entry.attr, child, mount)];
|
|
5715
5908
|
}
|
|
5716
5909
|
return [entry.name, await this.lstat(child).catch(() => null)];
|
|
5717
5910
|
})
|
|
@@ -5747,6 +5940,7 @@ var MountFs = class {
|
|
|
5747
5940
|
const real = normalizePath(path);
|
|
5748
5941
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
5749
5942
|
this.writable(mount, real);
|
|
5943
|
+
await this.table.commitUnder(real);
|
|
5750
5944
|
let attr;
|
|
5751
5945
|
try {
|
|
5752
5946
|
attr = await this.table.getattr(mount, real, rel2);
|
|
@@ -5770,6 +5964,8 @@ var MountFs = class {
|
|
|
5770
5964
|
if (!a && !b) return this.base.rename(from, to);
|
|
5771
5965
|
if (!a || !b || a.mount !== b.mount) throw errnoError("EXDEV", `${from} -> ${to}`);
|
|
5772
5966
|
this.writable(a.mount, normalizePath(to));
|
|
5967
|
+
await this.table.commitUnder(from);
|
|
5968
|
+
await this.table.commitUnder(to);
|
|
5773
5969
|
this.table.forget(a.mount, normalizePath(from));
|
|
5774
5970
|
this.table.forget(a.mount, normalizePath(to));
|
|
5775
5971
|
try {
|
|
@@ -7376,6 +7572,7 @@ var VfsNode = class {
|
|
|
7376
7572
|
writeBack;
|
|
7377
7573
|
writeBackCost = 0;
|
|
7378
7574
|
opens = 0;
|
|
7575
|
+
writers = 0;
|
|
7379
7576
|
missing = false;
|
|
7380
7577
|
revoked = false;
|
|
7381
7578
|
fs;
|
|
@@ -7551,8 +7748,10 @@ var VfsNodes = class {
|
|
|
7551
7748
|
byPath = /* @__PURE__ */ new Map();
|
|
7552
7749
|
fs;
|
|
7553
7750
|
entries = /* @__PURE__ */ new Map();
|
|
7554
|
-
|
|
7751
|
+
onClosed;
|
|
7752
|
+
constructor(fs, onClosed) {
|
|
7555
7753
|
this.fs = fs;
|
|
7754
|
+
this.onClosed = onClosed;
|
|
7556
7755
|
}
|
|
7557
7756
|
async onEntry(path, op) {
|
|
7558
7757
|
const key = await this.entryKey(path);
|
|
@@ -7590,16 +7789,17 @@ var VfsNodes = class {
|
|
|
7590
7789
|
await this.fs.writeFile(path, new Uint8Array(0));
|
|
7591
7790
|
});
|
|
7592
7791
|
}
|
|
7593
|
-
open(path, pin) {
|
|
7792
|
+
open(path, pin, writable = false) {
|
|
7594
7793
|
let node = this.byPath.get(path);
|
|
7595
7794
|
if (!node) {
|
|
7596
7795
|
node = new VfsNode(this.fs, path, void 0, false, false, pin);
|
|
7597
7796
|
this.byPath.set(path, node);
|
|
7598
7797
|
}
|
|
7599
7798
|
node.opens++;
|
|
7799
|
+
if (writable) node.writers++;
|
|
7600
7800
|
return node;
|
|
7601
7801
|
}
|
|
7602
|
-
adopt(path, contents2, dirty) {
|
|
7802
|
+
adopt(path, contents2, dirty, writable = false) {
|
|
7603
7803
|
let node = this.byPath.get(path);
|
|
7604
7804
|
if (!node) {
|
|
7605
7805
|
node = new VfsNode(this.fs, path, contents2, false, dirty);
|
|
@@ -7608,15 +7808,27 @@ var VfsNodes = class {
|
|
|
7608
7808
|
node.replace(contents2);
|
|
7609
7809
|
}
|
|
7610
7810
|
node.opens++;
|
|
7811
|
+
if (writable) node.writers++;
|
|
7611
7812
|
return node;
|
|
7612
7813
|
}
|
|
7613
7814
|
holds(prefix) {
|
|
7614
7815
|
for (const path of this.byPath.keys()) if (within4(path, prefix)) return true;
|
|
7615
7816
|
return false;
|
|
7616
7817
|
}
|
|
7617
|
-
|
|
7818
|
+
writes(prefix) {
|
|
7819
|
+
for (const [path, node] of this.byPath)
|
|
7820
|
+
if (node.writers > 0 && within4(path, prefix)) return true;
|
|
7821
|
+
return false;
|
|
7822
|
+
}
|
|
7823
|
+
closed(node, writable = false) {
|
|
7618
7824
|
node.opens--;
|
|
7619
|
-
if (
|
|
7825
|
+
if (writable) node.writers--;
|
|
7826
|
+
if (node.opens > 0) {
|
|
7827
|
+
if (writable && node.writers === 0) this.onClosed?.(node.path);
|
|
7828
|
+
return;
|
|
7829
|
+
}
|
|
7830
|
+
if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
|
|
7831
|
+
this.onClosed?.(node.path);
|
|
7620
7832
|
}
|
|
7621
7833
|
async flush(path) {
|
|
7622
7834
|
for (const [p, node] of this.byPath) if (within4(p, path)) await node.serial(() => node.flush());
|
|
@@ -7762,7 +7974,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7762
7974
|
const access = opts.flags & O_ACCMODE;
|
|
7763
7975
|
const readable = access !== O_WRONLY;
|
|
7764
7976
|
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);
|
|
7977
|
+
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
7978
|
let openError;
|
|
7767
7979
|
const atOpen = (op) => {
|
|
7768
7980
|
void node.serial(op).catch((err) => {
|
|
@@ -7825,7 +8037,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7825
8037
|
takeOpenError();
|
|
7826
8038
|
await node.flush();
|
|
7827
8039
|
} finally {
|
|
7828
|
-
nodes?.closed(node);
|
|
8040
|
+
nodes?.closed(node, writable);
|
|
7829
8041
|
}
|
|
7830
8042
|
})
|
|
7831
8043
|
});
|
|
@@ -9172,7 +9384,11 @@ function mediumSlot(lost, onLost) {
|
|
|
9172
9384
|
}
|
|
9173
9385
|
|
|
9174
9386
|
// src/mount/fsa.ts
|
|
9175
|
-
var FSA_CAPABILITIES = {
|
|
9387
|
+
var FSA_CAPABILITIES = {
|
|
9388
|
+
listingStats: true,
|
|
9389
|
+
ranges: true,
|
|
9390
|
+
sessions: true
|
|
9391
|
+
};
|
|
9176
9392
|
var codeOf2 = (err) => err?.code;
|
|
9177
9393
|
var denied = (err) => codeOf2(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
9178
9394
|
function attrOf(st) {
|
|
@@ -9212,30 +9428,20 @@ function kernelFsHandlers(fs) {
|
|
|
9212
9428
|
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
9213
9429
|
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
9214
9430
|
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
9215
|
-
|
|
9216
|
-
handles.set(++nextFh, { path
|
|
9431
|
+
if (!st || flags.truncate) await fs.writeFile(path, new Uint8Array(0));
|
|
9432
|
+
handles.set(++nextFh, { path });
|
|
9217
9433
|
return nextFh;
|
|
9218
9434
|
},
|
|
9219
|
-
async
|
|
9220
|
-
const h = handle(fh);
|
|
9221
|
-
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
9222
|
-
},
|
|
9435
|
+
read: async (fh, offset, size) => fs.pread(handle(fh).path, offset, size),
|
|
9223
9436
|
async write(fh, offset, bytes) {
|
|
9224
9437
|
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;
|
|
9438
|
+
h.session ??= fs.writeSession(h.path, false);
|
|
9439
|
+
await (await h.session).write(offset, bytes);
|
|
9234
9440
|
},
|
|
9235
9441
|
async release(fh) {
|
|
9236
9442
|
const h = handle(fh);
|
|
9237
9443
|
handles.delete(fh);
|
|
9238
|
-
if (h.
|
|
9444
|
+
if (h.session !== void 0) await (await h.session).close();
|
|
9239
9445
|
},
|
|
9240
9446
|
mkdir: (path) => fs.mkdir(path),
|
|
9241
9447
|
async rmdir(path) {
|
|
@@ -9251,6 +9457,13 @@ function kernelFsHandlers(fs) {
|
|
|
9251
9457
|
symlink: (target, path) => fs.symlink(target, path),
|
|
9252
9458
|
readlink: (path) => fs.readlink(path),
|
|
9253
9459
|
async setattr(path, change) {
|
|
9460
|
+
if (change.size !== void 0) {
|
|
9461
|
+
const open = [...handles.values()].find(
|
|
9462
|
+
(h) => h.path === path && h.session !== void 0
|
|
9463
|
+
)?.session;
|
|
9464
|
+
if (open !== void 0) await (await open).truncate(change.size);
|
|
9465
|
+
else await fs.truncate?.(path, change.size);
|
|
9466
|
+
}
|
|
9254
9467
|
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
9255
9468
|
if (change.mtime !== void 0) {
|
|
9256
9469
|
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
@@ -9966,6 +10179,7 @@ function tmpfs() {
|
|
|
9966
10179
|
const { dir, name: name2 } = parent(path);
|
|
9967
10180
|
if (dir.children.has(name2)) throw fsError2("EEXIST", path);
|
|
9968
10181
|
dir.children.set(name2, make("directory", 16877));
|
|
10182
|
+
dir.mtime = Date.now();
|
|
9969
10183
|
},
|
|
9970
10184
|
async rmdir(path) {
|
|
9971
10185
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9974,6 +10188,7 @@ function tmpfs() {
|
|
|
9974
10188
|
if (node.kind !== "directory") throw fsError2("ENOTDIR", path);
|
|
9975
10189
|
if (node.children.size > 0) throw fsError2("ENOTEMPTY", path);
|
|
9976
10190
|
dir.children.delete(name2);
|
|
10191
|
+
dir.mtime = Date.now();
|
|
9977
10192
|
},
|
|
9978
10193
|
async unlink(path) {
|
|
9979
10194
|
const { dir, name: name2 } = parent(path);
|
|
@@ -9981,6 +10196,7 @@ function tmpfs() {
|
|
|
9981
10196
|
if (!node) throw fsError2("ENOENT", path);
|
|
9982
10197
|
if (node.kind === "directory") throw fsError2("EISDIR", path);
|
|
9983
10198
|
dir.children.delete(name2);
|
|
10199
|
+
dir.mtime = Date.now();
|
|
9984
10200
|
},
|
|
9985
10201
|
async rename(from, to) {
|
|
9986
10202
|
const a = `/${parts(from).join("/")}`;
|
|
@@ -9997,6 +10213,8 @@ function tmpfs() {
|
|
|
9997
10213
|
}
|
|
9998
10214
|
source.dir.children.delete(source.name);
|
|
9999
10215
|
target.dir.children.set(target.name, node);
|
|
10216
|
+
source.dir.mtime = Date.now();
|
|
10217
|
+
target.dir.mtime = source.dir.mtime;
|
|
10000
10218
|
},
|
|
10001
10219
|
async symlink(target, path) {
|
|
10002
10220
|
const { dir, name: name2 } = parent(path);
|
|
@@ -10004,6 +10222,7 @@ function tmpfs() {
|
|
|
10004
10222
|
const node = make("symlink", 41471);
|
|
10005
10223
|
node.target = target;
|
|
10006
10224
|
dir.children.set(name2, node);
|
|
10225
|
+
dir.mtime = Date.now();
|
|
10007
10226
|
},
|
|
10008
10227
|
async readlink(path) {
|
|
10009
10228
|
const node = find(path);
|
|
@@ -10193,6 +10412,7 @@ var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
|
10193
10412
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
10194
10413
|
var WASM_MAGIC = [0, 97, 115, 109];
|
|
10195
10414
|
var SHEBANG_MAX = 256;
|
|
10415
|
+
var MAX_INTERPRETERS = 4;
|
|
10196
10416
|
var NOT_FOUND = 127;
|
|
10197
10417
|
var DECIDE_MS = 100;
|
|
10198
10418
|
var INIT_PID = 1;
|
|
@@ -10244,6 +10464,17 @@ function targetOf(command) {
|
|
|
10244
10464
|
...command.preopenRoot ? { preopenRoot: true } : {}
|
|
10245
10465
|
};
|
|
10246
10466
|
}
|
|
10467
|
+
function withScriptEnv(target, command) {
|
|
10468
|
+
if (!command) return target;
|
|
10469
|
+
return {
|
|
10470
|
+
...target,
|
|
10471
|
+
env: { ...target.env, ...command.env },
|
|
10472
|
+
unset: [
|
|
10473
|
+
...(target.unset ?? []).filter((key) => !Object.hasOwn(command.env ?? {}, key)),
|
|
10474
|
+
...command.unset ?? []
|
|
10475
|
+
]
|
|
10476
|
+
};
|
|
10477
|
+
}
|
|
10247
10478
|
function childHandle(handle) {
|
|
10248
10479
|
return {
|
|
10249
10480
|
pid: handle.pid,
|
|
@@ -10268,6 +10499,7 @@ var Launcher = class {
|
|
|
10268
10499
|
modulesDir;
|
|
10269
10500
|
env;
|
|
10270
10501
|
catalog;
|
|
10502
|
+
binfmts;
|
|
10271
10503
|
compiled = /* @__PURE__ */ new Map();
|
|
10272
10504
|
processes = /* @__PURE__ */ new Map();
|
|
10273
10505
|
zombies = /* @__PURE__ */ new Set();
|
|
@@ -10302,7 +10534,7 @@ var Launcher = class {
|
|
|
10302
10534
|
deciding = /* @__PURE__ */ new Map();
|
|
10303
10535
|
identities = { asked: 0, timedOut: 0 };
|
|
10304
10536
|
nodes;
|
|
10305
|
-
held =
|
|
10537
|
+
held = new HeldSet((path) => this.released(path));
|
|
10306
10538
|
processMounts;
|
|
10307
10539
|
booting = new AbortController();
|
|
10308
10540
|
fstab = Promise.resolve([]);
|
|
@@ -10344,11 +10576,12 @@ var Launcher = class {
|
|
|
10344
10576
|
});
|
|
10345
10577
|
enableCdp(this.net, this.cdp);
|
|
10346
10578
|
const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
10347
|
-
this.nodes = new VfsNodes(fs);
|
|
10579
|
+
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
10348
10580
|
this.openFiles.add(this.nodes);
|
|
10349
10581
|
this.fs = keepingOpen(fs, this.nodes);
|
|
10350
10582
|
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
10351
10583
|
this.catalog = void 0;
|
|
10584
|
+
this.binfmts = void 0;
|
|
10352
10585
|
});
|
|
10353
10586
|
}
|
|
10354
10587
|
setRoutes(table) {
|
|
@@ -10358,6 +10591,10 @@ var Launcher = class {
|
|
|
10358
10591
|
this.catalog ??= this.roots().then((roots) => scanCommands(this.base, roots));
|
|
10359
10592
|
return this.catalog;
|
|
10360
10593
|
}
|
|
10594
|
+
interpreters() {
|
|
10595
|
+
this.binfmts ??= this.roots().then((roots) => scanBinfmts(this.base, roots));
|
|
10596
|
+
return this.binfmts;
|
|
10597
|
+
}
|
|
10361
10598
|
async roots() {
|
|
10362
10599
|
return [this.modulesDir, ...await pnpmGlobalRoots(this.base, this.pnpmHome)];
|
|
10363
10600
|
}
|
|
@@ -10403,30 +10640,28 @@ var Launcher = class {
|
|
|
10403
10640
|
const command = (await this.commands()).get(name2);
|
|
10404
10641
|
return command?.script ? command : void 0;
|
|
10405
10642
|
}
|
|
10406
|
-
async interpreted(file, argv, cwd) {
|
|
10643
|
+
async interpreted(file, argv, cwd, depth = 0) {
|
|
10407
10644
|
const command = await this.scriptCommand(file);
|
|
10408
10645
|
const script = command?.script ?? this.fs.resolvePath(cwd, file);
|
|
10409
|
-
const
|
|
10646
|
+
const head = await this.head(script);
|
|
10647
|
+
if (!head) return void 0;
|
|
10648
|
+
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(), script);
|
|
10649
|
+
const words = shebang(head) ?? (binfmt ? [binfmt] : void 0);
|
|
10410
10650
|
if (!words) return void 0;
|
|
10411
10651
|
if (baseName(words[0]) === "env") words.shift();
|
|
10412
10652
|
const [interp, ...rest] = words;
|
|
10413
|
-
const found = interp ? await this.resolve(interp, interp, cwd) : void 0;
|
|
10414
|
-
if (!found) return void 0;
|
|
10415
|
-
const target = command ? {
|
|
10416
|
-
...found,
|
|
10417
|
-
env: { ...found.env, ...command.env },
|
|
10418
|
-
unset: [...found.unset ?? [], ...command.unset ?? []]
|
|
10419
|
-
} : found;
|
|
10420
10653
|
const arg = rest.join(" ");
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
}
|
|
10654
|
+
const passed = [...arg ? [arg] : [], command ? script : file, ...argv.slice(1)];
|
|
10655
|
+
const found = interp ? await this.resolve(interp, interp, cwd) : void 0;
|
|
10656
|
+
if (!found) {
|
|
10657
|
+
if (!interp || depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp)) {
|
|
10658
|
+
return void 0;
|
|
10659
|
+
}
|
|
10660
|
+
const inner = await this.interpreted(interp, [interp, ...passed], cwd, depth + 1);
|
|
10661
|
+
return inner && { ...inner, target: withScriptEnv(inner.target, command) };
|
|
10662
|
+
}
|
|
10663
|
+
const target = withScriptEnv(found, command);
|
|
10664
|
+
return { target, args: [...target.prefix ?? [], ...passed] };
|
|
10430
10665
|
}
|
|
10431
10666
|
async plan(file, argv, cwd) {
|
|
10432
10667
|
const direct = await this.resolve(file, argv[0] ?? file, cwd);
|
|
@@ -10434,8 +10669,10 @@ var Launcher = class {
|
|
|
10434
10669
|
return this.interpreted(file, argv, cwd);
|
|
10435
10670
|
}
|
|
10436
10671
|
async unrunnable(file, cwd) {
|
|
10437
|
-
const
|
|
10438
|
-
|
|
10672
|
+
const path = this.fs.resolvePath(cwd, file);
|
|
10673
|
+
const head = await this.base.readFileBuffer(path).catch(() => null);
|
|
10674
|
+
if (!head || head[0] === 35 && head[1] === 33) return "ENOENT";
|
|
10675
|
+
return binfmtOf(await this.interpreters(), path) ? "ENOENT" : "ENOEXEC";
|
|
10439
10676
|
}
|
|
10440
10677
|
module(path) {
|
|
10441
10678
|
return this.base.stat(path).then((st) => {
|
|
@@ -10706,6 +10943,11 @@ var Launcher = class {
|
|
|
10706
10943
|
umaskOf(pid) {
|
|
10707
10944
|
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
10708
10945
|
}
|
|
10946
|
+
released(path) {
|
|
10947
|
+
const at = normalizePath(path);
|
|
10948
|
+
const open = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
10949
|
+
if (!open) void this.mounts.commit(at).catch(() => void 0);
|
|
10950
|
+
}
|
|
10709
10951
|
ignoredBy(pid, fork = false) {
|
|
10710
10952
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
10711
10953
|
}
|
|
@@ -10890,6 +11132,7 @@ var Launcher = class {
|
|
|
10890
11132
|
}
|
|
10891
11133
|
async starting(argv, dir) {
|
|
10892
11134
|
this.catalog = void 0;
|
|
11135
|
+
this.binfmts = void 0;
|
|
10893
11136
|
const cwd = this.fs.resolvePath("/", dir ?? "/");
|
|
10894
11137
|
const [file = ""] = argv;
|
|
10895
11138
|
await this.base.mkdir(cwd, { recursive: true });
|