@poe-platform/safe-fs 0.1.803 → 0.1.805
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 +22 -4
- package/dist/safe-fs/bridge/filesystem.js +1 -1
- package/dist/safe-fs/contracts/errors.d.ts +1 -0
- package/dist/safe-fs/contracts/errors.js +16 -3
- package/dist/safe-fs/contracts/filesystem.d.ts +3 -2
- package/dist/safe-fs/contracts/io.d.ts +2 -0
- package/dist/safe-fs/contracts/io.js +32 -7
- package/dist/safe-fs/contracts/portable-path.d.ts +8 -0
- package/dist/safe-fs/contracts/portable-path.js +22 -1
- package/dist/safe-fs/core.d.ts +3 -14
- package/dist/safe-fs/core.js +3 -11
- package/dist/safe-fs/fs/devices/index.d.ts +6 -1
- package/dist/safe-fs/fs/devices/index.js +40 -24
- package/dist/safe-fs/fs/devices/path.js +1 -1
- package/dist/safe-fs/fs/directory-admission.js +2 -2
- package/dist/safe-fs/fs/memory/atomic-view.d.ts +3 -0
- package/dist/safe-fs/fs/memory/atomic-view.js +5 -0
- package/dist/safe-fs/fs/memory/index.d.ts +6 -3
- package/dist/safe-fs/fs/memory/index.js +147 -131
- package/dist/safe-fs/fs/memory/ledger.js +3 -1
- package/dist/safe-fs/fs/memory/limits.js +3 -0
- package/dist/safe-fs/fs/mount/comparison.js +3 -3
- package/dist/safe-fs/fs/object-publication/index.js +2 -1
- package/dist/safe-fs/fs/readonly/index.js +1 -1
- package/dist/safe-fs/fs/real/index.js +3 -2
- package/dist/safe-fs/fs/s3/filesystem.js +1 -1
- package/dist/safe-fs/fs/s3/http/request-fetch.d.ts +14 -3
- package/dist/safe-fs/fs/s3/http/request-node.d.ts +2 -2
- package/dist/safe-fs/fs/s3/http/types.d.ts +2 -2
- package/dist/safe-fs/fs/s3/manifest-admission.js +0 -4
- package/dist/safe-fs/fs/s3/namespace.js +2 -4
- package/dist/safe-fs/fs/webdav/webdav.js +5 -29
- package/dist/safe-fs/fs/webdav/xml.js +2 -2
- package/dist/safe-fs/python/emscripten.js +5 -2
- package/dist/safe-fs/python/filesystem.js +2 -2
- package/dist/safe-fs/python/native.js +1 -1
- package/dist/safe-fs/python/stat.js +5 -2
- package/dist/safe-fs/runtime-core.d.ts +26 -0
- package/dist/safe-fs/runtime-core.js +56 -0
- package/package.json +16 -2
|
@@ -9,7 +9,7 @@ import { directoryAncestryPaths, runStagingGuard, snapshotDirectoryAncestry, sna
|
|
|
9
9
|
import { compareIdentity } from "../mount/identity.js";
|
|
10
10
|
import { createStagingCleanup, snapshotStagingCreation } from "../staging-cleanup.js";
|
|
11
11
|
import { resolveMissingTarget } from "./missing-target.js";
|
|
12
|
-
import {
|
|
12
|
+
import { registerLazyMemoryAtomicView } from "./atomic-view.js";
|
|
13
13
|
import { snapshotConditionalChmod } from "../conditional-chmod.js";
|
|
14
14
|
import { MemoryAllocation, MemoryLedger } from "./ledger.js";
|
|
15
15
|
import { normalizeMemoryFileSystemLimits } from "./limits.js";
|
|
@@ -46,24 +46,21 @@ Object.assign(MemoryFileNode.prototype, {
|
|
|
46
46
|
sourceRef: undefined,
|
|
47
47
|
});
|
|
48
48
|
const EMPTY_ALLOC_BYTES = new Uint8Array(0);
|
|
49
|
-
const SMALL_ALLOC_SLAB_SIZE = 8192;
|
|
50
|
-
let smallAllocSlab = new Uint8Array(SMALL_ALLOC_SLAB_SIZE);
|
|
51
|
-
let smallAllocOffset = 0;
|
|
52
49
|
const DUMMY_POOL_LEDGER = new MemoryLedger(normalizeMemoryFileSystemLimits({}));
|
|
53
50
|
const DUMMY_POOL_ALLOCATION = new MemoryAllocation(EMPTY_ALLOC_BYTES, DUMMY_POOL_LEDGER);
|
|
54
51
|
const DUMMY_POOL_FILE_NODE = new MemoryFileNode(0, 0, null, 0, DUMMY_POOL_ALLOCATION, DUMMY_POOL_ALLOCATION.data);
|
|
55
52
|
DUMMY_POOL_FILE_NODE.atimeMs = DUMMY_POOL_FILE_NODE.mtimeMs = DUMMY_POOL_FILE_NODE.ctimeMs = DUMMY_POOL_FILE_NODE.birthtimeMs = 1700000000000;
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
const EMPTY_DIR_TABLE = new Int16Array(0);
|
|
54
|
+
const EMPTY_DIR_KEYS = [];
|
|
55
|
+
const EMPTY_DIR_VALS = [];
|
|
59
56
|
class FastDirectoryEntriesMap {
|
|
60
57
|
// Keep speculative slots local so a failed write cannot pin a tenant globally.
|
|
61
58
|
_missKey = "";
|
|
62
59
|
_missSlot = -1;
|
|
63
|
-
_table =
|
|
64
|
-
_mask =
|
|
65
|
-
_keys =
|
|
66
|
-
_vals =
|
|
60
|
+
_table = EMPTY_DIR_TABLE;
|
|
61
|
+
_mask = 0;
|
|
62
|
+
_keys = EMPTY_DIR_KEYS;
|
|
63
|
+
_vals = EMPTY_DIR_VALS;
|
|
67
64
|
_next = 0;
|
|
68
65
|
size = 0;
|
|
69
66
|
[Symbol.toStringTag] = "Map";
|
|
@@ -96,6 +93,11 @@ class FastDirectoryEntriesMap {
|
|
|
96
93
|
getForWriteWithHash(k, h) {
|
|
97
94
|
let slot = h & this._mask;
|
|
98
95
|
if (this.size === 0) {
|
|
96
|
+
if (this._keys.length === 0) {
|
|
97
|
+
this._missKey = "";
|
|
98
|
+
this._missSlot = -1;
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
99
101
|
this._missKey = k;
|
|
100
102
|
this._missSlot = slot;
|
|
101
103
|
return undefined;
|
|
@@ -211,7 +213,7 @@ class FastDirectoryEntriesMap {
|
|
|
211
213
|
return this;
|
|
212
214
|
}
|
|
213
215
|
if (this._next >= this._keys.length) {
|
|
214
|
-
this._rebuild(this.size * 2 <= this._keys.length ? this._keys.length : this._keys.length * 2);
|
|
216
|
+
this._rebuild(this._keys.length === 0 ? 8 : (this.size * 2 <= this._keys.length ? this._keys.length : this._keys.length * 2));
|
|
215
217
|
}
|
|
216
218
|
let slot = this._hash(k);
|
|
217
219
|
const mask = this._mask;
|
|
@@ -350,19 +352,13 @@ function collectRemovedChild(child, name) {
|
|
|
350
352
|
}
|
|
351
353
|
function replenishSharedMemoryPools() {
|
|
352
354
|
while (sharedAllocationPoolLen < 112) {
|
|
353
|
-
if (smallAllocOffset + 64 > SMALL_ALLOC_SLAB_SIZE) {
|
|
354
|
-
smallAllocSlab = new Uint8Array(SMALL_ALLOC_SLAB_SIZE);
|
|
355
|
-
smallAllocOffset = 0;
|
|
356
|
-
}
|
|
357
|
-
const slice = smallAllocSlab.subarray(smallAllocOffset, smallAllocOffset + 64);
|
|
358
|
-
smallAllocOffset += 64;
|
|
359
355
|
DUMMY_POOL_LEDGER.reserve(64, 0, "init", "/");
|
|
360
|
-
const alloc = new MemoryAllocation(
|
|
356
|
+
const alloc = new MemoryAllocation(new Uint8Array(64), DUMMY_POOL_LEDGER);
|
|
361
357
|
alloc.release();
|
|
362
358
|
sharedAllocationPool[sharedAllocationPoolLen++] = alloc;
|
|
363
359
|
}
|
|
364
360
|
while (sharedFileNodePoolLen < 112) {
|
|
365
|
-
sharedFileNodePool[sharedFileNodePoolLen++] = new MemoryFileNode(0, 0,
|
|
361
|
+
sharedFileNodePool[sharedFileNodePoolLen++] = new MemoryFileNode(0, 0, 0, 0, DUMMY_POOL_ALLOCATION, undefined);
|
|
366
362
|
}
|
|
367
363
|
while (sharedLargeAllocationPoolLen < 4) {
|
|
368
364
|
DUMMY_POOL_LEDGER.reserve(65536, 0, "init", "/");
|
|
@@ -377,7 +373,7 @@ function replenishSharedMemoryPools() {
|
|
|
377
373
|
sharedMediumAllocationPool[sharedMediumAllocationPoolLen++] = alloc;
|
|
378
374
|
}
|
|
379
375
|
while (sharedDirectoryNodePoolLen < 16) {
|
|
380
|
-
sharedDirectoryNodePool[sharedDirectoryNodePoolLen++] = new MemoryDirectoryNode(0, 0,
|
|
376
|
+
sharedDirectoryNodePool[sharedDirectoryNodePoolLen++] = new MemoryDirectoryNode(0, 0, 0);
|
|
381
377
|
}
|
|
382
378
|
}
|
|
383
379
|
class MemoryDirectoryNode {
|
|
@@ -427,7 +423,6 @@ class MemoryCache {
|
|
|
427
423
|
const typeModes = { file: 0o100000, directory: 0o040000, symlink: 0o120000 };
|
|
428
424
|
const emptyResolveOptions = Object.freeze({});
|
|
429
425
|
const noFollowResolveOptions = Object.freeze({ followFinal: false });
|
|
430
|
-
const sharedMkdirResolveOptions = { createDirectories: 0o777 };
|
|
431
426
|
const sharedAllowMissingNoFollowOptions = Object.freeze({ allowMissing: true, followFinal: false });
|
|
432
427
|
const sharedFastLocation = { node: undefined, parent: DUMMY_POOL_DIR_NODE, name: "", path: "" };
|
|
433
428
|
const resolvedVoid = Promise.resolve();
|
|
@@ -453,7 +448,7 @@ const compareOwnedMemory = async (own, peer, options) => {
|
|
|
453
448
|
let answer = "unknown";
|
|
454
449
|
const visited = new Set();
|
|
455
450
|
for (const [left, right] of [[own, peer], [peer, own]]) {
|
|
456
|
-
if (!registeredAuthorities.has(left.filesystem) || visited.has(left.filesystem))
|
|
451
|
+
if ((!registeredAuthorities.has(left.filesystem) && !ownedStores.has(left.filesystem)) || visited.has(left.filesystem))
|
|
457
452
|
continue;
|
|
458
453
|
visited.add(left.filesystem);
|
|
459
454
|
const comparison = left.filesystem.compareEntry;
|
|
@@ -602,32 +597,48 @@ class MemoryReadStream {
|
|
|
602
597
|
return STREAM_RESOLVED_DONE;
|
|
603
598
|
}
|
|
604
599
|
}
|
|
600
|
+
const SHARED_STOCK_MEMORY_CAPABILITIES = Object.freeze({
|
|
601
|
+
read: true, stat: true, readdir: true, realpath: true, access: true, open: true,
|
|
602
|
+
write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
|
|
603
|
+
mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
|
|
604
|
+
rename: true, atomicRenameNoReplace: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
|
|
605
|
+
streamingAppend: true, randomAccessWrite: true,
|
|
606
|
+
readOnly: false,
|
|
607
|
+
symlinks: true, conditionalChmod: true,
|
|
608
|
+
hardlinks: true,
|
|
609
|
+
permissions: true,
|
|
610
|
+
timestamps: true,
|
|
611
|
+
atomicRename: true,
|
|
612
|
+
atomicFileStaging: true, retainedStagingCleanup: true, retainedStagingWrite: true, atomicStagingAncestry: true, atomicFileMutation: true, atomicEntryRemoval: true, atomicEntryRemovalReceipt: true, atomicTreeRemoval: true,
|
|
613
|
+
synchronousDirectoryValidation: true, synchronousStagingResolution: true, guardedStagingPublication: true,
|
|
614
|
+
atomicDirectoryMetadata: true,
|
|
615
|
+
streamingRead: true,
|
|
616
|
+
retainedRead: true,
|
|
617
|
+
retainedResize: true,
|
|
618
|
+
streamingWrite: true,
|
|
619
|
+
descriptorWriteStream: true,
|
|
620
|
+
});
|
|
621
|
+
function customMemoryCapabilities(filesystem) {
|
|
622
|
+
return Object.freeze({
|
|
623
|
+
...SHARED_STOCK_MEMORY_CAPABILITIES,
|
|
624
|
+
get retainedResize() { return stockRetainedResize(filesystem); },
|
|
625
|
+
get descriptorWriteStream() { return stockDescriptorWrite(filesystem); },
|
|
626
|
+
});
|
|
627
|
+
}
|
|
605
628
|
export class MemoryFileSystem {
|
|
606
629
|
capabilitiesFor;
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
atomicRename: true,
|
|
620
|
-
atomicFileStaging: true, retainedStagingCleanup: true, retainedStagingWrite: true, atomicStagingAncestry: true, atomicFileMutation: true, atomicEntryRemoval: true, atomicEntryRemovalReceipt: true, atomicTreeRemoval: true,
|
|
621
|
-
synchronousDirectoryValidation: true, synchronousStagingResolution: true, guardedStagingPublication: true,
|
|
622
|
-
atomicDirectoryMetadata: true,
|
|
623
|
-
streamingRead: true,
|
|
624
|
-
retainedRead: true,
|
|
625
|
-
get retainedResize() { return stockRetainedResize(filesystem); },
|
|
626
|
-
streamingWrite: true,
|
|
627
|
-
get descriptorWriteStream() { return stockDescriptorWrite(filesystem); },
|
|
628
|
-
});
|
|
629
|
-
})(this);
|
|
630
|
-
identityScope = Symbol();
|
|
630
|
+
#customCapabilities;
|
|
631
|
+
#identityScopeSym;
|
|
632
|
+
get identityScope() {
|
|
633
|
+
return (this.#identityScopeSym ??= Symbol());
|
|
634
|
+
}
|
|
635
|
+
get capabilities() {
|
|
636
|
+
if (!this.#customCapabilities) {
|
|
637
|
+
this.#customCapabilities = customMemoryCapabilities(this);
|
|
638
|
+
this._owner.capabilities = this.#customCapabilities;
|
|
639
|
+
}
|
|
640
|
+
return this.#customCapabilities;
|
|
641
|
+
}
|
|
631
642
|
nextInode = 1;
|
|
632
643
|
ledger;
|
|
633
644
|
_cache;
|
|
@@ -636,26 +647,34 @@ export class MemoryFileSystem {
|
|
|
636
647
|
root;
|
|
637
648
|
totalBytes = 0;
|
|
638
649
|
symlinkCount = 0;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
650
|
+
#atomicView;
|
|
651
|
+
_getAtomicView() {
|
|
652
|
+
const owner = ownedStores.get(this);
|
|
653
|
+
if (!owner ||
|
|
654
|
+
Object.getPrototypeOf(this) !== MemoryFileSystem.prototype ||
|
|
655
|
+
this.root !== owner.root ||
|
|
656
|
+
this.ledger !== owner.ledger ||
|
|
657
|
+
this.capabilities !== owner.capabilities) {
|
|
658
|
+
return undefined;
|
|
643
659
|
}
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
660
|
+
const proto = MemoryFileSystem.prototype;
|
|
661
|
+
for (let i = 0; i < memoryImplementationKeys.length; i++) {
|
|
662
|
+
const name = memoryImplementationKeys[i];
|
|
663
|
+
const expected = memoryImplementationDescriptors[i];
|
|
664
|
+
if (name === "capabilities")
|
|
665
|
+
continue;
|
|
666
|
+
if (Object.prototype.hasOwnProperty.call(this, name)) {
|
|
667
|
+
const actual = Object.getOwnPropertyDescriptor(this, name);
|
|
668
|
+
if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
|
|
669
|
+
return undefined;
|
|
670
|
+
}
|
|
671
|
+
else if (expected.get !== undefined || expected.set !== undefined || proto[name] !== expected.value) {
|
|
672
|
+
const actual = Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, name);
|
|
673
|
+
if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return this.#atomicView ??= {
|
|
659
678
|
stat: (path) => {
|
|
660
679
|
this.validatePath(path, "overlayAtomicView");
|
|
661
680
|
let node = this.root;
|
|
@@ -677,30 +696,28 @@ export class MemoryFileSystem {
|
|
|
677
696
|
this.fail("ENOTDIR", "overlayAtomicView", path);
|
|
678
697
|
return [...node.entries.keys()];
|
|
679
698
|
},
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return true;
|
|
703
|
-
});
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
constructor(options = {}) {
|
|
702
|
+
this.ledger = new MemoryLedger(normalizeMemoryFileSystemLimits(options));
|
|
703
|
+
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes) {
|
|
704
|
+
replenishSharedMemoryPools();
|
|
705
|
+
}
|
|
706
|
+
const cache = new MemoryCache();
|
|
707
|
+
this._cache = cache;
|
|
708
|
+
memoryCaches.set(this.ledger, cache);
|
|
709
|
+
this.ledger.reserve(0, 1, "mkdir", "/");
|
|
710
|
+
this.root = this.directory(0o755);
|
|
711
|
+
const root = this.root;
|
|
712
|
+
const owner = {
|
|
713
|
+
root,
|
|
714
|
+
ledger: this.ledger,
|
|
715
|
+
capabilities: SHARED_STOCK_MEMORY_CAPABILITIES,
|
|
716
|
+
intact: () => this.root === root,
|
|
717
|
+
};
|
|
718
|
+
this._owner = owner;
|
|
719
|
+
ownedStores.set(this, owner);
|
|
720
|
+
registerLazyMemoryAtomicView(this, memoryImplementation._getAtomicView.value);
|
|
704
721
|
if (this.compareEntry === memoryImplementation.compareEntry?.value) {
|
|
705
722
|
registeredAuthorities.add(this);
|
|
706
723
|
registerEntryAuthority(this, compareOwnedMemory);
|
|
@@ -897,7 +914,6 @@ export class MemoryFileSystem {
|
|
|
897
914
|
if (alloc.isReleased64()) {
|
|
898
915
|
alloc.detachLedger(DUMMY_POOL_LEDGER);
|
|
899
916
|
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && sharedAllocationPoolLen < SHARED_POOL_CAPACITY) {
|
|
900
|
-
alloc.data.fill(0);
|
|
901
917
|
sharedAllocationPool[sharedAllocationPoolLen++] = alloc;
|
|
902
918
|
}
|
|
903
919
|
else if (cache.allocations.length < 128) {
|
|
@@ -907,7 +923,6 @@ export class MemoryFileSystem {
|
|
|
907
923
|
else if (alloc.isReleased65536()) {
|
|
908
924
|
alloc.detachLedger(DUMMY_POOL_LEDGER);
|
|
909
925
|
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && sharedLargeAllocationPoolLen < SHARED_LARGE_POOL_CAPACITY) {
|
|
910
|
-
alloc.data.fill(0);
|
|
911
926
|
sharedLargeAllocationPool[sharedLargeAllocationPoolLen++] = alloc;
|
|
912
927
|
}
|
|
913
928
|
}
|
|
@@ -953,14 +968,12 @@ export class MemoryFileSystem {
|
|
|
953
968
|
if (previous.isReleased64()) {
|
|
954
969
|
previous.detachLedger(DUMMY_POOL_LEDGER);
|
|
955
970
|
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && sharedAllocationPoolLen < SHARED_POOL_CAPACITY) {
|
|
956
|
-
previous.data.fill(0);
|
|
957
971
|
sharedAllocationPool[sharedAllocationPoolLen++] = previous;
|
|
958
972
|
}
|
|
959
973
|
}
|
|
960
974
|
else if (previous.isReleased65536()) {
|
|
961
975
|
previous.detachLedger(DUMMY_POOL_LEDGER);
|
|
962
976
|
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && sharedLargeAllocationPoolLen < SHARED_LARGE_POOL_CAPACITY) {
|
|
963
|
-
previous.data.fill(0);
|
|
964
977
|
sharedLargeAllocationPool[sharedLargeAllocationPoolLen++] = previous;
|
|
965
978
|
}
|
|
966
979
|
}
|
|
@@ -1372,17 +1385,6 @@ export class MemoryFileSystem {
|
|
|
1372
1385
|
}
|
|
1373
1386
|
}
|
|
1374
1387
|
try {
|
|
1375
|
-
// A shared slab's backing buffer exceeds the admitted slice capacity.
|
|
1376
|
-
// Finite file/storage ceilings require independently owned exact buffers.
|
|
1377
|
-
if (length <= 64 && this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes) {
|
|
1378
|
-
if (smallAllocOffset + length > SMALL_ALLOC_SLAB_SIZE) {
|
|
1379
|
-
smallAllocSlab = new Uint8Array(SMALL_ALLOC_SLAB_SIZE);
|
|
1380
|
-
smallAllocOffset = 0;
|
|
1381
|
-
}
|
|
1382
|
-
const slice = smallAllocSlab.subarray(smallAllocOffset, smallAllocOffset + length);
|
|
1383
|
-
smallAllocOffset += length;
|
|
1384
|
-
return new MemoryAllocation(slice, this.ledger);
|
|
1385
|
-
}
|
|
1386
1388
|
return new MemoryAllocation(new Uint8Array(length), this.ledger);
|
|
1387
1389
|
}
|
|
1388
1390
|
catch (cause) {
|
|
@@ -1568,11 +1570,12 @@ export class MemoryFileSystem {
|
|
|
1568
1570
|
}
|
|
1569
1571
|
if (position > curLen)
|
|
1570
1572
|
storage.fill(0, curLen, position);
|
|
1573
|
+
const source = data;
|
|
1571
1574
|
if (dataLen === data.byteLength) {
|
|
1572
1575
|
storage.set(data, position);
|
|
1573
1576
|
}
|
|
1574
|
-
else if (typeof
|
|
1575
|
-
|
|
1577
|
+
else if (typeof source.copy === "function") {
|
|
1578
|
+
source.copy(storage, position, 0, dataLen);
|
|
1576
1579
|
}
|
|
1577
1580
|
else {
|
|
1578
1581
|
for (let i = 0; i < dataLen; i++)
|
|
@@ -1771,7 +1774,7 @@ export class MemoryFileSystem {
|
|
|
1771
1774
|
1 + batchCount <= entries._keys.length) {
|
|
1772
1775
|
this.ledger.reserve(totalNameBytes, 2 * batchCount, "writeFile", fileNames[batchCount - 1]);
|
|
1773
1776
|
this.totalBytes += payloadBytesSum;
|
|
1774
|
-
const now =
|
|
1777
|
+
const now = Date.now();
|
|
1775
1778
|
const fileMode = typeModes.file | mode;
|
|
1776
1779
|
let ino = this.nextInode;
|
|
1777
1780
|
this.nextInode = ino + batchCount;
|
|
@@ -1844,7 +1847,7 @@ export class MemoryFileSystem {
|
|
|
1844
1847
|
const existing = nameHash !== undefined ? entries.getForWriteWithHash(name, nameHash) : entries.getForWrite(name);
|
|
1845
1848
|
if (existing === undefined && entries._next < entries._keys.length) {
|
|
1846
1849
|
this.ledger.reserve(name.length * 2, 2, "writeFile", name);
|
|
1847
|
-
const now =
|
|
1850
|
+
const now = Date.now();
|
|
1848
1851
|
const length = data.byteLength;
|
|
1849
1852
|
const node = sharedFileNodePool[--sharedFileNodePoolLen];
|
|
1850
1853
|
sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
|
|
@@ -1966,7 +1969,7 @@ export class MemoryFileSystem {
|
|
|
1966
1969
|
allocation.data.set(data);
|
|
1967
1970
|
this.ledger.reserve(nameBytes, 2, syscall, name);
|
|
1968
1971
|
try {
|
|
1969
|
-
const now =
|
|
1972
|
+
const now = Date.now();
|
|
1970
1973
|
const fileMode = typeModes.file | mode;
|
|
1971
1974
|
const view = zeroCopyConst ? new Uint8Array(data) : (capacity === length ? allocation.data : undefined);
|
|
1972
1975
|
let node;
|
|
@@ -2047,7 +2050,7 @@ export class MemoryFileSystem {
|
|
|
2047
2050
|
}
|
|
2048
2051
|
async readFile(path, options = {}) {
|
|
2049
2052
|
options.signal?.throwIfAborted();
|
|
2050
|
-
if (options.maxBytes !== undefined)
|
|
2053
|
+
if (options.maxBytes !== undefined && options.maxBytes !== Infinity)
|
|
2051
2054
|
this.integer(options.maxBytes, "readFile", path);
|
|
2052
2055
|
const node = this.file(path, "readFile");
|
|
2053
2056
|
this.permission(node, 4, "readFile", path);
|
|
@@ -2922,7 +2925,10 @@ export class MemoryFileSystem {
|
|
|
2922
2925
|
if (!descriptor || !("value" in descriptor) || descriptor.value !== memoryImplementation[name]?.value)
|
|
2923
2926
|
unsupported();
|
|
2924
2927
|
}
|
|
2925
|
-
const
|
|
2928
|
+
const capabilities = Object.getOwnPropertyDescriptor(this, "capabilities");
|
|
2929
|
+
const retainedRead = capabilities === undefined
|
|
2930
|
+
? Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get
|
|
2931
|
+
: capabilities.value?.retainedRead;
|
|
2926
2932
|
signal?.throwIfAborted();
|
|
2927
2933
|
if (retainedRead !== true)
|
|
2928
2934
|
unsupported();
|
|
@@ -3062,7 +3068,7 @@ function stockDescriptorWrite(filesystem) {
|
|
|
3062
3068
|
return false;
|
|
3063
3069
|
const owner = ownedStores.get(filesystem);
|
|
3064
3070
|
const capDesc = Object.getOwnPropertyDescriptor(filesystem, "capabilities");
|
|
3065
|
-
return !!capDesc && "value" in capDesc && capDesc.value === owner.capabilities;
|
|
3071
|
+
return (capDesc === undefined && Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get) || (!!capDesc && "value" in capDesc && capDesc.value === owner.capabilities);
|
|
3066
3072
|
}
|
|
3067
3073
|
function stockRetainedResize(filesystem) {
|
|
3068
3074
|
if (!stockDescriptorWrite(filesystem) || !isStockMemoryMethods(filesystem, stockRetainedResizeMethodNames, false))
|
|
@@ -3120,7 +3126,7 @@ export class MemoryRedirectHandle {
|
|
|
3120
3126
|
if (len === 0)
|
|
3121
3127
|
return;
|
|
3122
3128
|
const pos = this.append ? this.node.byteLength : this.position;
|
|
3123
|
-
const now = Date.now
|
|
3129
|
+
const now = Date.now();
|
|
3124
3130
|
this.fs.writeAtRange(this.node, src, len, pos, "write", this.path, now);
|
|
3125
3131
|
if (!this.append)
|
|
3126
3132
|
this.position = pos + len;
|
|
@@ -3140,7 +3146,7 @@ export class MemoryRedirectHandle {
|
|
|
3140
3146
|
mem.ledger.hasInfiniteRetained &&
|
|
3141
3147
|
mem.ledger.hasInfiniteFileBytes &&
|
|
3142
3148
|
mem.ledger.limits.maxBytes === undefined) {
|
|
3143
|
-
const now = Date.now
|
|
3149
|
+
const now = Date.now();
|
|
3144
3150
|
this.node.byteLength = len;
|
|
3145
3151
|
this.node.view = immutableData;
|
|
3146
3152
|
this.node.sourceRef = immutableData;
|
|
@@ -3266,7 +3272,7 @@ export function tryOpenMemoryRedirectHandleSync(filesystem, path, append, mode,
|
|
|
3266
3272
|
}
|
|
3267
3273
|
const cache = mem._cache;
|
|
3268
3274
|
cache.clearWrites();
|
|
3269
|
-
const now = Date.now
|
|
3275
|
+
const now = Date.now();
|
|
3270
3276
|
const fileMode = typeModes.file | validMode;
|
|
3271
3277
|
let newNode;
|
|
3272
3278
|
if (sharedFileNodePoolLen > 0) {
|
|
@@ -3421,7 +3427,7 @@ export function tryResolveMemoryDevicePath(filesystem, path, resizeCreate) {
|
|
|
3421
3427
|
start = slash + 1;
|
|
3422
3428
|
}
|
|
3423
3429
|
}
|
|
3424
|
-
const cachedMethodValuesMap = new WeakMap();
|
|
3430
|
+
const cachedMethodValuesMap = /* @__PURE__ */ new WeakMap();
|
|
3425
3431
|
function getExpectedMethodValues(names) {
|
|
3426
3432
|
let vals = cachedMethodValuesMap.get(names);
|
|
3427
3433
|
if (!vals) {
|
|
@@ -3467,7 +3473,7 @@ export function getLastReadMemoryFileSourceRef(view) {
|
|
|
3467
3473
|
lastReadViewSourceRef = undefined;
|
|
3468
3474
|
return ref;
|
|
3469
3475
|
}
|
|
3470
|
-
export function tryReadMemoryFileViewSync(filesystem, path, maxBytes, signal, captureSourceRef = false) {
|
|
3476
|
+
export function tryReadMemoryFileViewSync(filesystem, path, maxBytes, signal, captureSourceRef = false, beforeRead) {
|
|
3471
3477
|
// A capture belongs only to the most recent read, including failed/fallback reads.
|
|
3472
3478
|
lastReadViewData = undefined;
|
|
3473
3479
|
lastReadViewSourceRef = undefined;
|
|
@@ -3475,19 +3481,15 @@ export function tryReadMemoryFileViewSync(filesystem, path, maxBytes, signal, ca
|
|
|
3475
3481
|
if (mem._owner === undefined || !isStockMemoryMethods(mem, readFileFastMethodNames, false))
|
|
3476
3482
|
return undefined;
|
|
3477
3483
|
signal?.throwIfAborted();
|
|
3478
|
-
|
|
3484
|
+
beforeRead?.();
|
|
3485
|
+
if (maxBytes !== undefined && maxBytes !== Infinity)
|
|
3479
3486
|
mem.integer(maxBytes, "readFile", path);
|
|
3480
3487
|
const node = mem.file(path, "readFile");
|
|
3481
3488
|
mem.permission(node, 4, "readFile", path);
|
|
3482
3489
|
const data = node.data;
|
|
3483
3490
|
if (maxBytes !== undefined && data.byteLength > maxBytes)
|
|
3484
3491
|
mem.fail("EFBIG", "readFile", path);
|
|
3485
|
-
|
|
3486
|
-
node.atimeMs = Date.now();
|
|
3487
|
-
else if ((++fastWriteNowTick & 63) === 0)
|
|
3488
|
-
node.atimeMs = fastWriteCachedNow = Date.now();
|
|
3489
|
-
else
|
|
3490
|
-
node.atimeMs = fastWriteCachedNow;
|
|
3492
|
+
node.atimeMs = Date.now();
|
|
3491
3493
|
if (captureSourceRef && node.revision === 0) {
|
|
3492
3494
|
lastReadViewData = new WeakRef(data);
|
|
3493
3495
|
lastReadViewSourceRef = node.sourceRef === undefined ? undefined : new WeakRef(node.sourceRef);
|
|
@@ -3570,7 +3572,7 @@ export function tryGetMemoryDirectoryEntryNamesSync(filesystem, path) {
|
|
|
3570
3572
|
validatePath(path, owner.ledger.limits);
|
|
3571
3573
|
const root = mem.root;
|
|
3572
3574
|
if (path === "/") {
|
|
3573
|
-
if (((root.mode >> 6) &
|
|
3575
|
+
if (((root.mode >> 6) & 5) !== 5)
|
|
3574
3576
|
return undefined;
|
|
3575
3577
|
return root.entries;
|
|
3576
3578
|
}
|
|
@@ -3581,7 +3583,7 @@ export function tryGetMemoryDirectoryEntryNamesSync(filesystem, path) {
|
|
|
3581
3583
|
const fastPrefix = cache?.lastFastDirPrefix;
|
|
3582
3584
|
if (fastDir !== undefined &&
|
|
3583
3585
|
fastDir.nlink !== 0 &&
|
|
3584
|
-
((fastDir.mode >> 6) &
|
|
3586
|
+
((fastDir.mode >> 6) & 5) === 5 &&
|
|
3585
3587
|
fastPrefix !== undefined &&
|
|
3586
3588
|
(fastPrefix === path || (fastPrefix.length === path.length + 1 && fastPrefix.charCodeAt(path.length) === 47 && fastPrefix.startsWith(path)))) {
|
|
3587
3589
|
return fastDir.entries;
|
|
@@ -3594,7 +3596,7 @@ export function tryGetMemoryDirectoryEntryNamesSync(filesystem, path) {
|
|
|
3594
3596
|
const slash = path.indexOf("/", start);
|
|
3595
3597
|
if (slash === -1) {
|
|
3596
3598
|
const next = current.entries.getSubstr(path, start, path.length);
|
|
3597
|
-
if (!next || next.type !== "directory" || ((next.mode >> 6) &
|
|
3599
|
+
if (!next || next.type !== "directory" || ((next.mode >> 6) & 5) !== 5)
|
|
3598
3600
|
return undefined;
|
|
3599
3601
|
return next.entries;
|
|
3600
3602
|
}
|
|
@@ -3648,7 +3650,7 @@ export function tryMkdirMemorySync(filesystem, path, recursive, mode, signal, di
|
|
|
3648
3650
|
let next = current.entries.get(seg);
|
|
3649
3651
|
if (!next) {
|
|
3650
3652
|
mem.permission(current, 3, "mkdir", path);
|
|
3651
|
-
next = mem.addDirectoryNode(current, seg, validMode, "mkdir", path,
|
|
3653
|
+
next = mem.addDirectoryNode(current, seg, validMode, "mkdir", path, Date.now());
|
|
3652
3654
|
}
|
|
3653
3655
|
else if (next.type !== "directory") {
|
|
3654
3656
|
mem.fail(slash === -1 ? "EEXIST" : "ENOTDIR", "mkdir", path);
|
|
@@ -3669,7 +3671,7 @@ export function tryMkdirMemorySync(filesystem, path, recursive, mode, signal, di
|
|
|
3669
3671
|
if (location.node)
|
|
3670
3672
|
mem.fail("EEXIST", "mkdir", path);
|
|
3671
3673
|
mem.permission(location.parent, 3, "mkdir", path);
|
|
3672
|
-
mem.addDirectoryNode(location.parent, location.name, validMode, "mkdir", path,
|
|
3674
|
+
mem.addDirectoryNode(location.parent, location.name, validMode, "mkdir", path, Date.now());
|
|
3673
3675
|
return true;
|
|
3674
3676
|
}
|
|
3675
3677
|
export function tryRmRfMemorySync(filesystem, path, signal) {
|
|
@@ -3719,7 +3721,7 @@ export function tryRmRfMemorySync(filesystem, path, signal) {
|
|
|
3719
3721
|
sharedFastLocation.name = targetName;
|
|
3720
3722
|
sharedFastLocation.path = path;
|
|
3721
3723
|
try {
|
|
3722
|
-
mem.removeLocation(sharedFastLocation, path, "rm", true,
|
|
3724
|
+
mem.removeLocation(sharedFastLocation, path, "rm", true, Date.now());
|
|
3723
3725
|
}
|
|
3724
3726
|
finally {
|
|
3725
3727
|
sharedFastLocation.node = undefined;
|
|
@@ -3748,3 +3750,17 @@ export function tryWriteMemoryFileInDirSync(filesystem, dirPrefix, name, data, a
|
|
|
3748
3750
|
mem.writeMemoryFileInDirFast(dirPrefix, name, data, append, mode);
|
|
3749
3751
|
return true;
|
|
3750
3752
|
}
|
|
3753
|
+
const _memHooks = (globalThis.__safeBashMemHooks ??= { protos: new Set(), byProto: new Map() });
|
|
3754
|
+
_memHooks.protos.add(MemoryFileSystem.prototype);
|
|
3755
|
+
_memHooks.byProto.set(MemoryFileSystem.prototype, {
|
|
3756
|
+
tryGetMemoryDirectoryEntryNamesSync,
|
|
3757
|
+
tryReadMemoryFileViewSync,
|
|
3758
|
+
tryResolveMemoryDevicePath,
|
|
3759
|
+
tryOpenMemoryRedirectHandleSync,
|
|
3760
|
+
tryWriteMemoryFileSync,
|
|
3761
|
+
tryMkdirMemorySync,
|
|
3762
|
+
tryRmRfMemorySync,
|
|
3763
|
+
tryWriteMemoryFileInDirSync,
|
|
3764
|
+
});
|
|
3765
|
+
_memHooks.isCleanAbsolutePath = isCleanAbsolutePath;
|
|
3766
|
+
_memHooks.bindConditionalMutation = bindConditionalMutation;
|
|
@@ -84,8 +84,10 @@ export class MemoryAllocation {
|
|
|
84
84
|
return;
|
|
85
85
|
if (this.references <= 0)
|
|
86
86
|
throw new Error("Memory allocation already released");
|
|
87
|
-
if (--this.references === 0)
|
|
87
|
+
if (--this.references === 0) {
|
|
88
|
+
this.data.fill(0);
|
|
88
89
|
this.ledger.release(this.data.byteLength, 0);
|
|
90
|
+
}
|
|
89
91
|
}
|
|
90
92
|
isReleased64() {
|
|
91
93
|
return this.references === 0 && this.data.byteLength === 64;
|
|
@@ -7,6 +7,9 @@ export const defaultMemoryFileSystemLimits = Object.freeze({
|
|
|
7
7
|
maxMetadataUnits: Infinity,
|
|
8
8
|
});
|
|
9
9
|
export function normalizeMemoryFileSystemLimits(options) {
|
|
10
|
+
if (options === undefined || (typeof options === "object" && options !== null && Object.getPrototypeOf(options) === Object.prototype && Reflect.ownKeys(options).length === 0)) {
|
|
11
|
+
return defaultMemoryFileSystemLimits;
|
|
12
|
+
}
|
|
10
13
|
const keys = ["maxPathBytes", "maxPathComponents", "maxFileBytes", "maxRetainedBytes", "maxMetadataUnits"];
|
|
11
14
|
const record = readConfigRecord(options, "memory option", [...keys, "maxBytes"]);
|
|
12
15
|
const limits = { ...defaultMemoryFileSystemLimits };
|
|
@@ -29,7 +29,7 @@ export async function resolveEntryView(filesystem, path, options = {}) {
|
|
|
29
29
|
readOnly ||= location.readOnly === true || location.filesystem.capabilities.readOnly === true;
|
|
30
30
|
if (location.stat)
|
|
31
31
|
return { filesystem: location.filesystem, path: location.path, stat: location.stat, readOnly };
|
|
32
|
-
const resolve = resolvers.get(location.filesystem);
|
|
32
|
+
const resolve = resolvers.get(location.filesystem) ?? location.filesystem._resolveEntryView;
|
|
33
33
|
if (!resolve) {
|
|
34
34
|
let stat;
|
|
35
35
|
let followedPath;
|
|
@@ -49,7 +49,7 @@ export async function resolveEntryView(filesystem, path, options = {}) {
|
|
|
49
49
|
}
|
|
50
50
|
let next;
|
|
51
51
|
try {
|
|
52
|
-
next = await resolve(location.path, options);
|
|
52
|
+
next = await resolve.call(location.filesystem, location.path, options);
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
55
55
|
options.signal?.throwIfAborted();
|
|
@@ -74,7 +74,7 @@ export async function compareResolvedEntries(own, peer, options = {}) {
|
|
|
74
74
|
let result = "unknown";
|
|
75
75
|
for (const [left, right] of [[own, peer], [peer, own]]) {
|
|
76
76
|
options.signal?.throwIfAborted();
|
|
77
|
-
const authority = authorities.get(left.filesystem);
|
|
77
|
+
const authority = authorities.get(left.filesystem) ?? left.filesystem._entryAuthority;
|
|
78
78
|
const key = authority ?? left.filesystem;
|
|
79
79
|
if (queried.has(key))
|
|
80
80
|
continue;
|
|
@@ -9,7 +9,8 @@ export function withObjectFileDescriptors(filesystem, store, options = {}) {
|
|
|
9
9
|
const maxStagedPages = options.maxStagedPages ?? Infinity;
|
|
10
10
|
const maxFileBytes = options.maxFileBytes ?? Infinity;
|
|
11
11
|
const maxOpenFiles = options.maxOpenFiles ?? Infinity;
|
|
12
|
-
if (!
|
|
12
|
+
if (!Number.isSafeInteger(chunkBytes) || chunkBytes < 1
|
|
13
|
+
|| ![maxStagedBytes, maxStagedPages, maxFileBytes, maxOpenFiles].every(value => value === Infinity || Number.isSafeInteger(value) && value > 0)
|
|
13
14
|
|| typeof store.acquire !== "function"
|
|
14
15
|
|| store.publish !== undefined && typeof store.publish !== "function"
|
|
15
16
|
|| store.createStaging !== undefined && typeof store.createStaging !== "function")
|
|
@@ -202,7 +202,7 @@ export class ReadOnlyFileSystem {
|
|
|
202
202
|
readOnly("openResizeFile", path);
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
const readOnlyImplementation = Object.getOwnPropertyDescriptors(ReadOnlyFileSystem.prototype);
|
|
205
|
+
const readOnlyImplementation = /* @__PURE__ */ Object.getOwnPropertyDescriptors(ReadOnlyFileSystem.prototype);
|
|
206
206
|
export function createReadOnlyFileSystem(filesystem) {
|
|
207
207
|
return new ReadOnlyFileSystem(filesystem);
|
|
208
208
|
}
|
|
@@ -608,8 +608,9 @@ export class RealFileSystem {
|
|
|
608
608
|
}
|
|
609
609
|
async readFile(path, options = {}) {
|
|
610
610
|
return this.operation("readFile", path, options, async () => {
|
|
611
|
-
const maxBytes = options.maxBytes ??
|
|
612
|
-
|
|
611
|
+
const maxBytes = options.maxBytes ?? Infinity;
|
|
612
|
+
if (maxBytes !== Infinity)
|
|
613
|
+
integer(maxBytes);
|
|
613
614
|
return collectBytes(this.readStream(path, options), { maxBytes, ...options });
|
|
614
615
|
});
|
|
615
616
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import type { RequestOptions } from "node:http";
|
|
2
1
|
import type { RequestScope, WireResponse } from "./request.js";
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export type S3HttpRequestFactory = never;
|
|
3
|
+
interface FetchRequestOptions {
|
|
4
|
+
readonly protocol?: string | undefined;
|
|
5
|
+
readonly hostname?: string | undefined;
|
|
6
|
+
readonly port?: string | number | undefined;
|
|
7
|
+
readonly path?: string | undefined;
|
|
8
|
+
readonly method?: string | undefined;
|
|
9
|
+
readonly headers?: Record<string, string> | undefined;
|
|
10
|
+
readonly agent?: false;
|
|
11
|
+
readonly maxHeaderSize?: number;
|
|
12
|
+
readonly rejectUnauthorized?: true;
|
|
13
|
+
}
|
|
14
|
+
export declare function sendRequest(options: FetchRequestOptions, body: Uint8Array, scope: RequestScope, factory?: S3HttpRequestFactory): Promise<WireResponse>;
|
|
15
|
+
export {};
|