@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
package/dist/filesystem.js
CHANGED
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
}
|
|
13
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
14
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
15
|
-
}
|
|
16
|
-
else if (async) {
|
|
17
|
-
env.stack.push({ async: true });
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
};
|
|
21
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
22
|
-
return function (env) {
|
|
23
|
-
function fail(e) {
|
|
24
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
25
|
-
env.hasError = true;
|
|
26
|
-
}
|
|
27
|
-
function next() {
|
|
28
|
-
while (env.stack.length) {
|
|
29
|
-
var rec = env.stack.pop();
|
|
30
|
-
try {
|
|
31
|
-
var result = rec.dispose && rec.dispose.call(rec.value);
|
|
32
|
-
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
33
|
-
}
|
|
34
|
-
catch (e) {
|
|
35
|
-
fail(e);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (env.hasError) throw env.error;
|
|
39
|
-
}
|
|
40
|
-
return next();
|
|
41
|
-
};
|
|
42
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
43
|
-
var e = new Error(message);
|
|
44
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
45
|
-
});
|
|
46
|
-
import { rootCred } from './cred.js';
|
|
47
|
-
import { join } from './emulation/path.js';
|
|
48
|
-
import { Errno, ErrnoError } from './error.js';
|
|
49
|
-
import { PreloadFile, parseFlag } from './file.js';
|
|
50
1
|
import { ZenFsType } from './stats.js';
|
|
51
2
|
/**
|
|
52
3
|
* Structure for a filesystem. All ZenFS backends must extend this.
|
|
@@ -74,7 +25,7 @@ export class FileSystem {
|
|
|
74
25
|
constructor(...args) { }
|
|
75
26
|
async ready() { }
|
|
76
27
|
/**
|
|
77
|
-
* Test whether or not the given path exists
|
|
28
|
+
* Test whether or not the given path exists.
|
|
78
29
|
*/
|
|
79
30
|
async exists(path, cred) {
|
|
80
31
|
try {
|
|
@@ -86,7 +37,7 @@ export class FileSystem {
|
|
|
86
37
|
}
|
|
87
38
|
}
|
|
88
39
|
/**
|
|
89
|
-
* Test whether or not the given path exists
|
|
40
|
+
* Test whether or not the given path exists.
|
|
90
41
|
*/
|
|
91
42
|
existsSync(path, cred) {
|
|
92
43
|
try {
|
|
@@ -98,265 +49,3 @@ export class FileSystem {
|
|
|
98
49
|
}
|
|
99
50
|
}
|
|
100
51
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Implements the asynchronous API in terms of the synchronous API.
|
|
103
|
-
*/
|
|
104
|
-
export function Sync(FS) {
|
|
105
|
-
class SyncFS extends FS {
|
|
106
|
-
async exists(path, cred) {
|
|
107
|
-
return this.existsSync(path, cred);
|
|
108
|
-
}
|
|
109
|
-
async rename(oldPath, newPath, cred) {
|
|
110
|
-
return this.renameSync(oldPath, newPath, cred);
|
|
111
|
-
}
|
|
112
|
-
async stat(path, cred) {
|
|
113
|
-
return this.statSync(path, cred);
|
|
114
|
-
}
|
|
115
|
-
async createFile(path, flag, mode, cred) {
|
|
116
|
-
return this.createFileSync(path, flag, mode, cred);
|
|
117
|
-
}
|
|
118
|
-
async openFile(path, flag, cred) {
|
|
119
|
-
return this.openFileSync(path, flag, cred);
|
|
120
|
-
}
|
|
121
|
-
async unlink(path, cred) {
|
|
122
|
-
return this.unlinkSync(path, cred);
|
|
123
|
-
}
|
|
124
|
-
async rmdir(path, cred) {
|
|
125
|
-
return this.rmdirSync(path, cred);
|
|
126
|
-
}
|
|
127
|
-
async mkdir(path, mode, cred) {
|
|
128
|
-
return this.mkdirSync(path, mode, cred);
|
|
129
|
-
}
|
|
130
|
-
async readdir(path, cred) {
|
|
131
|
-
return this.readdirSync(path, cred);
|
|
132
|
-
}
|
|
133
|
-
async link(srcpath, dstpath, cred) {
|
|
134
|
-
return this.linkSync(srcpath, dstpath, cred);
|
|
135
|
-
}
|
|
136
|
-
async sync(path, data, stats) {
|
|
137
|
-
return this.syncSync(path, data, stats);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return SyncFS;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Async() implements synchronous methods on an asynchronous file system
|
|
144
|
-
*
|
|
145
|
-
* Implementing classes must define `_sync` for the synchronous file system used as a cache.
|
|
146
|
-
* Synchronous methods on an asynchronous FS are implemented by:
|
|
147
|
-
* - Performing operations over the in-memory copy,
|
|
148
|
-
* while asynchronously pipelining them to the backing store.
|
|
149
|
-
* - During loading, the contents of the async file system are preloaded into the synchronous store.
|
|
150
|
-
*
|
|
151
|
-
*/
|
|
152
|
-
export function Async(FS) {
|
|
153
|
-
class AsyncFS extends FS {
|
|
154
|
-
constructor() {
|
|
155
|
-
super(...arguments);
|
|
156
|
-
/**
|
|
157
|
-
* Queue of pending asynchronous operations.
|
|
158
|
-
*/
|
|
159
|
-
this._queue = [];
|
|
160
|
-
this._isInitialized = false;
|
|
161
|
-
}
|
|
162
|
-
get _queueRunning() {
|
|
163
|
-
return !!this._queue.length;
|
|
164
|
-
}
|
|
165
|
-
queueDone() {
|
|
166
|
-
return new Promise(resolve => {
|
|
167
|
-
const check = () => (this._queueRunning ? setTimeout(check) : resolve());
|
|
168
|
-
check();
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
async ready() {
|
|
172
|
-
await super.ready();
|
|
173
|
-
if (this._isInitialized || this._disableSync) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
this.checkSync();
|
|
177
|
-
await this._sync.ready();
|
|
178
|
-
try {
|
|
179
|
-
await this.crossCopy('/');
|
|
180
|
-
this._isInitialized = true;
|
|
181
|
-
}
|
|
182
|
-
catch (e) {
|
|
183
|
-
this._isInitialized = false;
|
|
184
|
-
throw e;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
checkSync(path, syscall) {
|
|
188
|
-
if (this._disableSync) {
|
|
189
|
-
throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
|
|
190
|
-
}
|
|
191
|
-
if (!this._sync) {
|
|
192
|
-
throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
renameSync(oldPath, newPath, cred) {
|
|
196
|
-
this.checkSync(oldPath, 'rename');
|
|
197
|
-
this._sync.renameSync(oldPath, newPath, cred);
|
|
198
|
-
this.queue('rename', oldPath, newPath, cred);
|
|
199
|
-
}
|
|
200
|
-
statSync(path, cred) {
|
|
201
|
-
this.checkSync(path, 'stat');
|
|
202
|
-
return this._sync.statSync(path, cred);
|
|
203
|
-
}
|
|
204
|
-
createFileSync(path, flag, mode, cred) {
|
|
205
|
-
this.checkSync(path, 'createFile');
|
|
206
|
-
this._sync.createFileSync(path, flag, mode, cred);
|
|
207
|
-
this.queue('createFile', path, flag, mode, cred);
|
|
208
|
-
return this.openFileSync(path, flag, cred);
|
|
209
|
-
}
|
|
210
|
-
openFileSync(path, flag, cred) {
|
|
211
|
-
this.checkSync(path, 'openFile');
|
|
212
|
-
const file = this._sync.openFileSync(path, flag, cred);
|
|
213
|
-
const stats = file.statSync();
|
|
214
|
-
const buffer = new Uint8Array(stats.size);
|
|
215
|
-
file.readSync(buffer);
|
|
216
|
-
return new PreloadFile(this, path, flag, stats, buffer);
|
|
217
|
-
}
|
|
218
|
-
unlinkSync(path, cred) {
|
|
219
|
-
this.checkSync(path, 'unlinkSync');
|
|
220
|
-
this._sync.unlinkSync(path, cred);
|
|
221
|
-
this.queue('unlink', path, cred);
|
|
222
|
-
}
|
|
223
|
-
rmdirSync(path, cred) {
|
|
224
|
-
this.checkSync(path, 'rmdir');
|
|
225
|
-
this._sync.rmdirSync(path, cred);
|
|
226
|
-
this.queue('rmdir', path, cred);
|
|
227
|
-
}
|
|
228
|
-
mkdirSync(path, mode, cred) {
|
|
229
|
-
this.checkSync(path, 'mkdir');
|
|
230
|
-
this._sync.mkdirSync(path, mode, cred);
|
|
231
|
-
this.queue('mkdir', path, mode, cred);
|
|
232
|
-
}
|
|
233
|
-
readdirSync(path, cred) {
|
|
234
|
-
this.checkSync(path, 'readdir');
|
|
235
|
-
return this._sync.readdirSync(path, cred);
|
|
236
|
-
}
|
|
237
|
-
linkSync(srcpath, dstpath, cred) {
|
|
238
|
-
this.checkSync(srcpath, 'link');
|
|
239
|
-
this._sync.linkSync(srcpath, dstpath, cred);
|
|
240
|
-
this.queue('link', srcpath, dstpath, cred);
|
|
241
|
-
}
|
|
242
|
-
syncSync(path, data, stats) {
|
|
243
|
-
this.checkSync(path, 'sync');
|
|
244
|
-
this._sync.syncSync(path, data, stats);
|
|
245
|
-
this.queue('sync', path, data, stats);
|
|
246
|
-
}
|
|
247
|
-
existsSync(path, cred) {
|
|
248
|
-
this.checkSync(path, 'exists');
|
|
249
|
-
return this._sync.existsSync(path, cred);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* @internal
|
|
253
|
-
*/
|
|
254
|
-
async crossCopy(path) {
|
|
255
|
-
this.checkSync(path, 'crossCopy');
|
|
256
|
-
const stats = await this.stat(path, rootCred);
|
|
257
|
-
if (stats.isDirectory()) {
|
|
258
|
-
if (path !== '/') {
|
|
259
|
-
const stats = await this.stat(path, rootCred);
|
|
260
|
-
this._sync.mkdirSync(path, stats.mode, stats.cred());
|
|
261
|
-
}
|
|
262
|
-
const files = await this.readdir(path, rootCred);
|
|
263
|
-
for (const file of files) {
|
|
264
|
-
await this.crossCopy(join(path, file));
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
269
|
-
try {
|
|
270
|
-
const asyncFile = __addDisposableResource(env_1, await this.openFile(path, parseFlag('r'), rootCred), true);
|
|
271
|
-
const syncFile = __addDisposableResource(env_1, this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred()), false);
|
|
272
|
-
const buffer = new Uint8Array(stats.size);
|
|
273
|
-
await asyncFile.read(buffer);
|
|
274
|
-
syncFile.writeSync(buffer, 0, stats.size);
|
|
275
|
-
}
|
|
276
|
-
catch (e_1) {
|
|
277
|
-
env_1.error = e_1;
|
|
278
|
-
env_1.hasError = true;
|
|
279
|
-
}
|
|
280
|
-
finally {
|
|
281
|
-
const result_1 = __disposeResources(env_1);
|
|
282
|
-
if (result_1)
|
|
283
|
-
await result_1;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* @internal
|
|
289
|
-
*/
|
|
290
|
-
async _next() {
|
|
291
|
-
if (!this._queueRunning) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
const [method, ...args] = this._queue.shift();
|
|
295
|
-
// @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
|
|
296
|
-
await this[method](...args);
|
|
297
|
-
await this._next();
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* @internal
|
|
301
|
-
*/
|
|
302
|
-
queue(...op) {
|
|
303
|
-
this._queue.push(op);
|
|
304
|
-
void this._next();
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return AsyncFS;
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Implements the non-readonly methods to throw `EROFS`
|
|
311
|
-
*/
|
|
312
|
-
export function Readonly(FS) {
|
|
313
|
-
class ReadonlyFS extends FS {
|
|
314
|
-
metadata() {
|
|
315
|
-
return { ...super.metadata(), readonly: true };
|
|
316
|
-
}
|
|
317
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
318
|
-
async rename(oldPath, newPath, cred) {
|
|
319
|
-
throw new ErrnoError(Errno.EROFS);
|
|
320
|
-
}
|
|
321
|
-
renameSync(oldPath, newPath, cred) {
|
|
322
|
-
throw new ErrnoError(Errno.EROFS);
|
|
323
|
-
}
|
|
324
|
-
async createFile(path, flag, mode, cred) {
|
|
325
|
-
throw new ErrnoError(Errno.EROFS);
|
|
326
|
-
}
|
|
327
|
-
createFileSync(path, flag, mode, cred) {
|
|
328
|
-
throw new ErrnoError(Errno.EROFS);
|
|
329
|
-
}
|
|
330
|
-
async unlink(path, cred) {
|
|
331
|
-
throw new ErrnoError(Errno.EROFS);
|
|
332
|
-
}
|
|
333
|
-
unlinkSync(path, cred) {
|
|
334
|
-
throw new ErrnoError(Errno.EROFS);
|
|
335
|
-
}
|
|
336
|
-
async rmdir(path, cred) {
|
|
337
|
-
throw new ErrnoError(Errno.EROFS);
|
|
338
|
-
}
|
|
339
|
-
rmdirSync(path, cred) {
|
|
340
|
-
throw new ErrnoError(Errno.EROFS);
|
|
341
|
-
}
|
|
342
|
-
async mkdir(path, mode, cred) {
|
|
343
|
-
throw new ErrnoError(Errno.EROFS);
|
|
344
|
-
}
|
|
345
|
-
mkdirSync(path, mode, cred) {
|
|
346
|
-
throw new ErrnoError(Errno.EROFS);
|
|
347
|
-
}
|
|
348
|
-
async link(srcpath, dstpath, cred) {
|
|
349
|
-
throw new ErrnoError(Errno.EROFS);
|
|
350
|
-
}
|
|
351
|
-
linkSync(srcpath, dstpath, cred) {
|
|
352
|
-
throw new ErrnoError(Errno.EROFS);
|
|
353
|
-
}
|
|
354
|
-
async sync(path, data, stats) {
|
|
355
|
-
throw new ErrnoError(Errno.EROFS);
|
|
356
|
-
}
|
|
357
|
-
syncSync(path, data, stats) {
|
|
358
|
-
throw new ErrnoError(Errno.EROFS);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return ReadonlyFS;
|
|
362
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +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/
|
|
6
|
-
export * from './backends/locked.js';
|
|
5
|
+
export * from './backends/file_index.js';
|
|
7
6
|
export * from './backends/overlay.js';
|
|
8
7
|
export * from './backends/store/fs.js';
|
|
9
8
|
export * from './backends/store/simple.js';
|
|
@@ -14,6 +13,7 @@ export * from './cred.js';
|
|
|
14
13
|
export * from './file.js';
|
|
15
14
|
export * from './filesystem.js';
|
|
16
15
|
export * from './inode.js';
|
|
16
|
+
export * from './mixins/index.js';
|
|
17
17
|
export * from './stats.js';
|
|
18
18
|
export * from './utils.js';
|
|
19
19
|
export * from './emulation/index.js';
|
package/dist/index.js
CHANGED
|
@@ -2,8 +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/
|
|
6
|
-
export * from './backends/locked.js';
|
|
5
|
+
export * from './backends/file_index.js';
|
|
7
6
|
export * from './backends/overlay.js';
|
|
8
7
|
export * from './backends/store/fs.js';
|
|
9
8
|
export * from './backends/store/simple.js';
|
|
@@ -14,6 +13,7 @@ export * from './cred.js';
|
|
|
14
13
|
export * from './file.js';
|
|
15
14
|
export * from './filesystem.js';
|
|
16
15
|
export * from './inode.js';
|
|
16
|
+
export * from './mixins/index.js';
|
|
17
17
|
export * from './stats.js';
|
|
18
18
|
export * from './utils.js';
|
|
19
19
|
export * from './emulation/index.js';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Cred } from '../cred.js';
|
|
2
|
+
import { type File } from '../file.js';
|
|
3
|
+
import type { FileSystem } from '../filesystem.js';
|
|
4
|
+
import type { Stats } from '../stats.js';
|
|
5
|
+
import type { _AsyncFSMethods, Mixin } from './shared.js';
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export type AsyncOperation = {
|
|
10
|
+
[K in keyof _AsyncFSMethods]: [K, ...Parameters<FileSystem[K]>];
|
|
11
|
+
}[keyof _AsyncFSMethods];
|
|
12
|
+
/**
|
|
13
|
+
* Async() implements synchronous methods on an asynchronous file system
|
|
14
|
+
*
|
|
15
|
+
* Implementing classes must define `_sync` for the synchronous file system used as a cache.
|
|
16
|
+
* Synchronous methods on an asynchronous FS are implemented by:
|
|
17
|
+
* - Performing operations over the in-memory copy,
|
|
18
|
+
* while asynchronously pipelining them to the backing store.
|
|
19
|
+
* - During loading, the contents of the async file system are preloaded into the synchronous store.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
export declare function Async<T extends typeof FileSystem>(FS: T): Mixin<T, {
|
|
23
|
+
/**
|
|
24
|
+
* @internal @protected
|
|
25
|
+
*/
|
|
26
|
+
_sync?: FileSystem;
|
|
27
|
+
queueDone(): Promise<void>;
|
|
28
|
+
ready(): Promise<void>;
|
|
29
|
+
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
30
|
+
statSync(path: string, cred: Cred): Stats;
|
|
31
|
+
createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
|
|
32
|
+
openFileSync(path: string, flag: string, cred: Cred): File;
|
|
33
|
+
unlinkSync(path: string, cred: Cred): void;
|
|
34
|
+
rmdirSync(path: string, cred: Cred): void;
|
|
35
|
+
mkdirSync(path: string, mode: number, cred: Cred): void;
|
|
36
|
+
readdirSync(path: string, cred: Cred): string[];
|
|
37
|
+
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
38
|
+
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
39
|
+
}>;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
}
|
|
13
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
14
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
15
|
+
}
|
|
16
|
+
else if (async) {
|
|
17
|
+
env.stack.push({ async: true });
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
22
|
+
return function (env) {
|
|
23
|
+
function fail(e) {
|
|
24
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
25
|
+
env.hasError = true;
|
|
26
|
+
}
|
|
27
|
+
function next() {
|
|
28
|
+
while (env.stack.length) {
|
|
29
|
+
var rec = env.stack.pop();
|
|
30
|
+
try {
|
|
31
|
+
var result = rec.dispose && rec.dispose.call(rec.value);
|
|
32
|
+
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
fail(e);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (env.hasError) throw env.error;
|
|
39
|
+
}
|
|
40
|
+
return next();
|
|
41
|
+
};
|
|
42
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
43
|
+
var e = new Error(message);
|
|
44
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
45
|
+
});
|
|
46
|
+
import { rootCred } from '../cred.js';
|
|
47
|
+
import { join } from '../emulation/path.js';
|
|
48
|
+
import { Errno, ErrnoError } from '../error.js';
|
|
49
|
+
import { PreloadFile, parseFlag } from '../file.js';
|
|
50
|
+
/**
|
|
51
|
+
* Async() implements synchronous methods on an asynchronous file system
|
|
52
|
+
*
|
|
53
|
+
* Implementing classes must define `_sync` for the synchronous file system used as a cache.
|
|
54
|
+
* Synchronous methods on an asynchronous FS are implemented by:
|
|
55
|
+
* - Performing operations over the in-memory copy,
|
|
56
|
+
* while asynchronously pipelining them to the backing store.
|
|
57
|
+
* - During loading, the contents of the async file system are preloaded into the synchronous store.
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
export function Async(FS) {
|
|
61
|
+
class AsyncFS extends FS {
|
|
62
|
+
constructor() {
|
|
63
|
+
super(...arguments);
|
|
64
|
+
/**
|
|
65
|
+
* Queue of pending asynchronous operations.
|
|
66
|
+
*/
|
|
67
|
+
this._queue = [];
|
|
68
|
+
this._isInitialized = false;
|
|
69
|
+
}
|
|
70
|
+
get _queueRunning() {
|
|
71
|
+
return !!this._queue.length;
|
|
72
|
+
}
|
|
73
|
+
queueDone() {
|
|
74
|
+
return new Promise(resolve => {
|
|
75
|
+
const check = () => (this._queueRunning ? setTimeout(check) : resolve());
|
|
76
|
+
check();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async ready() {
|
|
80
|
+
await super.ready();
|
|
81
|
+
if (this._isInitialized || this._disableSync) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.checkSync();
|
|
85
|
+
await this._sync.ready();
|
|
86
|
+
try {
|
|
87
|
+
await this.crossCopy('/');
|
|
88
|
+
this._isInitialized = true;
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
this._isInitialized = false;
|
|
92
|
+
throw e;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
checkSync(path, syscall) {
|
|
96
|
+
if (this._disableSync) {
|
|
97
|
+
throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
|
|
98
|
+
}
|
|
99
|
+
if (!this._sync) {
|
|
100
|
+
throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
renameSync(oldPath, newPath, cred) {
|
|
104
|
+
this.checkSync(oldPath, 'rename');
|
|
105
|
+
this._sync.renameSync(oldPath, newPath, cred);
|
|
106
|
+
this.queue('rename', oldPath, newPath, cred);
|
|
107
|
+
}
|
|
108
|
+
statSync(path, cred) {
|
|
109
|
+
this.checkSync(path, 'stat');
|
|
110
|
+
return this._sync.statSync(path, cred);
|
|
111
|
+
}
|
|
112
|
+
createFileSync(path, flag, mode, cred) {
|
|
113
|
+
this.checkSync(path, 'createFile');
|
|
114
|
+
this._sync.createFileSync(path, flag, mode, cred);
|
|
115
|
+
this.queue('createFile', path, flag, mode, cred);
|
|
116
|
+
return this.openFileSync(path, flag, cred);
|
|
117
|
+
}
|
|
118
|
+
openFileSync(path, flag, cred) {
|
|
119
|
+
this.checkSync(path, 'openFile');
|
|
120
|
+
const file = this._sync.openFileSync(path, flag, cred);
|
|
121
|
+
const stats = file.statSync();
|
|
122
|
+
const buffer = new Uint8Array(stats.size);
|
|
123
|
+
file.readSync(buffer);
|
|
124
|
+
return new PreloadFile(this, path, flag, stats, buffer);
|
|
125
|
+
}
|
|
126
|
+
unlinkSync(path, cred) {
|
|
127
|
+
this.checkSync(path, 'unlinkSync');
|
|
128
|
+
this._sync.unlinkSync(path, cred);
|
|
129
|
+
this.queue('unlink', path, cred);
|
|
130
|
+
}
|
|
131
|
+
rmdirSync(path, cred) {
|
|
132
|
+
this.checkSync(path, 'rmdir');
|
|
133
|
+
this._sync.rmdirSync(path, cred);
|
|
134
|
+
this.queue('rmdir', path, cred);
|
|
135
|
+
}
|
|
136
|
+
mkdirSync(path, mode, cred) {
|
|
137
|
+
this.checkSync(path, 'mkdir');
|
|
138
|
+
this._sync.mkdirSync(path, mode, cred);
|
|
139
|
+
this.queue('mkdir', path, mode, cred);
|
|
140
|
+
}
|
|
141
|
+
readdirSync(path, cred) {
|
|
142
|
+
this.checkSync(path, 'readdir');
|
|
143
|
+
return this._sync.readdirSync(path, cred);
|
|
144
|
+
}
|
|
145
|
+
linkSync(srcpath, dstpath, cred) {
|
|
146
|
+
this.checkSync(srcpath, 'link');
|
|
147
|
+
this._sync.linkSync(srcpath, dstpath, cred);
|
|
148
|
+
this.queue('link', srcpath, dstpath, cred);
|
|
149
|
+
}
|
|
150
|
+
syncSync(path, data, stats) {
|
|
151
|
+
this.checkSync(path, 'sync');
|
|
152
|
+
this._sync.syncSync(path, data, stats);
|
|
153
|
+
this.queue('sync', path, data, stats);
|
|
154
|
+
}
|
|
155
|
+
existsSync(path, cred) {
|
|
156
|
+
this.checkSync(path, 'exists');
|
|
157
|
+
return this._sync.existsSync(path, cred);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
async crossCopy(path) {
|
|
163
|
+
this.checkSync(path, 'crossCopy');
|
|
164
|
+
const stats = await this.stat(path, rootCred);
|
|
165
|
+
if (stats.isDirectory()) {
|
|
166
|
+
if (path !== '/') {
|
|
167
|
+
const stats = await this.stat(path, rootCred);
|
|
168
|
+
this._sync.mkdirSync(path, stats.mode, stats.cred());
|
|
169
|
+
}
|
|
170
|
+
const files = await this.readdir(path, rootCred);
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
await this.crossCopy(join(path, file));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
177
|
+
try {
|
|
178
|
+
const asyncFile = __addDisposableResource(env_1, await this.openFile(path, parseFlag('r'), rootCred), true);
|
|
179
|
+
const syncFile = __addDisposableResource(env_1, this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred()), false);
|
|
180
|
+
const buffer = new Uint8Array(stats.size);
|
|
181
|
+
await asyncFile.read(buffer);
|
|
182
|
+
syncFile.writeSync(buffer, 0, stats.size);
|
|
183
|
+
}
|
|
184
|
+
catch (e_1) {
|
|
185
|
+
env_1.error = e_1;
|
|
186
|
+
env_1.hasError = true;
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
const result_1 = __disposeResources(env_1);
|
|
190
|
+
if (result_1)
|
|
191
|
+
await result_1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
async _next() {
|
|
199
|
+
if (!this._queueRunning) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const [method, ...args] = this._queue.shift();
|
|
203
|
+
// @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
|
|
204
|
+
await this[method](...args);
|
|
205
|
+
await this._next();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* @internal
|
|
209
|
+
*/
|
|
210
|
+
queue(...op) {
|
|
211
|
+
this._queue.push(op);
|
|
212
|
+
void this._next();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return AsyncFS;
|
|
216
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FileSystem } from '../filesystem.js';
|
|
2
|
+
import '../polyfills.js';
|
|
3
|
+
import type { Mixin } from './shared.js';
|
|
4
|
+
export declare class MutexLock {
|
|
5
|
+
readonly path: string;
|
|
6
|
+
protected readonly previous?: MutexLock | undefined;
|
|
7
|
+
protected current: PromiseWithResolvers<void>;
|
|
8
|
+
protected _isLocked: boolean;
|
|
9
|
+
get isLocked(): boolean;
|
|
10
|
+
constructor(path: string, previous?: MutexLock | undefined);
|
|
11
|
+
done(): Promise<void>;
|
|
12
|
+
unlock(): void;
|
|
13
|
+
[Symbol.dispose](): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* This serializes access to an underlying async filesystem.
|
|
17
|
+
* For example, on an OverlayFS instance with an async lower
|
|
18
|
+
* directory operations like rename and rmdir may involve multiple
|
|
19
|
+
* requests involving both the upper and lower filesystems -- they
|
|
20
|
+
* are not executed in a single atomic step. OverlayFS uses this
|
|
21
|
+
* to avoid having to reason about the correctness of
|
|
22
|
+
* multiple requests interleaving.
|
|
23
|
+
*
|
|
24
|
+
* Note: `@ts-expect-error 2513` is needed because `FS` is not properly detected as being concrete
|
|
25
|
+
*
|
|
26
|
+
* @todo Change `using _` to `using void` pending https://github.com/tc39/proposal-discard-binding
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export declare function Mutexed<T extends new (...args: any[]) => FileSystem>(FS: T): Mixin<T, {
|
|
30
|
+
lock(path: string): Promise<MutexLock>;
|
|
31
|
+
lockSync(path: string): MutexLock;
|
|
32
|
+
isLocked(path: string): boolean;
|
|
33
|
+
}>;
|