@zenfs/core 0.16.4 → 0.17.1
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/backend.d.ts +3 -4
- package/dist/backends/fetch.d.ts +8 -3
- package/dist/backends/fetch.js +3 -2
- package/dist/backends/{index/fs.d.ts → file_index.d.ts} +49 -10
- package/dist/backends/{index/fs.js → file_index.js} +84 -5
- package/dist/backends/memory.d.ts +6 -1
- package/dist/backends/memory.js +2 -1
- package/dist/backends/overlay.d.ts +16 -16
- package/dist/backends/overlay.js +59 -82
- package/dist/backends/port/fs.d.ts +6 -2
- package/dist/backends/port/fs.js +4 -2
- package/dist/backends/store/fs.js +484 -304
- package/dist/backends/store/simple.js +5 -1
- package/dist/backends/store/store.d.ts +4 -1
- package/dist/backends/store/store.js +9 -5
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +4 -4
- package/dist/config.d.ts +3 -3
- package/dist/emulation/async.d.ts +1 -4
- package/dist/emulation/async.js +9 -4
- package/dist/emulation/dir.d.ts +4 -0
- package/dist/emulation/dir.js +8 -6
- package/dist/emulation/promises.d.ts +1 -3
- package/dist/emulation/promises.js +25 -2
- package/dist/emulation/sync.js +0 -1
- package/dist/emulation/watchers.d.ts +9 -4
- package/dist/emulation/watchers.js +7 -0
- package/dist/file.d.ts +17 -1
- package/dist/file.js +86 -1
- package/dist/filesystem.d.ts +4 -67
- package/dist/filesystem.js +2 -313
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/mixins/async.d.ts +39 -0
- package/dist/mixins/async.js +216 -0
- package/dist/mixins/index.d.ts +4 -0
- package/dist/mixins/index.js +4 -0
- package/dist/mixins/mutexed.d.ts +33 -0
- package/dist/mixins/mutexed.js +465 -0
- package/dist/mixins/readonly.d.ts +25 -0
- package/dist/mixins/readonly.js +57 -0
- package/dist/mixins/shared.d.ts +12 -0
- package/dist/mixins/shared.js +4 -0
- package/dist/mixins/sync.d.ts +6 -0
- package/dist/mixins/sync.js +43 -0
- package/dist/utils.d.ts +0 -5
- package/dist/utils.js +0 -7
- package/package.json +3 -2
- package/src/backends/backend.ts +3 -4
- package/src/backends/fetch.ts +7 -3
- package/src/backends/{index/fs.ts → file_index.ts} +106 -8
- package/src/backends/memory.ts +5 -1
- package/src/backends/overlay.ts +64 -90
- package/src/backends/port/fs.ts +7 -2
- package/src/backends/{index/readme.md → readme.md} +1 -1
- package/src/backends/store/fs.ts +97 -155
- package/src/backends/store/simple.ts +5 -1
- package/src/backends/store/store.ts +10 -5
- package/src/config.ts +3 -1
- package/src/emulation/async.ts +20 -9
- package/src/emulation/dir.ts +19 -16
- package/src/emulation/promises.ts +28 -6
- package/src/emulation/sync.ts +1 -2
- package/src/emulation/watchers.ts +10 -4
- package/src/file.ts +94 -1
- package/src/filesystem.ts +5 -368
- package/src/index.ts +2 -2
- package/src/mixins/async.ts +211 -0
- package/src/mixins/index.ts +4 -0
- package/src/mixins/mutexed.ts +245 -0
- package/src/mixins/readonly.ts +97 -0
- package/src/mixins/shared.ts +20 -0
- package/src/mixins/sync.ts +59 -0
- package/src/utils.ts +0 -8
- package/dist/backends/index/index.d.ts +0 -43
- package/dist/backends/index/index.js +0 -83
- package/dist/backends/locked.d.ts +0 -92
- package/dist/backends/locked.js +0 -487
- package/src/backends/index/index.ts +0 -104
- package/src/backends/locked.ts +0 -264
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import type { Cred } from '../cred.js';
|
|
2
|
+
import { ErrnoError } from '../error.js';
|
|
3
|
+
import type { File } from '../file.js';
|
|
4
|
+
import type { FileSystem } from '../filesystem.js';
|
|
5
|
+
import '../polyfills.js';
|
|
6
|
+
import type { Stats } from '../stats.js';
|
|
7
|
+
import type { Mixin } from './shared.js';
|
|
8
|
+
|
|
9
|
+
export class MutexLock {
|
|
10
|
+
protected current = Promise.withResolvers<void>();
|
|
11
|
+
|
|
12
|
+
protected _isLocked: boolean = true;
|
|
13
|
+
public get isLocked(): boolean {
|
|
14
|
+
return this._isLocked;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public constructor(
|
|
18
|
+
public readonly path: string,
|
|
19
|
+
protected readonly previous?: MutexLock
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
public async done(): Promise<void> {
|
|
23
|
+
await this.previous?.done();
|
|
24
|
+
await this.current.promise;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public unlock(): void {
|
|
28
|
+
this.current.resolve();
|
|
29
|
+
this._isLocked = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public [Symbol.dispose](): void {
|
|
33
|
+
this.unlock();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* This serializes access to an underlying async filesystem.
|
|
39
|
+
* For example, on an OverlayFS instance with an async lower
|
|
40
|
+
* directory operations like rename and rmdir may involve multiple
|
|
41
|
+
* requests involving both the upper and lower filesystems -- they
|
|
42
|
+
* are not executed in a single atomic step. OverlayFS uses this
|
|
43
|
+
* to avoid having to reason about the correctness of
|
|
44
|
+
* multiple requests interleaving.
|
|
45
|
+
*
|
|
46
|
+
* Note: `@ts-expect-error 2513` is needed because `FS` is not properly detected as being concrete
|
|
47
|
+
*
|
|
48
|
+
* @todo Change `using _` to `using void` pending https://github.com/tc39/proposal-discard-binding
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
export function Mutexed<T extends new (...args: any[]) => FileSystem>(
|
|
53
|
+
FS: T
|
|
54
|
+
): Mixin<
|
|
55
|
+
T,
|
|
56
|
+
{
|
|
57
|
+
lock(path: string): Promise<MutexLock>;
|
|
58
|
+
lockSync(path: string): MutexLock;
|
|
59
|
+
isLocked(path: string): boolean;
|
|
60
|
+
}
|
|
61
|
+
> {
|
|
62
|
+
class MutexedFS extends FS {
|
|
63
|
+
/**
|
|
64
|
+
* The current locks
|
|
65
|
+
*/
|
|
66
|
+
private locks: Map<string, MutexLock> = new Map();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Adds a lock for a path
|
|
70
|
+
*/
|
|
71
|
+
protected addLock(path: string): MutexLock {
|
|
72
|
+
const previous = this.locks.get(path);
|
|
73
|
+
const lock = new MutexLock(path, previous?.isLocked ? previous : undefined);
|
|
74
|
+
this.locks.set(path, lock);
|
|
75
|
+
return lock;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Locks `path` asynchronously.
|
|
80
|
+
* If the path is currently locked, waits for it to be unlocked.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
public async lock(path: string): Promise<MutexLock> {
|
|
84
|
+
const previous = this.locks.get(path);
|
|
85
|
+
const lock = this.addLock(path);
|
|
86
|
+
await previous?.done();
|
|
87
|
+
return lock;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Locks `path` asynchronously.
|
|
92
|
+
* If the path is currently locked, an error will be thrown
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
public lockSync(path: string): MutexLock {
|
|
96
|
+
if (this.locks.has(path)) {
|
|
97
|
+
// Non-null assertion: we already checked locks has path
|
|
98
|
+
throw ErrnoError.With('EBUSY', path, 'lockSync');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return this.addLock(path);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Whether `path` is locked
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
public isLocked(path: string): boolean {
|
|
109
|
+
return !!this.locks.get(path)?.isLocked;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
113
|
+
public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
|
|
114
|
+
using _ = await this.lock(oldPath);
|
|
115
|
+
// @ts-expect-error 2513
|
|
116
|
+
await super.rename(oldPath, newPath, cred);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public renameSync(oldPath: string, newPath: string, cred: Cred): void {
|
|
120
|
+
using _ = this.lockSync(oldPath);
|
|
121
|
+
// @ts-expect-error 2513
|
|
122
|
+
return super.renameSync(oldPath, newPath, cred);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public async stat(path: string, cred: Cred): Promise<Stats> {
|
|
126
|
+
using _ = await this.lock(path);
|
|
127
|
+
// @ts-expect-error 2513
|
|
128
|
+
return await super.stat(path, cred);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public statSync(path: string, cred: Cred): Stats {
|
|
132
|
+
using _ = this.lockSync(path);
|
|
133
|
+
// @ts-expect-error 2513
|
|
134
|
+
return super.statSync(path, cred);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public async openFile(path: string, flag: string, cred: Cred): Promise<File> {
|
|
138
|
+
using _ = await this.lock(path);
|
|
139
|
+
// @ts-expect-error 2513
|
|
140
|
+
return await super.openFile(path, flag, cred);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public openFileSync(path: string, flag: string, cred: Cred): File {
|
|
144
|
+
using _ = this.lockSync(path);
|
|
145
|
+
// @ts-expect-error 2513
|
|
146
|
+
return super.openFileSync(path, flag, cred);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
|
|
150
|
+
using _ = await this.lock(path);
|
|
151
|
+
// @ts-expect-error 2513
|
|
152
|
+
return await super.createFile(path, flag, mode, cred);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public createFileSync(path: string, flag: string, mode: number, cred: Cred): File {
|
|
156
|
+
using _ = this.lockSync(path);
|
|
157
|
+
// @ts-expect-error 2513
|
|
158
|
+
return super.createFileSync(path, flag, mode, cred);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public async unlink(path: string, cred: Cred): Promise<void> {
|
|
162
|
+
using _ = await this.lock(path);
|
|
163
|
+
// @ts-expect-error 2513
|
|
164
|
+
await super.unlink(path, cred);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public unlinkSync(path: string, cred: Cred): void {
|
|
168
|
+
using _ = this.lockSync(path);
|
|
169
|
+
// @ts-expect-error 2513
|
|
170
|
+
return super.unlinkSync(path, cred);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public async rmdir(path: string, cred: Cred): Promise<void> {
|
|
174
|
+
using _ = await this.lock(path);
|
|
175
|
+
// @ts-expect-error 2513
|
|
176
|
+
await super.rmdir(path, cred);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public rmdirSync(path: string, cred: Cred): void {
|
|
180
|
+
using _ = this.lockSync(path);
|
|
181
|
+
// @ts-expect-error 2513
|
|
182
|
+
return super.rmdirSync(path, cred);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
|
|
186
|
+
using _ = await this.lock(path);
|
|
187
|
+
// @ts-expect-error 2513
|
|
188
|
+
await super.mkdir(path, mode, cred);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public mkdirSync(path: string, mode: number, cred: Cred): void {
|
|
192
|
+
using _ = this.lockSync(path);
|
|
193
|
+
// @ts-expect-error 2513
|
|
194
|
+
return super.mkdirSync(path, mode, cred);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public async readdir(path: string, cred: Cred): Promise<string[]> {
|
|
198
|
+
using _ = await this.lock(path);
|
|
199
|
+
// @ts-expect-error 2513
|
|
200
|
+
return await super.readdir(path, cred);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public readdirSync(path: string, cred: Cred): string[] {
|
|
204
|
+
using _ = this.lockSync(path);
|
|
205
|
+
// @ts-expect-error 2513
|
|
206
|
+
return super.readdirSync(path, cred);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public async exists(path: string, cred: Cred): Promise<boolean> {
|
|
210
|
+
using _ = await this.lock(path);
|
|
211
|
+
return await super.exists(path, cred);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public existsSync(path: string, cred: Cred): boolean {
|
|
215
|
+
using _ = this.lockSync(path);
|
|
216
|
+
return super.existsSync(path, cred);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
|
|
220
|
+
using _ = await this.lock(srcpath);
|
|
221
|
+
// @ts-expect-error 2513
|
|
222
|
+
await super.link(srcpath, dstpath, cred);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
|
|
226
|
+
using _ = this.lockSync(srcpath);
|
|
227
|
+
// @ts-expect-error 2513
|
|
228
|
+
return super.linkSync(srcpath, dstpath, cred);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
|
|
232
|
+
using _ = await this.lock(path);
|
|
233
|
+
// @ts-expect-error 2513
|
|
234
|
+
await super.sync(path, data, stats);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
|
|
238
|
+
using _ = this.lockSync(path);
|
|
239
|
+
// @ts-expect-error 2513
|
|
240
|
+
return super.syncSync(path, data, stats);
|
|
241
|
+
}
|
|
242
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
243
|
+
}
|
|
244
|
+
return MutexedFS;
|
|
245
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Cred } from '../cred.js';
|
|
2
|
+
import { Errno, ErrnoError } from '../error.js';
|
|
3
|
+
import type { File } from '../file.js';
|
|
4
|
+
import type { FileSystem, FileSystemMetadata } from '../filesystem.js';
|
|
5
|
+
import type { Stats } from '../stats.js';
|
|
6
|
+
import type { Mixin } from './shared.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Implements the non-readonly methods to throw `EROFS`
|
|
10
|
+
*/
|
|
11
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
12
|
+
export function Readonly<T extends typeof FileSystem>(
|
|
13
|
+
FS: T
|
|
14
|
+
): Mixin<
|
|
15
|
+
T,
|
|
16
|
+
{
|
|
17
|
+
metadata(): FileSystemMetadata;
|
|
18
|
+
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
19
|
+
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
20
|
+
createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
|
|
21
|
+
createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
|
|
22
|
+
unlink(path: string, cred: Cred): Promise<void>;
|
|
23
|
+
unlinkSync(path: string, cred: Cred): void;
|
|
24
|
+
rmdir(path: string, cred: Cred): Promise<void>;
|
|
25
|
+
rmdirSync(path: string, cred: Cred): void;
|
|
26
|
+
mkdir(path: string, mode: number, cred: Cred): Promise<void>;
|
|
27
|
+
mkdirSync(path: string, mode: number, cred: Cred): void;
|
|
28
|
+
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
29
|
+
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
30
|
+
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
31
|
+
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
32
|
+
}
|
|
33
|
+
> {
|
|
34
|
+
abstract class ReadonlyFS extends FS {
|
|
35
|
+
public metadata(): FileSystemMetadata {
|
|
36
|
+
return { ...super.metadata(), readonly: true };
|
|
37
|
+
}
|
|
38
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
39
|
+
public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
|
|
40
|
+
throw new ErrnoError(Errno.EROFS);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public renameSync(oldPath: string, newPath: string, cred: Cred): void {
|
|
44
|
+
throw new ErrnoError(Errno.EROFS);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
|
|
48
|
+
throw new ErrnoError(Errno.EROFS);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public createFileSync(path: string, flag: string, mode: number, cred: Cred): File {
|
|
52
|
+
throw new ErrnoError(Errno.EROFS);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async unlink(path: string, cred: Cred): Promise<void> {
|
|
56
|
+
throw new ErrnoError(Errno.EROFS);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public unlinkSync(path: string, cred: Cred): void {
|
|
60
|
+
throw new ErrnoError(Errno.EROFS);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public async rmdir(path: string, cred: Cred): Promise<void> {
|
|
64
|
+
throw new ErrnoError(Errno.EROFS);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public rmdirSync(path: string, cred: Cred): void {
|
|
68
|
+
throw new ErrnoError(Errno.EROFS);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
|
|
72
|
+
throw new ErrnoError(Errno.EROFS);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public mkdirSync(path: string, mode: number, cred: Cred): void {
|
|
76
|
+
throw new ErrnoError(Errno.EROFS);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
|
|
80
|
+
throw new ErrnoError(Errno.EROFS);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
|
|
84
|
+
throw new ErrnoError(Errno.EROFS);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
|
|
88
|
+
throw new ErrnoError(Errno.EROFS);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
|
|
92
|
+
throw new ErrnoError(Errno.EROFS);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return ReadonlyFS;
|
|
96
|
+
}
|
|
97
|
+
/* eslint-enable @typescript-eslint/require-await */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Code shared by various mixins
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ExtractProperties } from 'utilium';
|
|
6
|
+
import type { FileSystem } from '../filesystem.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `TBase` with `TMixin` mixed-in.
|
|
10
|
+
* @internal @experimental
|
|
11
|
+
*/
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
export type Mixin<TBase extends typeof FileSystem, TMixin> = (abstract new (...args: any[]) => TMixin) & TBase;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Asynchronous `FileSystem` methods. This is a convience type.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
export type _AsyncFSMethods = ExtractProperties<FileSystem, (...args: any[]) => Promise<unknown>>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Cred } from '../cred.js';
|
|
2
|
+
import type { File } from '../file.js';
|
|
3
|
+
import type { Stats } from '../stats.js';
|
|
4
|
+
import type { FileSystem } from '../filesystem.js';
|
|
5
|
+
import type { Mixin, _AsyncFSMethods } from './shared.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Implements the asynchronous API in terms of the synchronous API.
|
|
9
|
+
*/
|
|
10
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
11
|
+
export function Sync<T extends typeof FileSystem>(FS: T): Mixin<T, _AsyncFSMethods> {
|
|
12
|
+
abstract class SyncFS extends FS implements _AsyncFSMethods {
|
|
13
|
+
public async exists(path: string, cred: Cred): Promise<boolean> {
|
|
14
|
+
return this.existsSync(path, cred);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
|
|
18
|
+
return this.renameSync(oldPath, newPath, cred);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async stat(path: string, cred: Cred): Promise<Stats> {
|
|
22
|
+
return this.statSync(path, cred);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
|
|
26
|
+
return this.createFileSync(path, flag, mode, cred);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async openFile(path: string, flag: string, cred: Cred): Promise<File> {
|
|
30
|
+
return this.openFileSync(path, flag, cred);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async unlink(path: string, cred: Cred): Promise<void> {
|
|
34
|
+
return this.unlinkSync(path, cred);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public async rmdir(path: string, cred: Cred): Promise<void> {
|
|
38
|
+
return this.rmdirSync(path, cred);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
|
|
42
|
+
return this.mkdirSync(path, mode, cred);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async readdir(path: string, cred: Cred): Promise<string[]> {
|
|
46
|
+
return this.readdirSync(path, cred);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
|
|
50
|
+
return this.linkSync(srcpath, dstpath, cred);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
|
|
54
|
+
return this.syncSync(path, data, stats);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return SyncFS;
|
|
58
|
+
}
|
|
59
|
+
/* eslint-enable @typescript-eslint/require-await */
|
package/src/utils.ts
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { StatsLike } from '../../stats.js';
|
|
2
|
-
import { Stats } from '../../stats.js';
|
|
3
|
-
/**
|
|
4
|
-
* An Index in JSON form
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
export interface IndexData {
|
|
8
|
-
version: 1;
|
|
9
|
-
entries: Record<string, StatsLike<number>>;
|
|
10
|
-
}
|
|
11
|
-
export declare const version = 1;
|
|
12
|
-
/**
|
|
13
|
-
* An index of files
|
|
14
|
-
* @internal
|
|
15
|
-
*/
|
|
16
|
-
export declare class Index extends Map<string, Stats> {
|
|
17
|
-
constructor();
|
|
18
|
-
/**
|
|
19
|
-
* Convience method
|
|
20
|
-
*/
|
|
21
|
-
files(): Map<string, Stats>;
|
|
22
|
-
/**
|
|
23
|
-
* Converts the index to JSON
|
|
24
|
-
*/
|
|
25
|
-
toJSON(): IndexData;
|
|
26
|
-
/**
|
|
27
|
-
* Converts the index to a string
|
|
28
|
-
*/
|
|
29
|
-
toString(): string;
|
|
30
|
-
/**
|
|
31
|
-
* Returns the files in the directory `dir`.
|
|
32
|
-
* This is expensive so it is only called once per directory.
|
|
33
|
-
*/
|
|
34
|
-
protected dirEntries(dir: string): string[];
|
|
35
|
-
/**
|
|
36
|
-
* Loads the index from JSON data
|
|
37
|
-
*/
|
|
38
|
-
fromJSON(json: IndexData): void;
|
|
39
|
-
/**
|
|
40
|
-
* Parses an index from a string
|
|
41
|
-
*/
|
|
42
|
-
static parse(data: string): Index;
|
|
43
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { isJSON } from 'utilium';
|
|
2
|
-
import { Errno, ErrnoError } from '../../error.js';
|
|
3
|
-
import { Stats } from '../../stats.js';
|
|
4
|
-
import { encode } from '../../utils.js';
|
|
5
|
-
import { basename, dirname } from '../../emulation/path.js';
|
|
6
|
-
export const version = 1;
|
|
7
|
-
/**
|
|
8
|
-
* An index of files
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
export class Index extends Map {
|
|
12
|
-
constructor() {
|
|
13
|
-
super();
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Convience method
|
|
17
|
-
*/
|
|
18
|
-
files() {
|
|
19
|
-
const files = new Map();
|
|
20
|
-
for (const [path, stats] of this) {
|
|
21
|
-
if (stats.isFile()) {
|
|
22
|
-
files.set(path, stats);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return files;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Converts the index to JSON
|
|
29
|
-
*/
|
|
30
|
-
toJSON() {
|
|
31
|
-
return {
|
|
32
|
-
version,
|
|
33
|
-
entries: Object.fromEntries(this),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Converts the index to a string
|
|
38
|
-
*/
|
|
39
|
-
toString() {
|
|
40
|
-
return JSON.stringify(this.toJSON());
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Returns the files in the directory `dir`.
|
|
44
|
-
* This is expensive so it is only called once per directory.
|
|
45
|
-
*/
|
|
46
|
-
dirEntries(dir) {
|
|
47
|
-
const entries = [];
|
|
48
|
-
for (const entry of this.keys()) {
|
|
49
|
-
if (dirname(entry) == dir) {
|
|
50
|
-
entries.push(basename(entry));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return entries;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Loads the index from JSON data
|
|
57
|
-
*/
|
|
58
|
-
fromJSON(json) {
|
|
59
|
-
if (json.version != version) {
|
|
60
|
-
throw new ErrnoError(Errno.EINVAL, 'Index version mismatch');
|
|
61
|
-
}
|
|
62
|
-
this.clear();
|
|
63
|
-
for (const [path, data] of Object.entries(json.entries)) {
|
|
64
|
-
const stats = new Stats(data);
|
|
65
|
-
if (stats.isDirectory()) {
|
|
66
|
-
stats.fileData = encode(JSON.stringify(this.dirEntries(path)));
|
|
67
|
-
}
|
|
68
|
-
this.set(path, stats);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Parses an index from a string
|
|
73
|
-
*/
|
|
74
|
-
static parse(data) {
|
|
75
|
-
if (!isJSON(data)) {
|
|
76
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid JSON');
|
|
77
|
-
}
|
|
78
|
-
const json = JSON.parse(data);
|
|
79
|
-
const index = new Index();
|
|
80
|
-
index.fromJSON(json);
|
|
81
|
-
return index;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { Cred } from '../cred.js';
|
|
2
|
-
import type { File } from '../file.js';
|
|
3
|
-
import type { FileSystemMetadata } from '../filesystem.js';
|
|
4
|
-
import { FileSystem } from '../filesystem.js';
|
|
5
|
-
import type { Stats } from '../stats.js';
|
|
6
|
-
import '../polyfills.js';
|
|
7
|
-
export interface MutexLock extends PromiseWithResolvers<void> {
|
|
8
|
-
[Symbol.dispose](): void;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* This class serializes access to an underlying async filesystem.
|
|
12
|
-
* For example, on an OverlayFS instance with an async lower
|
|
13
|
-
* directory operations like rename and rmdir may involve multiple
|
|
14
|
-
* requests involving both the upper and lower filesystems -- they
|
|
15
|
-
* are not executed in a single atomic step. OverlayFS uses this
|
|
16
|
-
* LockedFS to avoid having to reason about the correctness of
|
|
17
|
-
* multiple requests interleaving.
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
export declare class LockedFS<FS extends FileSystem> implements FileSystem {
|
|
21
|
-
readonly fs: FS;
|
|
22
|
-
constructor(fs: FS);
|
|
23
|
-
/**
|
|
24
|
-
* The current locks
|
|
25
|
-
*/
|
|
26
|
-
private locks;
|
|
27
|
-
protected addLock(path: string): MutexLock;
|
|
28
|
-
/**
|
|
29
|
-
* Locks `path` asynchronously.
|
|
30
|
-
* If the path is currently locked, waits for it to be unlocked.
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
lock(path: string): Promise<MutexLock>;
|
|
34
|
-
/**
|
|
35
|
-
* Locks `path` asynchronously.
|
|
36
|
-
* If the path is currently locked, an error will be thrown
|
|
37
|
-
* @internal
|
|
38
|
-
*/
|
|
39
|
-
lockSync(path: string): MutexLock;
|
|
40
|
-
/**
|
|
41
|
-
* Unlocks a path
|
|
42
|
-
* @param path The path to lock
|
|
43
|
-
* @param noThrow If true, an error will not be thrown if the path is already unlocked
|
|
44
|
-
* @returns Whether the path was unlocked
|
|
45
|
-
* @internal
|
|
46
|
-
*/
|
|
47
|
-
unlock(path: string, noThrow?: boolean): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Whether `path` is locked
|
|
50
|
-
* @internal
|
|
51
|
-
*/
|
|
52
|
-
isLocked(path: string): boolean;
|
|
53
|
-
ready(): Promise<void>;
|
|
54
|
-
metadata(): FileSystemMetadata;
|
|
55
|
-
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
56
|
-
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
57
|
-
stat(path: string, cred: Cred): Promise<Stats>;
|
|
58
|
-
statSync(path: string, cred: Cred): Stats;
|
|
59
|
-
openFile(path: string, flag: string, cred: Cred): Promise<File>;
|
|
60
|
-
openFileSync(path: string, flag: string, cred: Cred): File;
|
|
61
|
-
createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
|
|
62
|
-
createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
|
|
63
|
-
unlink(path: string, cred: Cred): Promise<void>;
|
|
64
|
-
unlinkSync(path: string, cred: Cred): void;
|
|
65
|
-
rmdir(path: string, cred: Cred): Promise<void>;
|
|
66
|
-
rmdirSync(path: string, cred: Cred): void;
|
|
67
|
-
mkdir(path: string, mode: number, cred: Cred): Promise<void>;
|
|
68
|
-
mkdirSync(path: string, mode: number, cred: Cred): void;
|
|
69
|
-
readdir(path: string, cred: Cred): Promise<string[]>;
|
|
70
|
-
readdirSync(path: string, cred: Cred): string[];
|
|
71
|
-
exists(path: string, cred: Cred): Promise<boolean>;
|
|
72
|
-
existsSync(path: string, cred: Cred): boolean;
|
|
73
|
-
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
74
|
-
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
75
|
-
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
76
|
-
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
77
|
-
}
|
|
78
|
-
export declare const Locked: {
|
|
79
|
-
name: string;
|
|
80
|
-
options: {
|
|
81
|
-
fs: {
|
|
82
|
-
type: "object";
|
|
83
|
-
required: true;
|
|
84
|
-
description: string;
|
|
85
|
-
validator(fs: FileSystem): void;
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
isAvailable(): true;
|
|
89
|
-
create({ fs }: {
|
|
90
|
-
fs: FileSystem;
|
|
91
|
-
} & Partial<import("./backend.js").SharedConfig>): LockedFS<FileSystem>;
|
|
92
|
-
};
|