@zenfs/core 1.9.5 → 1.10.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/dist/backends/fetch.d.ts +4 -4
- package/dist/backends/fetch.js +2 -2
- package/dist/backends/index.d.ts +1 -0
- package/dist/backends/index.js +1 -0
- package/dist/backends/memory.d.ts +26 -4
- package/dist/backends/memory.js +19 -3
- package/dist/backends/overlay.d.ts +5 -1
- package/dist/backends/overlay.js +7 -1
- package/dist/backends/passthrough.d.ts +2 -1
- package/dist/backends/passthrough.js +7 -0
- package/dist/backends/single_buffer.d.ts +149 -0
- package/dist/backends/single_buffer.js +498 -0
- package/dist/backends/store/fs.d.ts +5 -1
- package/dist/backends/store/fs.js +10 -0
- package/dist/backends/store/store.d.ts +5 -0
- package/dist/internal/devices.js +3 -1
- package/dist/internal/file_index.d.ts +8 -0
- package/dist/internal/file_index.js +22 -2
- package/dist/internal/index_fs.d.ts +2 -1
- package/dist/internal/index_fs.js +3 -0
- package/dist/internal/inode.d.ts +8 -0
- package/dist/internal/inode.js +8 -0
- package/dist/stats.js +5 -5
- package/dist/vfs/path.js +7 -7
- package/package.json +2 -2
- package/tests/setup/single-buffer.ts +9 -0
package/dist/backends/fetch.d.ts
CHANGED
|
@@ -16,10 +16,10 @@ export interface FetchOptions extends SharedConfig {
|
|
|
16
16
|
* Defaults to `index.json`.
|
|
17
17
|
*/
|
|
18
18
|
index?: string | IndexData;
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
19
|
+
/**
|
|
20
|
+
* Used as the URL prefix for fetched files.
|
|
21
21
|
*/
|
|
22
|
-
baseUrl
|
|
22
|
+
baseUrl: string;
|
|
23
23
|
/**
|
|
24
24
|
* If true, enables writing to the remote (using post and delete)
|
|
25
25
|
* @default false
|
|
@@ -56,7 +56,7 @@ declare const _Fetch: {
|
|
|
56
56
|
};
|
|
57
57
|
readonly baseUrl: {
|
|
58
58
|
readonly type: "string";
|
|
59
|
-
readonly required:
|
|
59
|
+
readonly required: true;
|
|
60
60
|
};
|
|
61
61
|
readonly requestInit: {
|
|
62
62
|
readonly type: "object";
|
package/dist/backends/fetch.js
CHANGED
|
@@ -88,7 +88,7 @@ const _Fetch = {
|
|
|
88
88
|
name: 'Fetch',
|
|
89
89
|
options: {
|
|
90
90
|
index: { type: ['string', 'object'], required: false },
|
|
91
|
-
baseUrl: { type: 'string', required:
|
|
91
|
+
baseUrl: { type: 'string', required: true },
|
|
92
92
|
requestInit: { type: 'object', required: false },
|
|
93
93
|
remoteWrite: { type: 'boolean', required: false },
|
|
94
94
|
},
|
|
@@ -97,7 +97,7 @@ const _Fetch = {
|
|
|
97
97
|
},
|
|
98
98
|
async create(options) {
|
|
99
99
|
var _a;
|
|
100
|
-
const url = new URL(options.baseUrl
|
|
100
|
+
const url = new URL(options.baseUrl);
|
|
101
101
|
url.pathname = normalizePath(url.pathname);
|
|
102
102
|
let baseUrl = url.toString();
|
|
103
103
|
if (baseUrl.at(-1) == '/')
|
package/dist/backends/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './memory.js';
|
|
|
4
4
|
export * from './overlay.js';
|
|
5
5
|
export * from './passthrough.js';
|
|
6
6
|
export * from './port/fs.js';
|
|
7
|
+
export * from './single_buffer.js';
|
|
7
8
|
export * from './store/fs.js';
|
|
8
9
|
export * from './store/map.js';
|
|
9
10
|
export * from './store/store.js';
|
package/dist/backends/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './memory.js';
|
|
|
4
4
|
export * from './overlay.js';
|
|
5
5
|
export * from './passthrough.js';
|
|
6
6
|
export * from './port/fs.js';
|
|
7
|
+
export * from './single_buffer.js';
|
|
7
8
|
export * from './store/fs.js';
|
|
8
9
|
export * from './store/map.js';
|
|
9
10
|
export * from './store/store.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UsageInfo } from '../internal/filesystem.js';
|
|
1
2
|
import { StoreFS } from './store/fs.js';
|
|
2
3
|
import { SyncMapTransaction, type SyncMapStore } from './store/map.js';
|
|
3
4
|
/**
|
|
@@ -5,24 +6,45 @@ import { SyncMapTransaction, type SyncMapStore } from './store/map.js';
|
|
|
5
6
|
* @category Stores and Transactions
|
|
6
7
|
*/
|
|
7
8
|
export declare class InMemoryStore extends Map<number, Uint8Array> implements SyncMapStore {
|
|
9
|
+
readonly maxSize: number;
|
|
8
10
|
readonly label?: string | undefined;
|
|
9
11
|
readonly flags: readonly [];
|
|
10
12
|
readonly name = "tmpfs";
|
|
11
|
-
constructor(label?: string | undefined);
|
|
13
|
+
constructor(maxSize?: number, label?: string | undefined);
|
|
12
14
|
sync(): Promise<void>;
|
|
13
15
|
transaction(): SyncMapTransaction;
|
|
16
|
+
get bytes(): number;
|
|
17
|
+
usage(): UsageInfo;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Options for an in-memory backend
|
|
21
|
+
* @category Backends and Configuration
|
|
22
|
+
*/
|
|
23
|
+
export interface InMemoryOptions {
|
|
24
|
+
/** The maximum size of the store. Defaults to 4 GiB */
|
|
25
|
+
maxSize?: number;
|
|
26
|
+
/** The label to use for the store and file system */
|
|
27
|
+
label?: string;
|
|
28
|
+
/** @deprecated use `label` */
|
|
29
|
+
name?: string;
|
|
14
30
|
}
|
|
15
31
|
declare const _InMemory: {
|
|
16
32
|
readonly name: "InMemory";
|
|
17
33
|
readonly options: {
|
|
34
|
+
readonly maxSize: {
|
|
35
|
+
readonly type: "number";
|
|
36
|
+
readonly required: false;
|
|
37
|
+
};
|
|
38
|
+
readonly label: {
|
|
39
|
+
readonly type: "string";
|
|
40
|
+
readonly required: false;
|
|
41
|
+
};
|
|
18
42
|
readonly name: {
|
|
19
43
|
readonly type: "string";
|
|
20
44
|
readonly required: false;
|
|
21
45
|
};
|
|
22
46
|
};
|
|
23
|
-
readonly create: ({ name }:
|
|
24
|
-
name?: string;
|
|
25
|
-
}) => StoreFS<InMemoryStore>;
|
|
47
|
+
readonly create: ({ maxSize, label, name }: InMemoryOptions) => StoreFS<InMemoryStore>;
|
|
26
48
|
};
|
|
27
49
|
type _InMemory = typeof _InMemory;
|
|
28
50
|
export interface InMemory extends _InMemory {
|
package/dist/backends/memory.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { size_max } from '../vfs/constants.js';
|
|
1
2
|
import { StoreFS } from './store/fs.js';
|
|
2
3
|
import { SyncMapTransaction } from './store/map.js';
|
|
3
4
|
/**
|
|
@@ -5,8 +6,9 @@ import { SyncMapTransaction } from './store/map.js';
|
|
|
5
6
|
* @category Stores and Transactions
|
|
6
7
|
*/
|
|
7
8
|
export class InMemoryStore extends Map {
|
|
8
|
-
constructor(label) {
|
|
9
|
+
constructor(maxSize = size_max, label) {
|
|
9
10
|
super();
|
|
11
|
+
this.maxSize = maxSize;
|
|
10
12
|
this.label = label;
|
|
11
13
|
this.flags = [];
|
|
12
14
|
this.name = 'tmpfs';
|
|
@@ -15,14 +17,28 @@ export class InMemoryStore extends Map {
|
|
|
15
17
|
transaction() {
|
|
16
18
|
return new SyncMapTransaction(this);
|
|
17
19
|
}
|
|
20
|
+
get bytes() {
|
|
21
|
+
let size = this.size * 4;
|
|
22
|
+
for (const data of this.values())
|
|
23
|
+
size += data.byteLength;
|
|
24
|
+
return size;
|
|
25
|
+
}
|
|
26
|
+
usage() {
|
|
27
|
+
return {
|
|
28
|
+
totalSpace: this.maxSize,
|
|
29
|
+
freeSpace: this.maxSize - this.bytes,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
18
32
|
}
|
|
19
33
|
const _InMemory = {
|
|
20
34
|
name: 'InMemory',
|
|
21
35
|
options: {
|
|
36
|
+
maxSize: { type: 'number', required: false },
|
|
37
|
+
label: { type: 'string', required: false },
|
|
22
38
|
name: { type: 'string', required: false },
|
|
23
39
|
},
|
|
24
|
-
create({ name }) {
|
|
25
|
-
const fs = new StoreFS(new InMemoryStore(name));
|
|
40
|
+
create({ maxSize, label, name }) {
|
|
41
|
+
const fs = new StoreFS(new InMemoryStore(maxSize, label !== null && label !== void 0 ? label : name));
|
|
26
42
|
fs.checkRootSync();
|
|
27
43
|
return fs;
|
|
28
44
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { File } from '../internal/file.js';
|
|
2
|
-
import type { CreationOptions } from '../internal/filesystem.js';
|
|
2
|
+
import type { CreationOptions, UsageInfo } from '../internal/filesystem.js';
|
|
3
3
|
import type { Stats } from '../stats.js';
|
|
4
4
|
import type { InodeLike } from '../internal/inode.js';
|
|
5
5
|
import { FileSystem } from '../internal/filesystem.js';
|
|
@@ -37,6 +37,10 @@ export declare class OverlayFS extends FileSystem {
|
|
|
37
37
|
private _deleteLogError?;
|
|
38
38
|
private _ready;
|
|
39
39
|
constructor({ writable, readable }: OverlayOptions);
|
|
40
|
+
/**
|
|
41
|
+
* @todo Consider trying to track information on the writable as well
|
|
42
|
+
*/
|
|
43
|
+
usage(): UsageInfo;
|
|
40
44
|
sync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): Promise<void>;
|
|
41
45
|
syncSync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): void;
|
|
42
46
|
read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
|
package/dist/backends/overlay.js
CHANGED
|
@@ -86,10 +86,16 @@ export class OverlayFS extends FileSystem {
|
|
|
86
86
|
this.writable = writable;
|
|
87
87
|
this.readable = readable;
|
|
88
88
|
if (this.writable.attributes.has('no_write')) {
|
|
89
|
-
throw err(new ErrnoError(Errno.EINVAL, 'Writable file can not be written to'));
|
|
89
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Writable file system can not be written to'));
|
|
90
90
|
}
|
|
91
91
|
this._ready = this._initialize();
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* @todo Consider trying to track information on the writable as well
|
|
95
|
+
*/
|
|
96
|
+
usage() {
|
|
97
|
+
return this.readable.usage();
|
|
98
|
+
}
|
|
93
99
|
async sync(path, data, stats) {
|
|
94
100
|
await this.copyForWrite(path);
|
|
95
101
|
await this.writable.sync(path, data, stats);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as fs from 'node:fs';
|
|
2
2
|
import { File } from '../internal/file.js';
|
|
3
|
-
import { FileSystem } from '../internal/filesystem.js';
|
|
3
|
+
import { FileSystem, type UsageInfo } from '../internal/filesystem.js';
|
|
4
4
|
import type { InodeLike } from '../internal/inode.js';
|
|
5
5
|
import { Stats } from '../stats.js';
|
|
6
6
|
export type NodeFS = typeof fs;
|
|
@@ -16,6 +16,7 @@ export declare class PassthroughFS extends FileSystem {
|
|
|
16
16
|
readonly nodeFS: NodeFS;
|
|
17
17
|
readonly prefix: string;
|
|
18
18
|
constructor(nodeFS: NodeFS, prefix: string);
|
|
19
|
+
usage(): UsageInfo;
|
|
19
20
|
path(path: string): string;
|
|
20
21
|
error(err: unknown, path: string): never;
|
|
21
22
|
/**
|
|
@@ -141,6 +141,13 @@ export class PassthroughFS extends FileSystem {
|
|
|
141
141
|
this.nodeFS = nodeFS;
|
|
142
142
|
this.prefix = prefix;
|
|
143
143
|
}
|
|
144
|
+
usage() {
|
|
145
|
+
const info = this.nodeFS.statfsSync(this.prefix);
|
|
146
|
+
return {
|
|
147
|
+
totalSpace: info.bsize * info.blocks,
|
|
148
|
+
freeSpace: info.bsize * info.bfree,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
144
151
|
path(path) {
|
|
145
152
|
return join(this.prefix, path.slice(1));
|
|
146
153
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { UsageInfo } from '../internal/filesystem.js';
|
|
2
|
+
import { StoreFS } from './store/fs.js';
|
|
3
|
+
import { SyncMapTransaction, type SyncMapStore } from './store/map.js';
|
|
4
|
+
import type { Store } from './store/store.js';
|
|
5
|
+
declare class MetadataEntry {
|
|
6
|
+
/** Inode or data ID */
|
|
7
|
+
id: number;
|
|
8
|
+
/** Reserved for 64-bit offset expansion */
|
|
9
|
+
protected offset_: number;
|
|
10
|
+
/** Offset into the buffer the data is stored at. */
|
|
11
|
+
offset: number;
|
|
12
|
+
/** The size of the data */
|
|
13
|
+
size: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A block of metadata for a single-buffer file system.
|
|
17
|
+
* This metadata maps IDs (for inodes and data) to actual offsets in the buffer.
|
|
18
|
+
* This is done since IDs are not guaranteed to be sequential.
|
|
19
|
+
*/
|
|
20
|
+
declare class MetadataBlock {
|
|
21
|
+
protected readonly superblock: SuperBlock;
|
|
22
|
+
offset: number;
|
|
23
|
+
constructor(superblock: SuperBlock, offset?: number);
|
|
24
|
+
/**
|
|
25
|
+
* The crc32c checksum for the metadata block.
|
|
26
|
+
* @privateRemarks Keep this first!
|
|
27
|
+
*/
|
|
28
|
+
checksum: number;
|
|
29
|
+
/** The (last) time this metadata block was updated */
|
|
30
|
+
timestamp: number;
|
|
31
|
+
/** Reserved for 64-bit offset expansion */
|
|
32
|
+
protected previous_offset_: number;
|
|
33
|
+
/** Offset to the previous metadata block */
|
|
34
|
+
previous_offset: number;
|
|
35
|
+
protected _previous?: MetadataBlock;
|
|
36
|
+
get previous(): MetadataBlock | undefined;
|
|
37
|
+
/** Metadata entries. */
|
|
38
|
+
entries: MetadataEntry[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The super block structure for a single-buffer file system
|
|
42
|
+
*/
|
|
43
|
+
declare class SuperBlock {
|
|
44
|
+
readonly store: SingleBufferStore;
|
|
45
|
+
constructor(store: SingleBufferStore);
|
|
46
|
+
/**
|
|
47
|
+
* The crc32c checksum for the super block.
|
|
48
|
+
* @privateRemarks Keep this first!
|
|
49
|
+
*/
|
|
50
|
+
checksum: number;
|
|
51
|
+
/** Signature for the superblock. */
|
|
52
|
+
magic: number;
|
|
53
|
+
/** The version of the on-disk format */
|
|
54
|
+
version: number;
|
|
55
|
+
/** Which format of `Inode` is used */
|
|
56
|
+
inode_format: number;
|
|
57
|
+
/** Flags for the file system. Currently unused */
|
|
58
|
+
flags: number;
|
|
59
|
+
/** The number of used bytes, including the super block and metadata */
|
|
60
|
+
used_bytes: bigint;
|
|
61
|
+
/** The total size of the entire file system, including the super block and metadata */
|
|
62
|
+
total_bytes: bigint;
|
|
63
|
+
/** An ID for this file system */
|
|
64
|
+
id: bigint;
|
|
65
|
+
/**
|
|
66
|
+
* The size in bytes of a metadata block.
|
|
67
|
+
* Not currently configurable.
|
|
68
|
+
*/
|
|
69
|
+
metadata_block_size: number;
|
|
70
|
+
/** Reserved for 64-bit offset expansion */
|
|
71
|
+
protected metadata_offset_: number;
|
|
72
|
+
/** Offset of the current metadata block */
|
|
73
|
+
metadata_offset: number;
|
|
74
|
+
metadata: MetadataBlock;
|
|
75
|
+
/** An optional label for the file system */
|
|
76
|
+
label: string;
|
|
77
|
+
/** Padded to 256 bytes */
|
|
78
|
+
_padding: number[];
|
|
79
|
+
/**
|
|
80
|
+
* Rotate out the current metadata block.
|
|
81
|
+
* Allocates a new metadata block, moves the current one to backup,
|
|
82
|
+
* and updates used_bytes accordingly.
|
|
83
|
+
* @returns the new metadata block
|
|
84
|
+
*/
|
|
85
|
+
rotateMetadata(): MetadataBlock;
|
|
86
|
+
/**
|
|
87
|
+
* Checks to see if `length` bytes are unused, starting at `offset`.
|
|
88
|
+
* @internal Not for external use!
|
|
89
|
+
*/
|
|
90
|
+
isUnused(offset: number, length: number): boolean;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @category Stores and Transactions
|
|
95
|
+
*/
|
|
96
|
+
export declare class SingleBufferStore implements SyncMapStore {
|
|
97
|
+
readonly flags: readonly [];
|
|
98
|
+
readonly name = "sbfs";
|
|
99
|
+
readonly id = 1935828595;
|
|
100
|
+
protected superblock: SuperBlock;
|
|
101
|
+
/**
|
|
102
|
+
* @internal @hidden
|
|
103
|
+
*/
|
|
104
|
+
readonly _view: DataView;
|
|
105
|
+
/**
|
|
106
|
+
* @internal @hidden
|
|
107
|
+
*/
|
|
108
|
+
readonly _buffer: Uint8Array;
|
|
109
|
+
constructor(buffer: ArrayBufferLike | ArrayBufferView);
|
|
110
|
+
/**
|
|
111
|
+
* Update a block's checksum and write it to the store's buffer.
|
|
112
|
+
* @internal @hidden
|
|
113
|
+
*/
|
|
114
|
+
_write(value: SuperBlock | MetadataBlock): void;
|
|
115
|
+
keys(): Iterable<number>;
|
|
116
|
+
get(id: number): Uint8Array | undefined;
|
|
117
|
+
set(id: number, data: Uint8Array): void;
|
|
118
|
+
delete(id: number): void;
|
|
119
|
+
_fs?: StoreFS<Store> | undefined;
|
|
120
|
+
sync(): Promise<void>;
|
|
121
|
+
usage(): UsageInfo;
|
|
122
|
+
transaction(): SyncMapTransaction;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Options for the `SingleBuffer` backend
|
|
126
|
+
* @category Backends and Configuration
|
|
127
|
+
*/
|
|
128
|
+
export interface SingleBufferOptions {
|
|
129
|
+
buffer: ArrayBufferLike | ArrayBufferView;
|
|
130
|
+
}
|
|
131
|
+
declare const _SingleBuffer: {
|
|
132
|
+
readonly name: "SingleBuffer";
|
|
133
|
+
readonly options: {
|
|
134
|
+
readonly buffer: {
|
|
135
|
+
readonly type: "object";
|
|
136
|
+
readonly required: true;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
readonly create: ({ buffer }: SingleBufferOptions) => StoreFS<SingleBufferStore>;
|
|
140
|
+
};
|
|
141
|
+
type _SingleBuffer = typeof _SingleBuffer;
|
|
142
|
+
export interface SingleBuffer extends _SingleBuffer {
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A backend that uses a single buffer for storing data
|
|
146
|
+
* @category Backends and Configuration
|
|
147
|
+
*/
|
|
148
|
+
export declare const SingleBuffer: SingleBuffer;
|
|
149
|
+
export {};
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
|
|
36
|
+
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
37
|
+
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
38
|
+
};
|
|
39
|
+
import { deserialize, member, offsetof, serialize, sizeof, struct, types as t } from 'utilium';
|
|
40
|
+
import { crc32c } from 'utilium/checksum.js';
|
|
41
|
+
import { Errno, ErrnoError } from '../internal/error.js';
|
|
42
|
+
import { _inode_version } from '../internal/inode.js';
|
|
43
|
+
import { crit, warn } from '../internal/log.js';
|
|
44
|
+
import { StoreFS } from './store/fs.js';
|
|
45
|
+
import { SyncMapTransaction } from './store/map.js';
|
|
46
|
+
let MetadataEntry = (() => {
|
|
47
|
+
var _a, _b, _c, _d;
|
|
48
|
+
let _classDecorators = [struct()];
|
|
49
|
+
let _classDescriptor;
|
|
50
|
+
let _classExtraInitializers = [];
|
|
51
|
+
let _classThis;
|
|
52
|
+
let _id_decorators;
|
|
53
|
+
let _id_initializers = [];
|
|
54
|
+
let _id_extraInitializers = [];
|
|
55
|
+
let _offset__decorators;
|
|
56
|
+
let _offset__initializers = [];
|
|
57
|
+
let _offset__extraInitializers = [];
|
|
58
|
+
let _offset_decorators;
|
|
59
|
+
let _offset_initializers = [];
|
|
60
|
+
let _offset_extraInitializers = [];
|
|
61
|
+
let _size_decorators;
|
|
62
|
+
let _size_initializers = [];
|
|
63
|
+
let _size_extraInitializers = [];
|
|
64
|
+
var MetadataEntry = _classThis = class {
|
|
65
|
+
constructor() {
|
|
66
|
+
/** Inode or data ID */
|
|
67
|
+
this.id = __runInitializers(this, _id_initializers, 0);
|
|
68
|
+
/** Reserved for 64-bit offset expansion */
|
|
69
|
+
this.offset_ = (__runInitializers(this, _id_extraInitializers), __runInitializers(this, _offset__initializers, 0));
|
|
70
|
+
/** Offset into the buffer the data is stored at. */
|
|
71
|
+
this.offset = (__runInitializers(this, _offset__extraInitializers), __runInitializers(this, _offset_initializers, 0));
|
|
72
|
+
/** The size of the data */
|
|
73
|
+
this.size = (__runInitializers(this, _offset_extraInitializers), __runInitializers(this, _size_initializers, 0));
|
|
74
|
+
__runInitializers(this, _size_extraInitializers);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
__setFunctionName(_classThis, "MetadataEntry");
|
|
78
|
+
(() => {
|
|
79
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
80
|
+
_id_decorators = [(_a = t).uint32.bind(_a)];
|
|
81
|
+
_offset__decorators = [(_b = t).uint32.bind(_b)];
|
|
82
|
+
_offset_decorators = [(_c = t).uint32.bind(_c)];
|
|
83
|
+
_size_decorators = [(_d = t).uint32.bind(_d)];
|
|
84
|
+
__esDecorate(null, null, _id_decorators, { kind: "field", name: "id", static: false, private: false, access: { has: obj => "id" in obj, get: obj => obj.id, set: (obj, value) => { obj.id = value; } }, metadata: _metadata }, _id_initializers, _id_extraInitializers);
|
|
85
|
+
__esDecorate(null, null, _offset__decorators, { kind: "field", name: "offset_", static: false, private: false, access: { has: obj => "offset_" in obj, get: obj => obj.offset_, set: (obj, value) => { obj.offset_ = value; } }, metadata: _metadata }, _offset__initializers, _offset__extraInitializers);
|
|
86
|
+
__esDecorate(null, null, _offset_decorators, { kind: "field", name: "offset", static: false, private: false, access: { has: obj => "offset" in obj, get: obj => obj.offset, set: (obj, value) => { obj.offset = value; } }, metadata: _metadata }, _offset_initializers, _offset_extraInitializers);
|
|
87
|
+
__esDecorate(null, null, _size_decorators, { kind: "field", name: "size", static: false, private: false, access: { has: obj => "size" in obj, get: obj => obj.size, set: (obj, value) => { obj.size = value; } }, metadata: _metadata }, _size_initializers, _size_extraInitializers);
|
|
88
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
89
|
+
MetadataEntry = _classThis = _classDescriptor.value;
|
|
90
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
91
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
92
|
+
})();
|
|
93
|
+
return MetadataEntry = _classThis;
|
|
94
|
+
})();
|
|
95
|
+
/**
|
|
96
|
+
* Number of entries per block of metadata
|
|
97
|
+
*/
|
|
98
|
+
const entries_per_block = 255;
|
|
99
|
+
/**
|
|
100
|
+
* A block of metadata for a single-buffer file system.
|
|
101
|
+
* This metadata maps IDs (for inodes and data) to actual offsets in the buffer.
|
|
102
|
+
* This is done since IDs are not guaranteed to be sequential.
|
|
103
|
+
*/
|
|
104
|
+
let MetadataBlock = (() => {
|
|
105
|
+
var _a, _b, _c, _d;
|
|
106
|
+
let _classDecorators = [struct()];
|
|
107
|
+
let _classDescriptor;
|
|
108
|
+
let _classExtraInitializers = [];
|
|
109
|
+
let _classThis;
|
|
110
|
+
let _checksum_decorators;
|
|
111
|
+
let _checksum_initializers = [];
|
|
112
|
+
let _checksum_extraInitializers = [];
|
|
113
|
+
let _timestamp_decorators;
|
|
114
|
+
let _timestamp_initializers = [];
|
|
115
|
+
let _timestamp_extraInitializers = [];
|
|
116
|
+
let _previous_offset__decorators;
|
|
117
|
+
let _previous_offset__initializers = [];
|
|
118
|
+
let _previous_offset__extraInitializers = [];
|
|
119
|
+
let _previous_offset_decorators;
|
|
120
|
+
let _previous_offset_initializers = [];
|
|
121
|
+
let _previous_offset_extraInitializers = [];
|
|
122
|
+
let _entries_decorators;
|
|
123
|
+
let _entries_initializers = [];
|
|
124
|
+
let _entries_extraInitializers = [];
|
|
125
|
+
var MetadataBlock = _classThis = class {
|
|
126
|
+
constructor(superblock, offset = 0) {
|
|
127
|
+
this.superblock = superblock;
|
|
128
|
+
this.offset = offset;
|
|
129
|
+
/**
|
|
130
|
+
* The crc32c checksum for the metadata block.
|
|
131
|
+
* @privateRemarks Keep this first!
|
|
132
|
+
*/
|
|
133
|
+
this.checksum = __runInitializers(this, _checksum_initializers, 0);
|
|
134
|
+
/** The (last) time this metadata block was updated */
|
|
135
|
+
this.timestamp = (__runInitializers(this, _checksum_extraInitializers), __runInitializers(this, _timestamp_initializers, Date.now()));
|
|
136
|
+
/** Reserved for 64-bit offset expansion */
|
|
137
|
+
this.previous_offset_ = (__runInitializers(this, _timestamp_extraInitializers), __runInitializers(this, _previous_offset__initializers, 0));
|
|
138
|
+
/** Offset to the previous metadata block */
|
|
139
|
+
this.previous_offset = (__runInitializers(this, _previous_offset__extraInitializers), __runInitializers(this, _previous_offset_initializers, 0));
|
|
140
|
+
this._previous = __runInitializers(this, _previous_offset_extraInitializers);
|
|
141
|
+
/** Metadata entries. */
|
|
142
|
+
this.entries = __runInitializers(this, _entries_initializers, Array.from({ length: entries_per_block }, () => new MetadataEntry()));
|
|
143
|
+
__runInitializers(this, _entries_extraInitializers);
|
|
144
|
+
this.superblock = superblock;
|
|
145
|
+
this.offset = offset;
|
|
146
|
+
if (!offset)
|
|
147
|
+
return; // fresh block
|
|
148
|
+
deserialize(this, superblock.store._buffer.subarray(offset, offset + sizeof(MetadataBlock)));
|
|
149
|
+
if (!checksumMatches(this))
|
|
150
|
+
throw crit(new ErrnoError(Errno.EIO, 'SingleBuffer: Checksum mismatch for metadata block at 0x' + offset.toString(16)));
|
|
151
|
+
}
|
|
152
|
+
get previous() {
|
|
153
|
+
var _a;
|
|
154
|
+
if (!this.previous_offset)
|
|
155
|
+
return;
|
|
156
|
+
(_a = this._previous) !== null && _a !== void 0 ? _a : (this._previous = new MetadataBlock(this.superblock, this.previous_offset));
|
|
157
|
+
return this._previous;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
__setFunctionName(_classThis, "MetadataBlock");
|
|
161
|
+
(() => {
|
|
162
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
163
|
+
_checksum_decorators = [(_a = t).uint32.bind(_a)];
|
|
164
|
+
_timestamp_decorators = [(_b = t).uint32.bind(_b)];
|
|
165
|
+
_previous_offset__decorators = [(_c = t).uint32.bind(_c)];
|
|
166
|
+
_previous_offset_decorators = [(_d = t).uint32.bind(_d)];
|
|
167
|
+
_entries_decorators = [member(MetadataEntry, entries_per_block)];
|
|
168
|
+
__esDecorate(null, null, _checksum_decorators, { kind: "field", name: "checksum", static: false, private: false, access: { has: obj => "checksum" in obj, get: obj => obj.checksum, set: (obj, value) => { obj.checksum = value; } }, metadata: _metadata }, _checksum_initializers, _checksum_extraInitializers);
|
|
169
|
+
__esDecorate(null, null, _timestamp_decorators, { kind: "field", name: "timestamp", static: false, private: false, access: { has: obj => "timestamp" in obj, get: obj => obj.timestamp, set: (obj, value) => { obj.timestamp = value; } }, metadata: _metadata }, _timestamp_initializers, _timestamp_extraInitializers);
|
|
170
|
+
__esDecorate(null, null, _previous_offset__decorators, { kind: "field", name: "previous_offset_", static: false, private: false, access: { has: obj => "previous_offset_" in obj, get: obj => obj.previous_offset_, set: (obj, value) => { obj.previous_offset_ = value; } }, metadata: _metadata }, _previous_offset__initializers, _previous_offset__extraInitializers);
|
|
171
|
+
__esDecorate(null, null, _previous_offset_decorators, { kind: "field", name: "previous_offset", static: false, private: false, access: { has: obj => "previous_offset" in obj, get: obj => obj.previous_offset, set: (obj, value) => { obj.previous_offset = value; } }, metadata: _metadata }, _previous_offset_initializers, _previous_offset_extraInitializers);
|
|
172
|
+
__esDecorate(null, null, _entries_decorators, { kind: "field", name: "entries", static: false, private: false, access: { has: obj => "entries" in obj, get: obj => obj.entries, set: (obj, value) => { obj.entries = value; } }, metadata: _metadata }, _entries_initializers, _entries_extraInitializers);
|
|
173
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
174
|
+
MetadataBlock = _classThis = _classDescriptor.value;
|
|
175
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
176
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
177
|
+
})();
|
|
178
|
+
return MetadataBlock = _classThis;
|
|
179
|
+
})();
|
|
180
|
+
const sb_magic = 0x7a2e7362; // 'z.sb'
|
|
181
|
+
/**
|
|
182
|
+
* The super block structure for a single-buffer file system
|
|
183
|
+
*/
|
|
184
|
+
let SuperBlock = (() => {
|
|
185
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
186
|
+
let _classDecorators = [struct()];
|
|
187
|
+
let _classDescriptor;
|
|
188
|
+
let _classExtraInitializers = [];
|
|
189
|
+
let _classThis;
|
|
190
|
+
let _checksum_decorators;
|
|
191
|
+
let _checksum_initializers = [];
|
|
192
|
+
let _checksum_extraInitializers = [];
|
|
193
|
+
let _magic_decorators;
|
|
194
|
+
let _magic_initializers = [];
|
|
195
|
+
let _magic_extraInitializers = [];
|
|
196
|
+
let _version_decorators;
|
|
197
|
+
let _version_initializers = [];
|
|
198
|
+
let _version_extraInitializers = [];
|
|
199
|
+
let _inode_format_decorators;
|
|
200
|
+
let _inode_format_initializers = [];
|
|
201
|
+
let _inode_format_extraInitializers = [];
|
|
202
|
+
let _flags_decorators;
|
|
203
|
+
let _flags_initializers = [];
|
|
204
|
+
let _flags_extraInitializers = [];
|
|
205
|
+
let _used_bytes_decorators;
|
|
206
|
+
let _used_bytes_initializers = [];
|
|
207
|
+
let _used_bytes_extraInitializers = [];
|
|
208
|
+
let _total_bytes_decorators;
|
|
209
|
+
let _total_bytes_initializers = [];
|
|
210
|
+
let _total_bytes_extraInitializers = [];
|
|
211
|
+
let _id_decorators;
|
|
212
|
+
let _id_initializers = [];
|
|
213
|
+
let _id_extraInitializers = [];
|
|
214
|
+
let _metadata_block_size_decorators;
|
|
215
|
+
let _metadata_block_size_initializers = [];
|
|
216
|
+
let _metadata_block_size_extraInitializers = [];
|
|
217
|
+
let _metadata_offset__decorators;
|
|
218
|
+
let _metadata_offset__initializers = [];
|
|
219
|
+
let _metadata_offset__extraInitializers = [];
|
|
220
|
+
let _metadata_offset_decorators;
|
|
221
|
+
let _metadata_offset_initializers = [];
|
|
222
|
+
let _metadata_offset_extraInitializers = [];
|
|
223
|
+
let _label_decorators;
|
|
224
|
+
let _label_initializers = [];
|
|
225
|
+
let _label_extraInitializers = [];
|
|
226
|
+
let __padding_decorators;
|
|
227
|
+
let __padding_initializers = [];
|
|
228
|
+
let __padding_extraInitializers = [];
|
|
229
|
+
var SuperBlock = _classThis = class {
|
|
230
|
+
constructor(store) {
|
|
231
|
+
this.store = store;
|
|
232
|
+
/**
|
|
233
|
+
* The crc32c checksum for the super block.
|
|
234
|
+
* @privateRemarks Keep this first!
|
|
235
|
+
*/
|
|
236
|
+
this.checksum = __runInitializers(this, _checksum_initializers, 0);
|
|
237
|
+
/** Signature for the superblock. */
|
|
238
|
+
this.magic = (__runInitializers(this, _checksum_extraInitializers), __runInitializers(this, _magic_initializers, sb_magic));
|
|
239
|
+
/** The version of the on-disk format */
|
|
240
|
+
this.version = (__runInitializers(this, _magic_extraInitializers), __runInitializers(this, _version_initializers, 1));
|
|
241
|
+
/** Which format of `Inode` is used */
|
|
242
|
+
this.inode_format = (__runInitializers(this, _version_extraInitializers), __runInitializers(this, _inode_format_initializers, _inode_version));
|
|
243
|
+
/** Flags for the file system. Currently unused */
|
|
244
|
+
this.flags = (__runInitializers(this, _inode_format_extraInitializers), __runInitializers(this, _flags_initializers, 0));
|
|
245
|
+
/** The number of used bytes, including the super block and metadata */
|
|
246
|
+
this.used_bytes = (__runInitializers(this, _flags_extraInitializers), __runInitializers(this, _used_bytes_initializers, BigInt(0)));
|
|
247
|
+
/** The total size of the entire file system, including the super block and metadata */
|
|
248
|
+
this.total_bytes = (__runInitializers(this, _used_bytes_extraInitializers), __runInitializers(this, _total_bytes_initializers, BigInt(0)));
|
|
249
|
+
/** An ID for this file system */
|
|
250
|
+
this.id = (__runInitializers(this, _total_bytes_extraInitializers), __runInitializers(this, _id_initializers, BigInt(0)));
|
|
251
|
+
/**
|
|
252
|
+
* The size in bytes of a metadata block.
|
|
253
|
+
* Not currently configurable.
|
|
254
|
+
*/
|
|
255
|
+
this.metadata_block_size = (__runInitializers(this, _id_extraInitializers), __runInitializers(this, _metadata_block_size_initializers, sizeof(MetadataBlock)));
|
|
256
|
+
/** Reserved for 64-bit offset expansion */
|
|
257
|
+
this.metadata_offset_ = (__runInitializers(this, _metadata_block_size_extraInitializers), __runInitializers(this, _metadata_offset__initializers, 0));
|
|
258
|
+
/** Offset of the current metadata block */
|
|
259
|
+
this.metadata_offset = (__runInitializers(this, _metadata_offset__extraInitializers), __runInitializers(this, _metadata_offset_initializers, 0));
|
|
260
|
+
this.metadata = __runInitializers(this, _metadata_offset_extraInitializers);
|
|
261
|
+
/** An optional label for the file system */
|
|
262
|
+
this.label = __runInitializers(this, _label_initializers, '');
|
|
263
|
+
/** Padded to 256 bytes */
|
|
264
|
+
this._padding = (__runInitializers(this, _label_extraInitializers), __runInitializers(this, __padding_initializers, new Array(132).fill(0)));
|
|
265
|
+
__runInitializers(this, __padding_extraInitializers);
|
|
266
|
+
this.store = store;
|
|
267
|
+
if (store._view.getUint32(offsetof(SuperBlock, 'magic'), true) != sb_magic) {
|
|
268
|
+
warn('SingleBuffer: Invalid magic value. Assuming this is a fresh super block.');
|
|
269
|
+
this.metadata = new MetadataBlock(this);
|
|
270
|
+
this.used_bytes = BigInt(sizeof(SuperBlock) + sizeof(MetadataBlock));
|
|
271
|
+
this.total_bytes = BigInt(store._buffer.byteLength);
|
|
272
|
+
store._write(this);
|
|
273
|
+
store._write(this.metadata);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
deserialize(this, store._buffer.subarray(0, sizeof(SuperBlock)));
|
|
277
|
+
if (!checksumMatches(this))
|
|
278
|
+
throw crit(new ErrnoError(Errno.EIO, 'SingleBuffer: Checksum mismatch for super block!'));
|
|
279
|
+
this.metadata = new MetadataBlock(this, this.metadata_offset);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Rotate out the current metadata block.
|
|
283
|
+
* Allocates a new metadata block, moves the current one to backup,
|
|
284
|
+
* and updates used_bytes accordingly.
|
|
285
|
+
* @returns the new metadata block
|
|
286
|
+
*/
|
|
287
|
+
rotateMetadata() {
|
|
288
|
+
const metadata = new MetadataBlock(this);
|
|
289
|
+
metadata.offset = Number(this.used_bytes);
|
|
290
|
+
metadata.previous_offset = this.metadata_offset;
|
|
291
|
+
this.metadata = metadata;
|
|
292
|
+
this.metadata_offset = metadata.offset;
|
|
293
|
+
this.store._write(metadata);
|
|
294
|
+
this.used_bytes += BigInt(sizeof(MetadataBlock));
|
|
295
|
+
this.store._write(this);
|
|
296
|
+
return metadata;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Checks to see if `length` bytes are unused, starting at `offset`.
|
|
300
|
+
* @internal Not for external use!
|
|
301
|
+
*/
|
|
302
|
+
isUnused(offset, length) {
|
|
303
|
+
if (!length)
|
|
304
|
+
return true;
|
|
305
|
+
if (offset + length > this.total_bytes || offset < sizeof(SuperBlock))
|
|
306
|
+
return false;
|
|
307
|
+
for (let block = this.metadata; block; block = block.previous) {
|
|
308
|
+
if (offset < block.offset + sizeof(MetadataBlock) && offset + length > block.offset)
|
|
309
|
+
return false;
|
|
310
|
+
for (const entry of block.entries) {
|
|
311
|
+
if (!entry.offset)
|
|
312
|
+
continue;
|
|
313
|
+
if ((offset >= entry.offset && offset < entry.offset + entry.size)
|
|
314
|
+
|| (offset + length > entry.offset && offset + length <= entry.offset + entry.size)
|
|
315
|
+
|| (offset <= entry.offset && offset + length >= entry.offset + entry.size)) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
__setFunctionName(_classThis, "SuperBlock");
|
|
324
|
+
(() => {
|
|
325
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
326
|
+
_checksum_decorators = [(_a = t).uint32.bind(_a)];
|
|
327
|
+
_magic_decorators = [(_b = t).uint32.bind(_b)];
|
|
328
|
+
_version_decorators = [(_c = t).uint16.bind(_c)];
|
|
329
|
+
_inode_format_decorators = [(_d = t).uint16.bind(_d)];
|
|
330
|
+
_flags_decorators = [(_e = t).uint32.bind(_e)];
|
|
331
|
+
_used_bytes_decorators = [(_f = t).uint64.bind(_f)];
|
|
332
|
+
_total_bytes_decorators = [(_g = t).uint64.bind(_g)];
|
|
333
|
+
_id_decorators = [(_h = t).uint128.bind(_h)];
|
|
334
|
+
_metadata_block_size_decorators = [(_j = t).uint32.bind(_j)];
|
|
335
|
+
_metadata_offset__decorators = [(_k = t).uint32.bind(_k)];
|
|
336
|
+
_metadata_offset_decorators = [(_l = t).uint32.bind(_l)];
|
|
337
|
+
_label_decorators = [t.char(64)];
|
|
338
|
+
__padding_decorators = [t.char(132)];
|
|
339
|
+
__esDecorate(null, null, _checksum_decorators, { kind: "field", name: "checksum", static: false, private: false, access: { has: obj => "checksum" in obj, get: obj => obj.checksum, set: (obj, value) => { obj.checksum = value; } }, metadata: _metadata }, _checksum_initializers, _checksum_extraInitializers);
|
|
340
|
+
__esDecorate(null, null, _magic_decorators, { kind: "field", name: "magic", static: false, private: false, access: { has: obj => "magic" in obj, get: obj => obj.magic, set: (obj, value) => { obj.magic = value; } }, metadata: _metadata }, _magic_initializers, _magic_extraInitializers);
|
|
341
|
+
__esDecorate(null, null, _version_decorators, { kind: "field", name: "version", static: false, private: false, access: { has: obj => "version" in obj, get: obj => obj.version, set: (obj, value) => { obj.version = value; } }, metadata: _metadata }, _version_initializers, _version_extraInitializers);
|
|
342
|
+
__esDecorate(null, null, _inode_format_decorators, { kind: "field", name: "inode_format", static: false, private: false, access: { has: obj => "inode_format" in obj, get: obj => obj.inode_format, set: (obj, value) => { obj.inode_format = value; } }, metadata: _metadata }, _inode_format_initializers, _inode_format_extraInitializers);
|
|
343
|
+
__esDecorate(null, null, _flags_decorators, { kind: "field", name: "flags", static: false, private: false, access: { has: obj => "flags" in obj, get: obj => obj.flags, set: (obj, value) => { obj.flags = value; } }, metadata: _metadata }, _flags_initializers, _flags_extraInitializers);
|
|
344
|
+
__esDecorate(null, null, _used_bytes_decorators, { kind: "field", name: "used_bytes", static: false, private: false, access: { has: obj => "used_bytes" in obj, get: obj => obj.used_bytes, set: (obj, value) => { obj.used_bytes = value; } }, metadata: _metadata }, _used_bytes_initializers, _used_bytes_extraInitializers);
|
|
345
|
+
__esDecorate(null, null, _total_bytes_decorators, { kind: "field", name: "total_bytes", static: false, private: false, access: { has: obj => "total_bytes" in obj, get: obj => obj.total_bytes, set: (obj, value) => { obj.total_bytes = value; } }, metadata: _metadata }, _total_bytes_initializers, _total_bytes_extraInitializers);
|
|
346
|
+
__esDecorate(null, null, _id_decorators, { kind: "field", name: "id", static: false, private: false, access: { has: obj => "id" in obj, get: obj => obj.id, set: (obj, value) => { obj.id = value; } }, metadata: _metadata }, _id_initializers, _id_extraInitializers);
|
|
347
|
+
__esDecorate(null, null, _metadata_block_size_decorators, { kind: "field", name: "metadata_block_size", static: false, private: false, access: { has: obj => "metadata_block_size" in obj, get: obj => obj.metadata_block_size, set: (obj, value) => { obj.metadata_block_size = value; } }, metadata: _metadata }, _metadata_block_size_initializers, _metadata_block_size_extraInitializers);
|
|
348
|
+
__esDecorate(null, null, _metadata_offset__decorators, { kind: "field", name: "metadata_offset_", static: false, private: false, access: { has: obj => "metadata_offset_" in obj, get: obj => obj.metadata_offset_, set: (obj, value) => { obj.metadata_offset_ = value; } }, metadata: _metadata }, _metadata_offset__initializers, _metadata_offset__extraInitializers);
|
|
349
|
+
__esDecorate(null, null, _metadata_offset_decorators, { kind: "field", name: "metadata_offset", static: false, private: false, access: { has: obj => "metadata_offset" in obj, get: obj => obj.metadata_offset, set: (obj, value) => { obj.metadata_offset = value; } }, metadata: _metadata }, _metadata_offset_initializers, _metadata_offset_extraInitializers);
|
|
350
|
+
__esDecorate(null, null, _label_decorators, { kind: "field", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
|
|
351
|
+
__esDecorate(null, null, __padding_decorators, { kind: "field", name: "_padding", static: false, private: false, access: { has: obj => "_padding" in obj, get: obj => obj._padding, set: (obj, value) => { obj._padding = value; } }, metadata: _metadata }, __padding_initializers, __padding_extraInitializers);
|
|
352
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
353
|
+
SuperBlock = _classThis = _classDescriptor.value;
|
|
354
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
355
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
356
|
+
})();
|
|
357
|
+
return SuperBlock = _classThis;
|
|
358
|
+
})();
|
|
359
|
+
function checksumMatches(value) {
|
|
360
|
+
const buffer = serialize(value);
|
|
361
|
+
const computed = crc32c(buffer.subarray(4)); // note we don't include the checksum when computing a new one.
|
|
362
|
+
return value.checksum === computed;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
*
|
|
366
|
+
* @category Stores and Transactions
|
|
367
|
+
*/
|
|
368
|
+
export class SingleBufferStore {
|
|
369
|
+
constructor(buffer) {
|
|
370
|
+
this.flags = [];
|
|
371
|
+
this.name = 'sbfs';
|
|
372
|
+
this.id = 0x73626673; // 'sbfs'
|
|
373
|
+
if (buffer.byteLength < sizeof(SuperBlock) + sizeof(MetadataBlock))
|
|
374
|
+
throw crit(new ErrnoError(Errno.EINVAL, 'SingleBuffer: Buffer is too small for a file system.'));
|
|
375
|
+
this._view = !ArrayBuffer.isView(buffer) ? new DataView(buffer) : new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
376
|
+
this._buffer = !ArrayBuffer.isView(buffer) ? new Uint8Array(buffer) : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
377
|
+
this.superblock = new SuperBlock(this);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Update a block's checksum and write it to the store's buffer.
|
|
381
|
+
* @internal @hidden
|
|
382
|
+
*/
|
|
383
|
+
_write(value) {
|
|
384
|
+
value.checksum = crc32c(serialize(value).subarray(4));
|
|
385
|
+
const offset = 'offset' in value ? value.offset : 0;
|
|
386
|
+
this._buffer.set(serialize(value), offset);
|
|
387
|
+
}
|
|
388
|
+
keys() {
|
|
389
|
+
const keys = new Set();
|
|
390
|
+
for (let block = this.superblock.metadata; block; block = block.previous) {
|
|
391
|
+
for (const entry of block.entries)
|
|
392
|
+
if (entry.offset)
|
|
393
|
+
keys.add(entry.id);
|
|
394
|
+
}
|
|
395
|
+
return keys;
|
|
396
|
+
}
|
|
397
|
+
get(id) {
|
|
398
|
+
for (let block = this.superblock.metadata; block; block = block.previous) {
|
|
399
|
+
for (const entry of block.entries) {
|
|
400
|
+
if (entry.offset && entry.id == id) {
|
|
401
|
+
return this._buffer.subarray(entry.offset, entry.offset + entry.size);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
set(id, data) {
|
|
407
|
+
for (let block = this.superblock.metadata; block; block = block.previous) {
|
|
408
|
+
for (const entry of block.entries) {
|
|
409
|
+
if (!entry.offset || entry.id != id)
|
|
410
|
+
continue;
|
|
411
|
+
if (data.length <= entry.size) {
|
|
412
|
+
this._buffer.set(data, entry.offset);
|
|
413
|
+
if (data.length < entry.size) {
|
|
414
|
+
entry.size = data.length;
|
|
415
|
+
this._write(block);
|
|
416
|
+
}
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (this.superblock.isUnused(entry.offset, data.length)) {
|
|
420
|
+
entry.size = data.length;
|
|
421
|
+
this._buffer.set(data, entry.offset);
|
|
422
|
+
this._write(block);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const used_bytes = Number(this.superblock.used_bytes);
|
|
426
|
+
for (let block = this.superblock.metadata; block; block = block.previous) {
|
|
427
|
+
for (const entry of block.entries) {
|
|
428
|
+
if (entry.offset != used_bytes)
|
|
429
|
+
continue;
|
|
430
|
+
entry.offset += data.length;
|
|
431
|
+
this._write(block);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
entry.offset = used_bytes;
|
|
436
|
+
entry.size = data.length;
|
|
437
|
+
this._buffer.set(data, entry.offset);
|
|
438
|
+
this._write(block);
|
|
439
|
+
this.superblock.used_bytes += BigInt(data.length);
|
|
440
|
+
this._write(this.superblock);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
let entry = this.superblock.metadata.entries.find(e => !e.offset);
|
|
445
|
+
if (!entry) {
|
|
446
|
+
this.superblock.rotateMetadata();
|
|
447
|
+
entry = this.superblock.metadata.entries[0];
|
|
448
|
+
}
|
|
449
|
+
const offset = Number(this.superblock.used_bytes);
|
|
450
|
+
entry.id = id;
|
|
451
|
+
entry.offset = offset;
|
|
452
|
+
entry.size = data.length;
|
|
453
|
+
this._buffer.set(data, offset);
|
|
454
|
+
this.superblock.used_bytes += BigInt(data.length);
|
|
455
|
+
this._write(this.superblock.metadata);
|
|
456
|
+
this._write(this.superblock);
|
|
457
|
+
}
|
|
458
|
+
delete(id) {
|
|
459
|
+
for (let block = this.superblock.metadata; block; block = block.previous) {
|
|
460
|
+
for (const entry of block.entries) {
|
|
461
|
+
if (entry.id != id)
|
|
462
|
+
continue;
|
|
463
|
+
entry.offset = 0;
|
|
464
|
+
entry.size = 0;
|
|
465
|
+
this._write(block);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
async sync() {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
usage() {
|
|
474
|
+
return {
|
|
475
|
+
totalSpace: Number(this.superblock.total_bytes),
|
|
476
|
+
freeSpace: Number(this.superblock.total_bytes - this.superblock.used_bytes),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
transaction() {
|
|
480
|
+
return new SyncMapTransaction(this);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const _SingleBuffer = {
|
|
484
|
+
name: 'SingleBuffer',
|
|
485
|
+
options: {
|
|
486
|
+
buffer: { type: 'object', required: true },
|
|
487
|
+
},
|
|
488
|
+
create({ buffer }) {
|
|
489
|
+
const fs = new StoreFS(new SingleBufferStore(buffer));
|
|
490
|
+
fs.checkRootSync();
|
|
491
|
+
return fs;
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* A backend that uses a single buffer for storing data
|
|
496
|
+
* @category Backends and Configuration
|
|
497
|
+
*/
|
|
498
|
+
export const SingleBuffer = _SingleBuffer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { File } from '../../internal/file.js';
|
|
2
2
|
import { Index } from '../../internal/file_index.js';
|
|
3
|
-
import type { CreationOptions, PureCreationOptions } from '../../internal/filesystem.js';
|
|
3
|
+
import type { CreationOptions, PureCreationOptions, UsageInfo } from '../../internal/filesystem.js';
|
|
4
4
|
import { FileSystem } from '../../internal/filesystem.js';
|
|
5
5
|
import { Inode, type InodeLike } from '../../internal/inode.js';
|
|
6
6
|
import type { Stats } from '../../stats.js';
|
|
@@ -43,6 +43,10 @@ export declare class StoreFS<T extends Store = Store> extends FileSystem {
|
|
|
43
43
|
protected _initialized: boolean;
|
|
44
44
|
ready(): Promise<void>;
|
|
45
45
|
constructor(store: T);
|
|
46
|
+
/**
|
|
47
|
+
* @experimental
|
|
48
|
+
*/
|
|
49
|
+
usage(): UsageInfo;
|
|
46
50
|
/**
|
|
47
51
|
* Delete all contents stored in the file system.
|
|
48
52
|
* @deprecated
|
|
@@ -150,6 +150,16 @@ export class StoreFS extends FileSystem {
|
|
|
150
150
|
store._fs = this;
|
|
151
151
|
debug(this.name + ': supports features: ' + ((_b = this.store.flags) === null || _b === void 0 ? void 0 : _b.join(', ')));
|
|
152
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* @experimental
|
|
155
|
+
*/
|
|
156
|
+
usage() {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
return (((_b = (_a = this.store).usage) === null || _b === void 0 ? void 0 : _b.call(_a)) || {
|
|
159
|
+
totalSpace: 0,
|
|
160
|
+
freeSpace: 0,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
153
163
|
/* node:coverage disable */
|
|
154
164
|
/**
|
|
155
165
|
* Delete all contents stored in the file system.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Resource } from 'utilium/cache.js';
|
|
2
2
|
import '../../polyfills.js';
|
|
3
3
|
import type { StoreFS } from './fs.js';
|
|
4
|
+
import type { UsageInfo } from '../../internal/filesystem.js';
|
|
4
5
|
/**
|
|
5
6
|
* @category Stores and Transactions
|
|
6
7
|
*/
|
|
@@ -48,6 +49,10 @@ export interface Store {
|
|
|
48
49
|
* Use for optimizations
|
|
49
50
|
*/
|
|
50
51
|
readonly flags?: readonly StoreFlag[];
|
|
52
|
+
/**
|
|
53
|
+
* Usage information for the store
|
|
54
|
+
*/
|
|
55
|
+
usage?(): UsageInfo;
|
|
51
56
|
/**
|
|
52
57
|
* @internal @hidden
|
|
53
58
|
*/
|
package/dist/internal/devices.js
CHANGED
|
@@ -244,7 +244,9 @@ export class DeviceFS extends StoreFS {
|
|
|
244
244
|
debug('Added default devices.');
|
|
245
245
|
}
|
|
246
246
|
constructor() {
|
|
247
|
-
|
|
247
|
+
// Please don't store your temporary files in /dev.
|
|
248
|
+
// If you do, you'll have up to 16 MiB
|
|
249
|
+
super(new InMemoryStore(0x1000000, 'devfs'));
|
|
248
250
|
this.devices = new Map();
|
|
249
251
|
}
|
|
250
252
|
async rename(oldPath, newPath) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { InodeLike } from './inode.js';
|
|
2
2
|
import { Inode } from './inode.js';
|
|
3
|
+
import type { UsageInfo } from './filesystem.js';
|
|
3
4
|
/**
|
|
4
5
|
* An Index in JSON form
|
|
5
6
|
* @internal
|
|
6
7
|
*/
|
|
7
8
|
export interface IndexData {
|
|
8
9
|
version: number;
|
|
10
|
+
maxSize?: number;
|
|
9
11
|
entries: Record<string, InodeLike>;
|
|
10
12
|
}
|
|
11
13
|
export declare const version = 1;
|
|
@@ -15,6 +17,7 @@ export declare const version = 1;
|
|
|
15
17
|
* @internal
|
|
16
18
|
*/
|
|
17
19
|
export declare class Index extends Map<string, Inode> {
|
|
20
|
+
maxSize: number;
|
|
18
21
|
/**
|
|
19
22
|
* Converts the index to JSON
|
|
20
23
|
*/
|
|
@@ -23,6 +26,11 @@ export declare class Index extends Map<string, Inode> {
|
|
|
23
26
|
* Converts the index to a string
|
|
24
27
|
*/
|
|
25
28
|
toString(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Get the size in bytes of the index (including the size reported for each entry)
|
|
31
|
+
*/
|
|
32
|
+
get byteSize(): number;
|
|
33
|
+
usage(): UsageInfo;
|
|
26
34
|
pathOf(id: number): string | undefined;
|
|
27
35
|
getByID(id: number): Inode | undefined;
|
|
28
36
|
entryByID(id: number): {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* Note: this file is named file_index.ts because Typescript has special behavior regarding index.ts which can't be disabled. */
|
|
2
|
-
import { isJSON, randomInt } from 'utilium';
|
|
2
|
+
import { isJSON, randomInt, sizeof } from 'utilium';
|
|
3
3
|
import { S_IFDIR, S_IFMT, size_max } from '../vfs/constants.js';
|
|
4
4
|
import { basename, dirname } from '../vfs/path.js';
|
|
5
5
|
import { Errno, ErrnoError } from './error.js';
|
|
6
|
-
import { Inode } from './inode.js';
|
|
6
|
+
import { __inode_sz, Inode } from './inode.js';
|
|
7
7
|
export const version = 1;
|
|
8
8
|
/**
|
|
9
9
|
* An index of file metadata
|
|
@@ -11,12 +11,17 @@ export const version = 1;
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
export class Index extends Map {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.maxSize = size_max;
|
|
17
|
+
}
|
|
14
18
|
/**
|
|
15
19
|
* Converts the index to JSON
|
|
16
20
|
*/
|
|
17
21
|
toJSON() {
|
|
18
22
|
return {
|
|
19
23
|
version,
|
|
24
|
+
maxSize: this.maxSize,
|
|
20
25
|
entries: Object.fromEntries([...this].map(([k, v]) => [k, v.toJSON()])),
|
|
21
26
|
};
|
|
22
27
|
}
|
|
@@ -26,6 +31,21 @@ export class Index extends Map {
|
|
|
26
31
|
toString() {
|
|
27
32
|
return JSON.stringify(this.toJSON());
|
|
28
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the size in bytes of the index (including the size reported for each entry)
|
|
36
|
+
*/
|
|
37
|
+
get byteSize() {
|
|
38
|
+
let size = this.size * __inode_sz;
|
|
39
|
+
for (const entry of this.values())
|
|
40
|
+
size += entry.size;
|
|
41
|
+
return size;
|
|
42
|
+
}
|
|
43
|
+
usage() {
|
|
44
|
+
return {
|
|
45
|
+
totalSpace: this.maxSize,
|
|
46
|
+
freeSpace: this.maxSize - this.byteSize,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
29
49
|
pathOf(id) {
|
|
30
50
|
for (const [path, inode] of this) {
|
|
31
51
|
if (inode.ino == id || inode.data == id)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Stats } from '../stats.js';
|
|
2
2
|
import { type File } from './file.js';
|
|
3
3
|
import { Index } from './file_index.js';
|
|
4
|
-
import { FileSystem, type CreationOptions, type PureCreationOptions } from './filesystem.js';
|
|
4
|
+
import { FileSystem, type CreationOptions, type PureCreationOptions, type UsageInfo } from './filesystem.js';
|
|
5
5
|
import { Inode, type InodeLike } from './inode.js';
|
|
6
6
|
/**
|
|
7
7
|
* A file system that uses an `Index` for metadata.
|
|
@@ -11,6 +11,7 @@ import { Inode, type InodeLike } from './inode.js';
|
|
|
11
11
|
export declare abstract class IndexFS extends FileSystem {
|
|
12
12
|
readonly index: Index;
|
|
13
13
|
constructor(id: number, name: string, index?: Index);
|
|
14
|
+
usage(): UsageInfo;
|
|
14
15
|
/**
|
|
15
16
|
* @deprecated
|
|
16
17
|
*/
|
package/dist/internal/inode.d.ts
CHANGED
|
@@ -21,6 +21,14 @@ export interface InodeLike extends StatsLike<number>, InodeFields {
|
|
|
21
21
|
* @internal @hidden
|
|
22
22
|
*/
|
|
23
23
|
export declare const _inode_fields: readonly ["ino", "data", "size", "mode", "flags", "nlink", "uid", "gid", "atimeMs", "birthtimeMs", "mtimeMs", "ctimeMs"];
|
|
24
|
+
/**
|
|
25
|
+
* Represents which version of the `Inode` format we are on.
|
|
26
|
+
* 1. 58 bytes. The first member was called `ino` but used as the ID for data.
|
|
27
|
+
* 2. 66 bytes. Renamed the first member from `ino` to `data` and added a separate `ino` field
|
|
28
|
+
* 3. (current) 72 bytes. Changed the ID fields from 64 to 32 bits and added `flags`.
|
|
29
|
+
* @internal @hidden
|
|
30
|
+
*/
|
|
31
|
+
export declare const _inode_version = 3;
|
|
24
32
|
/**
|
|
25
33
|
* Generic inode definition that can easily be serialized.
|
|
26
34
|
* @category Internals
|
package/dist/internal/inode.js
CHANGED
|
@@ -49,6 +49,14 @@ export const rootIno = 0;
|
|
|
49
49
|
* @internal @hidden
|
|
50
50
|
*/
|
|
51
51
|
export const _inode_fields = ['ino', 'data', 'size', 'mode', 'flags', 'nlink', 'uid', 'gid', 'atimeMs', 'birthtimeMs', 'mtimeMs', 'ctimeMs'];
|
|
52
|
+
/**
|
|
53
|
+
* Represents which version of the `Inode` format we are on.
|
|
54
|
+
* 1. 58 bytes. The first member was called `ino` but used as the ID for data.
|
|
55
|
+
* 2. 66 bytes. Renamed the first member from `ino` to `data` and added a separate `ino` field
|
|
56
|
+
* 3. (current) 72 bytes. Changed the ID fields from 64 to 32 bits and added `flags`.
|
|
57
|
+
* @internal @hidden
|
|
58
|
+
*/
|
|
59
|
+
export const _inode_version = 3;
|
|
52
60
|
/**
|
|
53
61
|
* Generic inode definition that can easily be serialized.
|
|
54
62
|
* @category Internals
|
package/dist/stats.js
CHANGED
|
@@ -233,11 +233,11 @@ export class BigIntStats extends StatsCommon {
|
|
|
233
233
|
* @internal
|
|
234
234
|
*/
|
|
235
235
|
export function isStatsEqual(left, right) {
|
|
236
|
-
return (left.size == right.size
|
|
237
|
-
+left.atime == +right.atime
|
|
238
|
-
+left.mtime == +right.mtime
|
|
239
|
-
+left.ctime == +right.ctime
|
|
240
|
-
left.mode == right.mode);
|
|
236
|
+
return (left.size == right.size
|
|
237
|
+
&& +left.atime == +right.atime
|
|
238
|
+
&& +left.mtime == +right.mtime
|
|
239
|
+
&& +left.ctime == +right.ctime
|
|
240
|
+
&& left.mode == right.mode);
|
|
241
241
|
}
|
|
242
242
|
/** @internal */
|
|
243
243
|
export const ZenFsType = 0x7a656e6673; // 'z' 'e' 'n' 'f' 's'
|
package/dist/vfs/path.js
CHANGED
|
@@ -338,12 +338,12 @@ export function extname(path) {
|
|
|
338
338
|
preDotState = -1;
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
-
if (startDot === -1
|
|
342
|
-
end === -1
|
|
341
|
+
if (startDot === -1
|
|
342
|
+
|| end === -1
|
|
343
343
|
// We saw a non-dot character immediately before the dot
|
|
344
|
-
preDotState === 0
|
|
344
|
+
|| preDotState === 0
|
|
345
345
|
// The (right-most) trimmed path component is exactly '..'
|
|
346
|
-
(preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
|
|
346
|
+
|| (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
|
|
347
347
|
return '';
|
|
348
348
|
}
|
|
349
349
|
return path.slice(startDot, end);
|
|
@@ -403,11 +403,11 @@ export function parse(path) {
|
|
|
403
403
|
}
|
|
404
404
|
if (end !== -1) {
|
|
405
405
|
const start = startPart === 0 && isAbsolute ? 1 : startPart;
|
|
406
|
-
if (startDot === -1
|
|
406
|
+
if (startDot === -1
|
|
407
407
|
// We saw a non-dot character immediately before the dot
|
|
408
|
-
preDotState === 0
|
|
408
|
+
|| preDotState === 0
|
|
409
409
|
// The (right-most) trimmed path component is exactly '..'
|
|
410
|
-
(preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
|
|
410
|
+
|| (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
|
|
411
411
|
ret.base = ret.name = path.slice(start, end);
|
|
412
412
|
}
|
|
413
413
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "A filesystem, anywhere",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"buffer": "^6.0.3",
|
|
71
71
|
"eventemitter3": "^5.0.1",
|
|
72
72
|
"readable-stream": "^4.5.2",
|
|
73
|
-
"utilium": "^1.
|
|
73
|
+
"utilium": "^1.3.1"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@eslint/js": "^9.8.0",
|