@zenfs/core 0.9.4 → 0.9.6
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/AsyncStore.d.ts +15 -1
- package/dist/backends/AsyncStore.js +22 -8
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +3 -3
- package/dist/filesystem.d.ts +1 -0
- package/dist/filesystem.js +11 -8
- package/dist/stats.d.ts +5 -1
- package/dist/stats.js +2 -1
- package/package.json +1 -1
- package/src/backends/AsyncStore.ts +23 -9
- package/src/filesystem.ts +15 -10
- package/src/stats.ts +6 -1
- package/tsconfig.json +12 -0
|
@@ -3,6 +3,18 @@ import { PreloadFile } from '../file.js';
|
|
|
3
3
|
import { FileSystem, type FileSystemMetadata } from '../filesystem.js';
|
|
4
4
|
import { type Ino } from '../inode.js';
|
|
5
5
|
import { type Stats } from '../stats.js';
|
|
6
|
+
/**
|
|
7
|
+
* Last Recently Used cache
|
|
8
|
+
*/
|
|
9
|
+
declare class LRUCache<K, V> {
|
|
10
|
+
readonly limit: number;
|
|
11
|
+
private cache;
|
|
12
|
+
constructor(limit: number);
|
|
13
|
+
set(key: K, value: V): void;
|
|
14
|
+
get(key: K): V | null;
|
|
15
|
+
remove(key: K): void;
|
|
16
|
+
reset(): void;
|
|
17
|
+
}
|
|
6
18
|
/**
|
|
7
19
|
* Represents an asynchronous key-value store.
|
|
8
20
|
*/
|
|
@@ -68,6 +80,7 @@ export interface AsyncStoreOptions {
|
|
|
68
80
|
}
|
|
69
81
|
declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
|
|
70
82
|
_sync: FileSystem;
|
|
83
|
+
queueDone(): Promise<void>;
|
|
71
84
|
metadata(): FileSystemMetadata;
|
|
72
85
|
ready(): Promise<any>;
|
|
73
86
|
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
@@ -101,7 +114,8 @@ declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
|
|
|
101
114
|
export declare class AsyncStoreFS extends AsyncStoreFS_base {
|
|
102
115
|
protected _options: AsyncStoreOptions;
|
|
103
116
|
protected store: AsyncStore;
|
|
104
|
-
|
|
117
|
+
protected _cache?: LRUCache<string, Ino>;
|
|
118
|
+
private _initialized;
|
|
105
119
|
_sync: FileSystem;
|
|
106
120
|
ready(): Promise<this>;
|
|
107
121
|
metadata(): FileSystemMetadata;
|
|
@@ -52,6 +52,10 @@ class LRUCache {
|
|
|
52
52
|
*/
|
|
53
53
|
export class AsyncStoreFS extends Async(FileSystem) {
|
|
54
54
|
async ready() {
|
|
55
|
+
if (this._initialized) {
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
this._initialized = true;
|
|
55
59
|
if (this._options.lruCacheSize > 0) {
|
|
56
60
|
this._cache = new LRUCache(this._options.lruCacheSize);
|
|
57
61
|
}
|
|
@@ -70,6 +74,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
70
74
|
constructor(_options) {
|
|
71
75
|
super();
|
|
72
76
|
this._options = _options;
|
|
77
|
+
this._initialized = false;
|
|
73
78
|
}
|
|
74
79
|
/**
|
|
75
80
|
* Delete all contents stored in the file system.
|
|
@@ -79,13 +84,14 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
79
84
|
this._cache.reset();
|
|
80
85
|
}
|
|
81
86
|
await this.store.clear();
|
|
82
|
-
//
|
|
87
|
+
// Root always exists.
|
|
83
88
|
await this.makeRootDirectory();
|
|
84
89
|
}
|
|
85
90
|
/**
|
|
86
91
|
* @todo Make rename compatible with the cache.
|
|
87
92
|
*/
|
|
88
93
|
async rename(oldPath, newPath, cred) {
|
|
94
|
+
await this.queueDone();
|
|
89
95
|
const c = this._cache;
|
|
90
96
|
if (this._cache) {
|
|
91
97
|
// Clear and disable cache during renaming process.
|
|
@@ -160,6 +166,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
168
|
async stat(p, cred) {
|
|
169
|
+
await this.queueDone();
|
|
163
170
|
const tx = this.store.beginTransaction();
|
|
164
171
|
const inode = await this.findINode(tx, p);
|
|
165
172
|
if (!inode) {
|
|
@@ -172,11 +179,13 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
172
179
|
return stats;
|
|
173
180
|
}
|
|
174
181
|
async createFile(p, flag, mode, cred) {
|
|
182
|
+
await this.queueDone();
|
|
175
183
|
const tx = this.store.beginTransaction(), data = new Uint8Array(0), newFile = await this.commitNewFile(tx, p, FileType.FILE, mode, cred, data);
|
|
176
184
|
// Open the file.
|
|
177
185
|
return new PreloadFile(this, p, flag, newFile.toStats(), data);
|
|
178
186
|
}
|
|
179
187
|
async openFile(p, flag, cred) {
|
|
188
|
+
await this.queueDone();
|
|
180
189
|
const tx = this.store.beginTransaction(), node = await this.findINode(tx, p), data = await tx.get(node.ino);
|
|
181
190
|
if (!node.toStats().hasAccess(flagToMode(flag), cred)) {
|
|
182
191
|
throw ApiError.With('EACCES', p, 'openFile');
|
|
@@ -187,9 +196,11 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
187
196
|
return new PreloadFile(this, p, flag, node.toStats(), data);
|
|
188
197
|
}
|
|
189
198
|
async unlink(p, cred) {
|
|
199
|
+
await this.queueDone();
|
|
190
200
|
return this.removeEntry(p, false, cred);
|
|
191
201
|
}
|
|
192
202
|
async rmdir(p, cred) {
|
|
203
|
+
await this.queueDone();
|
|
193
204
|
// Check first if directory is empty.
|
|
194
205
|
const list = await this.readdir(p, cred);
|
|
195
206
|
if (list.length > 0) {
|
|
@@ -198,10 +209,12 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
198
209
|
await this.removeEntry(p, true, cred);
|
|
199
210
|
}
|
|
200
211
|
async mkdir(p, mode, cred) {
|
|
212
|
+
await this.queueDone();
|
|
201
213
|
const tx = this.store.beginTransaction(), data = encode('{}');
|
|
202
214
|
await this.commitNewFile(tx, p, FileType.DIRECTORY, mode, cred, data);
|
|
203
215
|
}
|
|
204
216
|
async readdir(p, cred) {
|
|
217
|
+
await this.queueDone();
|
|
205
218
|
const tx = this.store.beginTransaction();
|
|
206
219
|
const node = await this.findINode(tx, p);
|
|
207
220
|
if (!node.toStats().hasAccess(R_OK, cred)) {
|
|
@@ -214,6 +227,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
214
227
|
* @todo Ensure mtime updates properly, and use that to determine if a data update is required.
|
|
215
228
|
*/
|
|
216
229
|
async sync(p, data, stats) {
|
|
230
|
+
await this.queueDone();
|
|
217
231
|
const tx = this.store.beginTransaction(),
|
|
218
232
|
// We use the _findInode helper because we actually need the INode id.
|
|
219
233
|
fileInodeId = await this._findINode(tx, dirname(p), basename(p)), fileInode = await this.getINode(tx, fileInodeId, p), inodeChanged = fileInode.update(stats);
|
|
@@ -232,6 +246,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
232
246
|
await tx.commit();
|
|
233
247
|
}
|
|
234
248
|
async link(existing, newpath, cred) {
|
|
249
|
+
await this.queueDone();
|
|
235
250
|
const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = await this.findINode(tx, existingDir);
|
|
236
251
|
if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
|
|
237
252
|
throw ApiError.With('EACCES', existingDir, 'link');
|
|
@@ -262,14 +277,13 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
262
277
|
*/
|
|
263
278
|
async makeRootDirectory() {
|
|
264
279
|
const tx = this.store.beginTransaction();
|
|
265
|
-
if ((await tx.get(rootIno))
|
|
280
|
+
if (!(await tx.get(rootIno))) {
|
|
266
281
|
// Create new inode. o777, owned by root:root
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
// If the root doesn't exist, the first random ID shouldn't exist
|
|
270
|
-
|
|
271
|
-
await tx.put(
|
|
272
|
-
await tx.put(rootIno, dirInode.data, false);
|
|
282
|
+
const inode = new Inode();
|
|
283
|
+
inode.mode = 0o777 | FileType.DIRECTORY;
|
|
284
|
+
// If the root doesn't exist, the first random ID shouldn't exist either.
|
|
285
|
+
await tx.put(inode.ino, encode('{}'), false);
|
|
286
|
+
await tx.put(rootIno, inode.data, false);
|
|
273
287
|
await tx.commit();
|
|
274
288
|
}
|
|
275
289
|
}
|