@zenfs/core 0.11.1 → 0.12.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 +20 -33
- package/dist/backends/fetch.js +48 -93
- package/dist/backends/index/fs.d.ts +49 -0
- package/dist/backends/index/fs.js +86 -0
- package/dist/backends/index/index.d.ts +37 -0
- package/dist/backends/index/index.js +82 -0
- package/dist/backends/locked.d.ts +1 -1
- package/dist/backends/locked.js +34 -34
- package/dist/backends/memory.d.ts +1 -1
- package/dist/backends/port/fs.d.ts +1 -1
- package/dist/backends/port/fs.js +2 -1
- package/dist/backends/port/rpc.js +3 -1
- package/dist/backends/store/fs.d.ts +5 -5
- package/dist/backends/store/fs.js +1 -1
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +4 -4
- package/dist/emulation/promises.js +1 -2
- package/dist/emulation/sync.js +24 -40
- package/dist/file.d.ts +1 -1
- package/dist/file.js +2 -2
- package/dist/filesystem.d.ts +6 -6
- package/dist/filesystem.js +11 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mutex.d.ts +1 -1
- package/dist/mutex.js +11 -11
- package/dist/stats.d.ts +10 -10
- package/package.json +1 -1
- package/scripts/make-index.js +39 -24
- package/src/backends/fetch.ts +52 -110
- package/src/backends/index/fs.ts +113 -0
- package/src/backends/index/index.ts +98 -0
- package/src/backends/index/readme.md +3 -0
- package/src/backends/locked.ts +34 -34
- package/src/backends/memory.ts +1 -1
- package/src/backends/port/fs.ts +2 -1
- package/src/backends/port/rpc.ts +2 -1
- package/src/backends/store/fs.ts +5 -5
- package/src/emulation/promises.ts +1 -2
- package/src/emulation/sync.ts +23 -41
- package/src/file.ts +2 -2
- package/src/filesystem.ts +18 -17
- package/src/index.ts +1 -1
- package/src/mutex.ts +11 -11
- package/src/stats.ts +10 -10
- package/dist/backends/Index.d.ts +0 -204
- package/dist/backends/Index.js +0 -410
- package/src/backends/Index.ts +0 -504
package/src/backends/port/rpc.ts
CHANGED
|
@@ -85,10 +85,11 @@ export function request<const TRequest extends Request, TValue>(
|
|
|
85
85
|
const id = Math.random().toString(16).slice(10);
|
|
86
86
|
executors.set(id, { resolve, reject, fs });
|
|
87
87
|
port.postMessage({ ...request, _zenfs: true, id, stack });
|
|
88
|
-
setTimeout(() => {
|
|
88
|
+
const _ = setTimeout(() => {
|
|
89
89
|
const error = new ErrnoError(Errno.EIO, 'RPC Failed');
|
|
90
90
|
error.stack += stack;
|
|
91
91
|
reject(error);
|
|
92
|
+
if (typeof _ == 'object') _.unref();
|
|
92
93
|
}, timeout);
|
|
93
94
|
});
|
|
94
95
|
}
|
package/src/backends/store/fs.ts
CHANGED
|
@@ -12,22 +12,22 @@ import type { Store, Transaction } from './store.js';
|
|
|
12
12
|
const maxInodeAllocTries = 5;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* A
|
|
15
|
+
* A file system which uses a key-value store.
|
|
16
16
|
*
|
|
17
17
|
* We use a unique ID for each node in the file system. The root node has a fixed ID.
|
|
18
18
|
* @todo Introduce Node ID caching.
|
|
19
19
|
* @todo Check modes.
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
|
-
export class StoreFS extends FileSystem {
|
|
23
|
-
protected get store():
|
|
22
|
+
export class StoreFS<T extends Store = Store> extends FileSystem {
|
|
23
|
+
protected get store(): T {
|
|
24
24
|
if (!this._store) {
|
|
25
25
|
throw new ErrnoError(Errno.ENODATA, 'No store attached');
|
|
26
26
|
}
|
|
27
27
|
return this._store;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
protected _store?:
|
|
30
|
+
protected _store?: T;
|
|
31
31
|
|
|
32
32
|
private _initialized: boolean = false;
|
|
33
33
|
|
|
@@ -40,7 +40,7 @@ export class StoreFS extends FileSystem {
|
|
|
40
40
|
this._store = await this.$store;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
constructor(private $store:
|
|
43
|
+
constructor(private $store: T | Promise<T>) {
|
|
44
44
|
super();
|
|
45
45
|
|
|
46
46
|
if (!($store instanceof Promise)) {
|
|
@@ -144,8 +144,7 @@ export class FileHandle implements promises.FileHandle {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const { size } = await this.stat();
|
|
147
|
-
const data = new Uint8Array(size);
|
|
148
|
-
await this.file.read(data, 0, size, 0);
|
|
147
|
+
const { buffer: data } = await this.file.read(new Uint8Array(size), 0, size, 0);
|
|
149
148
|
const buffer = Buffer.from(data);
|
|
150
149
|
return options.encoding ? buffer.toString(options.encoding) : buffer;
|
|
151
150
|
}
|
package/src/emulation/sync.ts
CHANGED
|
@@ -16,7 +16,7 @@ type FileSystemMethod = {
|
|
|
16
16
|
: never;
|
|
17
17
|
}[keyof FileSystem]; // https://stackoverflow.com/a/76335220/17637456
|
|
18
18
|
|
|
19
|
-
function
|
|
19
|
+
function wrap<M extends FileSystemMethod, RT extends ReturnType<M>>(...[name, resolveSymlinks, path, ...args]: Parameters<M>): RT {
|
|
20
20
|
path = normalizePath(path!);
|
|
21
21
|
const { fs, path: resolvedPath } = resolveMount(resolveSymlinks && existsSync(path) ? realpathSync(path) : path);
|
|
22
22
|
try {
|
|
@@ -78,7 +78,7 @@ existsSync satisfies typeof fs.existsSync;
|
|
|
78
78
|
export function statSync(path: fs.PathLike, options?: { bigint?: boolean }): Stats;
|
|
79
79
|
export function statSync(path: fs.PathLike, options: { bigint: true }): BigIntStats;
|
|
80
80
|
export function statSync(path: fs.PathLike, options?: fs.StatOptions): Stats | BigIntStats {
|
|
81
|
-
const stats: Stats =
|
|
81
|
+
const stats: Stats = wrap('statSync', true, path.toString(), cred);
|
|
82
82
|
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
83
83
|
}
|
|
84
84
|
statSync satisfies typeof fs.statSync;
|
|
@@ -92,7 +92,7 @@ statSync satisfies typeof fs.statSync;
|
|
|
92
92
|
export function lstatSync(path: fs.PathLike, options?: { bigint?: boolean }): Stats;
|
|
93
93
|
export function lstatSync(path: fs.PathLike, options: { bigint: true }): BigIntStats;
|
|
94
94
|
export function lstatSync(path: fs.PathLike, options?: fs.StatOptions): Stats | BigIntStats {
|
|
95
|
-
const stats: Stats =
|
|
95
|
+
const stats: Stats = wrap('statSync', false, path.toString(), cred);
|
|
96
96
|
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
97
97
|
}
|
|
98
98
|
lstatSync satisfies typeof fs.lstatSync;
|
|
@@ -117,7 +117,7 @@ truncateSync satisfies typeof fs.truncateSync;
|
|
|
117
117
|
* @param path
|
|
118
118
|
*/
|
|
119
119
|
export function unlinkSync(path: fs.PathLike): void {
|
|
120
|
-
return
|
|
120
|
+
return wrap('unlinkSync', false, path.toString(), cred);
|
|
121
121
|
}
|
|
122
122
|
unlinkSync satisfies typeof fs.unlinkSync;
|
|
123
123
|
|
|
@@ -128,17 +128,17 @@ function _openSync(_path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | nul
|
|
|
128
128
|
// Check if the path exists, and is a file.
|
|
129
129
|
let stats: Stats;
|
|
130
130
|
try {
|
|
131
|
-
stats =
|
|
131
|
+
stats = wrap('statSync', resolveSymlinks, path, cred);
|
|
132
132
|
} catch (e) {
|
|
133
133
|
// File does not exist.
|
|
134
134
|
switch (pathNotExistsAction(flag)) {
|
|
135
135
|
case ActionType.CREATE:
|
|
136
136
|
// Ensure parent exists.
|
|
137
|
-
const parentStats: Stats =
|
|
137
|
+
const parentStats: Stats = wrap('statSync', resolveSymlinks, dirname(path), cred);
|
|
138
138
|
if (!parentStats.isDirectory()) {
|
|
139
139
|
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
|
|
140
140
|
}
|
|
141
|
-
return
|
|
141
|
+
return wrap('createFileSync', resolveSymlinks, path, flag, mode, cred);
|
|
142
142
|
case ActionType.THROW:
|
|
143
143
|
throw ErrnoError.With('ENOENT', path, '_open');
|
|
144
144
|
default:
|
|
@@ -155,16 +155,16 @@ function _openSync(_path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | nul
|
|
|
155
155
|
throw ErrnoError.With('EEXIST', path, '_open');
|
|
156
156
|
case ActionType.TRUNCATE:
|
|
157
157
|
// Delete file.
|
|
158
|
-
|
|
158
|
+
wrap('unlinkSync', resolveSymlinks, path, cred);
|
|
159
159
|
/*
|
|
160
160
|
Create file. Use the same mode as the old file.
|
|
161
161
|
Node itself modifies the ctime when this occurs, so this action
|
|
162
162
|
will preserve that behavior if the underlying file system
|
|
163
163
|
supports those properties.
|
|
164
164
|
*/
|
|
165
|
-
return
|
|
165
|
+
return wrap('createFileSync', resolveSymlinks, path, flag, stats.mode, cred);
|
|
166
166
|
case ActionType.NOP:
|
|
167
|
-
return
|
|
167
|
+
return wrap('openFileSync', resolveSymlinks, path, flag, cred);
|
|
168
168
|
default:
|
|
169
169
|
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
170
170
|
}
|
|
@@ -230,21 +230,6 @@ export function readFileSync(path: fs.PathOrFileDescriptor, _options: fs.WriteFi
|
|
|
230
230
|
}
|
|
231
231
|
readFileSync satisfies typeof fs.readFileSync;
|
|
232
232
|
|
|
233
|
-
/**
|
|
234
|
-
* Synchronously writes data to a file, replacing the file
|
|
235
|
-
* if it already exists.
|
|
236
|
-
*
|
|
237
|
-
* The encoding option is ignored if data is a buffer.
|
|
238
|
-
*/
|
|
239
|
-
function _writeFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
|
|
240
|
-
const file = _openSync(fname, flag, mode, resolveSymlinks);
|
|
241
|
-
try {
|
|
242
|
-
file.writeSync(data, 0, data.byteLength, 0);
|
|
243
|
-
} finally {
|
|
244
|
-
file.closeSync();
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
233
|
/**
|
|
249
234
|
* Synchronously writes data to a file, replacing the file if it already
|
|
250
235
|
* exists.
|
|
@@ -272,22 +257,14 @@ export function writeFileSync(path: fs.PathOrFileDescriptor, data: FileContents,
|
|
|
272
257
|
if (!encodedData) {
|
|
273
258
|
throw new ErrnoError(Errno.EINVAL, 'Data not specified');
|
|
274
259
|
}
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
writeFileSync satisfies typeof fs.writeFileSync;
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Synchronously append data to a file, creating the file if
|
|
281
|
-
* it not yet exists.
|
|
282
|
-
*/
|
|
283
|
-
function _appendFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
|
|
284
|
-
const file = _openSync(fname, flag, mode, resolveSymlinks);
|
|
260
|
+
const file = _openSync(typeof path == 'number' ? fd2file(path).path! : path.toString(), flag, options.mode, true);
|
|
285
261
|
try {
|
|
286
|
-
file.writeSync(
|
|
262
|
+
file.writeSync(encodedData, 0, encodedData.byteLength, 0);
|
|
287
263
|
} finally {
|
|
288
264
|
file.closeSync();
|
|
289
265
|
}
|
|
290
266
|
}
|
|
267
|
+
writeFileSync satisfies typeof fs.writeFileSync;
|
|
291
268
|
|
|
292
269
|
/**
|
|
293
270
|
* Asynchronously append data to a file, creating the file if it not yet
|
|
@@ -310,7 +287,12 @@ export function appendFileSync(filename: fs.PathOrFileDescriptor, data: FileCont
|
|
|
310
287
|
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
|
|
311
288
|
}
|
|
312
289
|
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
313
|
-
|
|
290
|
+
const file = _openSync(typeof filename == 'number' ? fd2file(filename).path! : filename.toString(), flag, options.mode, true);
|
|
291
|
+
try {
|
|
292
|
+
file.writeSync(encodedData, 0, encodedData.byteLength, null);
|
|
293
|
+
} finally {
|
|
294
|
+
file.closeSync();
|
|
295
|
+
}
|
|
314
296
|
}
|
|
315
297
|
appendFileSync satisfies typeof fs.appendFileSync;
|
|
316
298
|
|
|
@@ -481,7 +463,7 @@ futimesSync satisfies typeof fs.futimesSync;
|
|
|
481
463
|
* @param path
|
|
482
464
|
*/
|
|
483
465
|
export function rmdirSync(path: fs.PathLike): void {
|
|
484
|
-
return
|
|
466
|
+
return wrap('rmdirSync', true, path.toString(), cred);
|
|
485
467
|
}
|
|
486
468
|
rmdirSync satisfies typeof fs.rmdirSync;
|
|
487
469
|
|
|
@@ -497,7 +479,7 @@ export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirector
|
|
|
497
479
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined | void {
|
|
498
480
|
const mode: fs.Mode | undefined = typeof options == 'number' || typeof options == 'string' ? options : options?.mode;
|
|
499
481
|
const recursive = typeof options == 'object' && options?.recursive;
|
|
500
|
-
|
|
482
|
+
wrap('mkdirSync', true, path.toString(), normalizeMode(mode, 0o777), cred);
|
|
501
483
|
}
|
|
502
484
|
mkdirSync satisfies typeof fs.mkdirSync;
|
|
503
485
|
|
|
@@ -514,7 +496,7 @@ export function readdirSync(
|
|
|
514
496
|
options?: { recursive?: boolean; encoding?: BufferEncoding | 'buffer' | null; withFileTypes?: boolean } | BufferEncoding | 'buffer' | null
|
|
515
497
|
): string[] | Dirent[] | Buffer[] {
|
|
516
498
|
path = normalizePath(path);
|
|
517
|
-
const entries: string[] =
|
|
499
|
+
const entries: string[] = wrap('readdirSync', true, path, cred);
|
|
518
500
|
for (const mount of mounts.keys()) {
|
|
519
501
|
if (!mount.startsWith(path)) {
|
|
520
502
|
continue;
|
|
@@ -549,7 +531,7 @@ readdirSync satisfies typeof fs.readdirSync;
|
|
|
549
531
|
*/
|
|
550
532
|
export function linkSync(existing: fs.PathLike, newpath: fs.PathLike): void {
|
|
551
533
|
newpath = normalizePath(newpath);
|
|
552
|
-
return
|
|
534
|
+
return wrap('linkSync', false, existing.toString(), newpath.toString(), cred);
|
|
553
535
|
}
|
|
554
536
|
linkSync satisfies typeof fs.linkSync;
|
|
555
537
|
|
package/src/file.ts
CHANGED
|
@@ -701,8 +701,8 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
701
701
|
* For the filesystems which do not sync to anything..
|
|
702
702
|
*/
|
|
703
703
|
export class NoSyncFile<T extends FileSystem> extends PreloadFile<T> {
|
|
704
|
-
constructor(
|
|
705
|
-
super(
|
|
704
|
+
constructor(fs: T, path: string, flag: string, stats: Stats, contents?: Uint8Array) {
|
|
705
|
+
super(fs, path, flag, stats, contents);
|
|
706
706
|
}
|
|
707
707
|
/**
|
|
708
708
|
* Asynchronous sync. Doesn't do anything, simply calls the cb.
|
package/src/filesystem.ts
CHANGED
|
@@ -197,7 +197,7 @@ export abstract class FileSystem {
|
|
|
197
197
|
/**
|
|
198
198
|
* @internal
|
|
199
199
|
*/
|
|
200
|
-
declare abstract class
|
|
200
|
+
declare abstract class SyncFS extends FileSystem {
|
|
201
201
|
metadata(): FileSystemMetadata;
|
|
202
202
|
ready(): Promise<void>;
|
|
203
203
|
exists(path: string, cred: Cred): Promise<boolean>;
|
|
@@ -217,8 +217,8 @@ declare abstract class SyncFileSystem extends FileSystem {
|
|
|
217
217
|
* Implements the asynchronous API in terms of the synchronous API.
|
|
218
218
|
*/
|
|
219
219
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
220
|
-
export function Sync<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) =>
|
|
221
|
-
abstract class
|
|
220
|
+
export function Sync<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => SyncFS) & T {
|
|
221
|
+
abstract class _SyncFS extends FS implements SyncFS {
|
|
222
222
|
public async exists(path: string, cred: Cred): Promise<boolean> {
|
|
223
223
|
return this.existsSync(path, cred);
|
|
224
224
|
}
|
|
@@ -263,13 +263,13 @@ export function Sync<T extends abstract new (...args: any[]) => FileSystem>(FS:
|
|
|
263
263
|
return this.syncSync(path, data, stats);
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
-
return
|
|
266
|
+
return _SyncFS;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
270
|
* @internal
|
|
271
271
|
*/
|
|
272
|
-
declare abstract class
|
|
272
|
+
declare abstract class AsyncFS extends FileSystem {
|
|
273
273
|
/**
|
|
274
274
|
* @hidden
|
|
275
275
|
*/
|
|
@@ -312,8 +312,8 @@ type AsyncOperation = {
|
|
|
312
312
|
*
|
|
313
313
|
*/
|
|
314
314
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
-
export function Async<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) =>
|
|
316
|
-
abstract class
|
|
315
|
+
export function Async<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => AsyncFS) & T {
|
|
316
|
+
abstract class _AsyncFS extends FS implements AsyncFS {
|
|
317
317
|
/**
|
|
318
318
|
* Queue of pending asynchronous operations.
|
|
319
319
|
*/
|
|
@@ -359,18 +359,19 @@ export function Async<T extends abstract new (...args: any[]) => FileSystem>(FS:
|
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
public createFileSync(path: string, flag: string, mode: number, cred: Cred): PreloadFile<this> {
|
|
362
|
-
|
|
362
|
+
this._sync.createFileSync(path, flag, mode, cred);
|
|
363
363
|
this.queue('createFile', path, flag, mode, cred);
|
|
364
|
+
return this.openFileSync(path, flag, cred);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
public openFileSync(path: string, flag: string, cred: Cred): PreloadFile<this> {
|
|
368
|
+
const file = this._sync.openFileSync(path, flag, cred);
|
|
364
369
|
const stats = file.statSync();
|
|
365
370
|
const buffer = new Uint8Array(stats.size);
|
|
366
371
|
file.readSync(buffer);
|
|
367
372
|
return new PreloadFile(this, path, flag, stats, buffer);
|
|
368
373
|
}
|
|
369
374
|
|
|
370
|
-
public openFileSync(path: string, flag: string, cred: Cred): File {
|
|
371
|
-
return this._sync.openFileSync(path, flag, cred);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
375
|
public unlinkSync(path: string, cred: Cred): void {
|
|
375
376
|
this._sync.unlinkSync(path, cred);
|
|
376
377
|
this.queue('unlink', path, cred);
|
|
@@ -455,13 +456,13 @@ export function Async<T extends abstract new (...args: any[]) => FileSystem>(FS:
|
|
|
455
456
|
}
|
|
456
457
|
}
|
|
457
458
|
|
|
458
|
-
return
|
|
459
|
+
return _AsyncFS;
|
|
459
460
|
}
|
|
460
461
|
|
|
461
462
|
/**
|
|
462
463
|
* @internal
|
|
463
464
|
*/
|
|
464
|
-
declare abstract class
|
|
465
|
+
declare abstract class ReadonlyFS extends FileSystem {
|
|
465
466
|
metadata(): FileSystemMetadata;
|
|
466
467
|
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
467
468
|
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
@@ -483,8 +484,8 @@ declare abstract class ReadonlyFileSystem extends FileSystem {
|
|
|
483
484
|
* Implements the non-readonly methods to throw `EROFS`
|
|
484
485
|
*/
|
|
485
486
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
486
|
-
export function Readonly<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) =>
|
|
487
|
-
abstract class
|
|
487
|
+
export function Readonly<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => ReadonlyFS) & T {
|
|
488
|
+
abstract class _ReadonlyFS extends FS implements ReadonlyFS {
|
|
488
489
|
public metadata(): FileSystemMetadata {
|
|
489
490
|
return { ...super.metadata(), readonly: true };
|
|
490
491
|
}
|
|
@@ -546,5 +547,5 @@ export function Readonly<T extends abstract new (...args: any[]) => FileSystem>(
|
|
|
546
547
|
}
|
|
547
548
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
548
549
|
}
|
|
549
|
-
return
|
|
550
|
+
return _ReadonlyFS;
|
|
550
551
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ export * from './error.js';
|
|
|
2
2
|
export * from './backends/port/fs.js';
|
|
3
3
|
export * from './backends/fetch.js';
|
|
4
4
|
export * from './backends/memory.js';
|
|
5
|
-
export * from './backends/
|
|
5
|
+
export * from './backends/index/fs.js';
|
|
6
6
|
export * from './backends/locked.js';
|
|
7
7
|
export * from './backends/overlay.js';
|
|
8
8
|
export * from './backends/store/fs.js';
|
package/src/mutex.ts
CHANGED
|
@@ -5,24 +5,24 @@ import { ErrnoError, Errno } from './error.js';
|
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
7
|
export class Mutex {
|
|
8
|
-
|
|
8
|
+
protected locks: Map<string, (() => void)[]> = new Map();
|
|
9
9
|
|
|
10
10
|
public lock(path: string): Promise<void> {
|
|
11
11
|
return new Promise(resolve => {
|
|
12
|
-
if (this.
|
|
13
|
-
this.
|
|
12
|
+
if (this.locks.has(path)) {
|
|
13
|
+
this.locks.get(path)!.push(resolve);
|
|
14
14
|
} else {
|
|
15
|
-
this.
|
|
15
|
+
this.locks.set(path, [resolve]);
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
public unlock(path: string): void {
|
|
21
|
-
if (!this.
|
|
21
|
+
if (!this.locks.has(path)) {
|
|
22
22
|
throw new ErrnoError(Errno.EPERM, 'Can not unlock an already unlocked path', path);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const next = this.
|
|
25
|
+
const next = this.locks.get(path)?.shift();
|
|
26
26
|
/*
|
|
27
27
|
don't unlock - we want to queue up next for the
|
|
28
28
|
end of the current task execution, but we don't
|
|
@@ -32,23 +32,23 @@ export class Mutex {
|
|
|
32
32
|
lock won't cause starvation.
|
|
33
33
|
*/
|
|
34
34
|
if (next) {
|
|
35
|
-
setTimeout(next
|
|
35
|
+
setTimeout(next);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
this.
|
|
39
|
+
this.locks.delete(path);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
public tryLock(path: string): boolean {
|
|
43
|
-
if (this.
|
|
43
|
+
if (this.locks.has(path)) {
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
this.
|
|
47
|
+
this.locks.set(path, []);
|
|
48
48
|
return true;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
public isLocked(path: string): boolean {
|
|
52
|
-
return this.
|
|
52
|
+
return this.locks.has(path);
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/stats.ts
CHANGED
|
@@ -14,45 +14,45 @@ export enum FileType {
|
|
|
14
14
|
/**
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
|
-
export interface StatsLike {
|
|
17
|
+
export interface StatsLike<T extends number | bigint = number | bigint> {
|
|
18
18
|
/**
|
|
19
19
|
* Size of the item in bytes.
|
|
20
20
|
* For directories/symlinks, this is normally the size of the struct that represents the item.
|
|
21
21
|
*/
|
|
22
|
-
size:
|
|
22
|
+
size: T;
|
|
23
23
|
/**
|
|
24
24
|
* Unix-style file mode (e.g. 0o644) that includes the item type
|
|
25
25
|
* Type of the item can be FILE, DIRECTORY, SYMLINK, or SOCKET
|
|
26
26
|
*/
|
|
27
|
-
mode:
|
|
27
|
+
mode: T;
|
|
28
28
|
/**
|
|
29
29
|
* time of last access, in milliseconds since epoch
|
|
30
30
|
*/
|
|
31
|
-
atimeMs:
|
|
31
|
+
atimeMs: T;
|
|
32
32
|
/**
|
|
33
33
|
* time of last modification, in milliseconds since epoch
|
|
34
34
|
*/
|
|
35
|
-
mtimeMs:
|
|
35
|
+
mtimeMs: T;
|
|
36
36
|
/**
|
|
37
37
|
* time of last time file status was changed, in milliseconds since epoch
|
|
38
38
|
*/
|
|
39
|
-
ctimeMs:
|
|
39
|
+
ctimeMs: T;
|
|
40
40
|
/**
|
|
41
41
|
* time of file creation, in milliseconds since epoch
|
|
42
42
|
*/
|
|
43
|
-
birthtimeMs:
|
|
43
|
+
birthtimeMs: T;
|
|
44
44
|
/**
|
|
45
45
|
* the id of the user that owns the file
|
|
46
46
|
*/
|
|
47
|
-
uid:
|
|
47
|
+
uid: T;
|
|
48
48
|
/**
|
|
49
49
|
* the id of the group that owns the file
|
|
50
50
|
*/
|
|
51
|
-
gid:
|
|
51
|
+
gid: T;
|
|
52
52
|
/**
|
|
53
53
|
* the ino
|
|
54
54
|
*/
|
|
55
|
-
ino:
|
|
55
|
+
ino: T;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|