@zenfs/core 1.3.6 → 1.4.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/memory.d.ts +4 -4
- package/dist/backends/memory.js +4 -4
- package/dist/backends/overlay.d.ts +5 -2
- package/dist/backends/overlay.js +7 -10
- package/dist/backends/port/fs.js +1 -4
- package/dist/config.js +4 -8
- package/dist/context.d.ts +32 -0
- package/dist/context.js +23 -0
- package/dist/credentials.d.ts +5 -5
- package/dist/credentials.js +10 -6
- package/dist/emulation/async.d.ts +90 -89
- package/dist/emulation/async.js +76 -75
- package/dist/emulation/dir.d.ts +3 -1
- package/dist/emulation/dir.js +6 -7
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/promises.d.ts +50 -48
- package/dist/emulation/promises.js +78 -77
- package/dist/emulation/shared.d.ts +35 -8
- package/dist/emulation/shared.js +37 -11
- package/dist/emulation/sync.d.ts +63 -62
- package/dist/emulation/sync.js +72 -73
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/stats.d.ts +2 -1
- package/dist/stats.js +5 -4
- package/package.json +3 -5
- package/scripts/test.js +78 -17
- package/tests/assignment.ts +1 -1
- package/tests/common/context.test.ts +19 -0
- package/tests/{devices.test.ts → common/devices.test.ts} +3 -3
- package/tests/{handle.test.ts → common/handle.test.ts} +1 -1
- package/tests/common/mounts.test.ts +36 -0
- package/tests/{mutex.test.ts → common/mutex.test.ts} +3 -3
- package/tests/common/path.test.ts +34 -0
- package/tests/common.ts +4 -3
- package/tests/fs/dir.test.ts +11 -11
- package/tests/fs/directory.test.ts +17 -17
- package/tests/fs/errors.test.ts +29 -39
- package/tests/fs/watch.test.ts +2 -2
- package/tests/setup/context.ts +9 -0
- package/tests/setup/cow+fetch.ts +1 -1
- package/tests/setup/memory.ts +1 -1
- package/tests/{setup/common.ts → setup.ts} +6 -5
- package/src/backends/backend.ts +0 -161
- package/src/backends/fetch.ts +0 -180
- package/src/backends/file_index.ts +0 -206
- package/src/backends/memory.ts +0 -45
- package/src/backends/overlay.ts +0 -560
- package/src/backends/port/fs.ts +0 -329
- package/src/backends/port/readme.md +0 -54
- package/src/backends/port/rpc.ts +0 -167
- package/src/backends/readme.md +0 -3
- package/src/backends/store/fs.ts +0 -667
- package/src/backends/store/readme.md +0 -9
- package/src/backends/store/simple.ts +0 -154
- package/src/backends/store/store.ts +0 -189
- package/src/config.ts +0 -227
- package/src/credentials.ts +0 -49
- package/src/devices.ts +0 -521
- package/src/emulation/async.ts +0 -834
- package/src/emulation/cache.ts +0 -86
- package/src/emulation/config.ts +0 -21
- package/src/emulation/constants.ts +0 -182
- package/src/emulation/dir.ts +0 -138
- package/src/emulation/index.ts +0 -8
- package/src/emulation/path.ts +0 -440
- package/src/emulation/promises.ts +0 -1140
- package/src/emulation/shared.ts +0 -172
- package/src/emulation/streams.ts +0 -34
- package/src/emulation/sync.ts +0 -863
- package/src/emulation/watchers.ts +0 -194
- package/src/error.ts +0 -307
- package/src/file.ts +0 -631
- package/src/filesystem.ts +0 -174
- package/src/index.ts +0 -35
- package/src/inode.ts +0 -128
- package/src/mixins/async.ts +0 -230
- package/src/mixins/index.ts +0 -5
- package/src/mixins/mutexed.ts +0 -257
- package/src/mixins/readonly.ts +0 -96
- package/src/mixins/shared.ts +0 -25
- package/src/mixins/sync.ts +0 -58
- package/src/polyfills.ts +0 -21
- package/src/stats.ts +0 -405
- package/src/utils.ts +0 -276
- package/tests/mounts.test.ts +0 -18
- package/tests/path.test.ts +0 -34
package/src/filesystem.ts
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import type { ErrnoError } from './error.js';
|
|
2
|
-
import type { File } from './file.js';
|
|
3
|
-
import { ZenFsType, type Stats } from './stats.js';
|
|
4
|
-
|
|
5
|
-
export type FileContents = ArrayBufferView | string;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Metadata about a FileSystem
|
|
9
|
-
*/
|
|
10
|
-
export interface FileSystemMetadata {
|
|
11
|
-
/**
|
|
12
|
-
* The name of the FS
|
|
13
|
-
*/
|
|
14
|
-
name: string;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Whether the FS is readonly or not
|
|
18
|
-
*/
|
|
19
|
-
readonly: boolean;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* The total space
|
|
23
|
-
*/
|
|
24
|
-
totalSpace: number;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* The available space
|
|
28
|
-
*/
|
|
29
|
-
freeSpace: number;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* If set, disables File from using a resizable array buffer.
|
|
33
|
-
* @default false
|
|
34
|
-
*/
|
|
35
|
-
noResizableBuffers: boolean;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* If set, disables caching on async file systems.
|
|
39
|
-
* This means *sync operations will not work*.
|
|
40
|
-
* It has no affect on sync file systems.
|
|
41
|
-
* @default false
|
|
42
|
-
*/
|
|
43
|
-
noAsyncCache: boolean;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The optimal block size to use with the file system
|
|
47
|
-
* @default 4096
|
|
48
|
-
*/
|
|
49
|
-
blockSize?: number;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Total number of (file) nodes available
|
|
53
|
-
*/
|
|
54
|
-
totalNodes?: number;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Number of free (file) nodes available
|
|
58
|
-
*/
|
|
59
|
-
freeNodes?: number;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The type of the FS
|
|
63
|
-
*/
|
|
64
|
-
type: number;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Provides a consistent and easy to use internal API.
|
|
69
|
-
* Default implementations for `exists` and `existsSync` are included.
|
|
70
|
-
* If you are extending this class, note that every path is an absolute path and all arguments are present.
|
|
71
|
-
* @internal
|
|
72
|
-
*/
|
|
73
|
-
export abstract class FileSystem {
|
|
74
|
-
/**
|
|
75
|
-
* Get metadata about the current file system
|
|
76
|
-
*/
|
|
77
|
-
public metadata(): FileSystemMetadata {
|
|
78
|
-
return {
|
|
79
|
-
name: this.constructor.name.toLowerCase(),
|
|
80
|
-
readonly: false,
|
|
81
|
-
totalSpace: 0,
|
|
82
|
-
freeSpace: 0,
|
|
83
|
-
noResizableBuffers: false,
|
|
84
|
-
noAsyncCache: this._disableSync ?? false,
|
|
85
|
-
type: ZenFsType,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Whether the sync cache should be disabled.
|
|
91
|
-
* Only affects async things.
|
|
92
|
-
* @internal @protected
|
|
93
|
-
*/
|
|
94
|
-
_disableSync?: boolean;
|
|
95
|
-
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
97
|
-
public constructor(...args: any[]) {}
|
|
98
|
-
|
|
99
|
-
public async ready(): Promise<void> {}
|
|
100
|
-
|
|
101
|
-
public abstract rename(oldPath: string, newPath: string): Promise<void>;
|
|
102
|
-
public abstract renameSync(oldPath: string, newPath: string): void;
|
|
103
|
-
|
|
104
|
-
public abstract stat(path: string): Promise<Stats>;
|
|
105
|
-
public abstract statSync(path: string): Stats;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Opens the file at `path` with `flag`. The file must exist.
|
|
109
|
-
* @param path The path to open.
|
|
110
|
-
* @param flag The flag to use when opening the file.
|
|
111
|
-
*/
|
|
112
|
-
public abstract openFile(path: string, flag: string): Promise<File>;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Opens the file at `path` with `flag`. The file must exist.
|
|
116
|
-
* @param path The path to open.
|
|
117
|
-
* @param flag The flag to use when opening the file.
|
|
118
|
-
*/
|
|
119
|
-
public abstract openFileSync(path: string, flag: string): File;
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Create the file at `path` with `mode`. Then, open it with `flag`.
|
|
123
|
-
*/
|
|
124
|
-
public abstract createFile(path: string, flag: string, mode: number): Promise<File>;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Create the file at `path` with `mode`. Then, open it with `flag`.
|
|
128
|
-
*/
|
|
129
|
-
public abstract createFileSync(path: string, flag: string, mode: number): File;
|
|
130
|
-
|
|
131
|
-
public abstract unlink(path: string): Promise<void>;
|
|
132
|
-
public abstract unlinkSync(path: string): void;
|
|
133
|
-
|
|
134
|
-
// Directory operations
|
|
135
|
-
|
|
136
|
-
public abstract rmdir(path: string): Promise<void>;
|
|
137
|
-
public abstract rmdirSync(path: string): void;
|
|
138
|
-
|
|
139
|
-
public abstract mkdir(path: string, mode: number): Promise<void>;
|
|
140
|
-
public abstract mkdirSync(path: string, mode: number): void;
|
|
141
|
-
|
|
142
|
-
public abstract readdir(path: string): Promise<string[]>;
|
|
143
|
-
public abstract readdirSync(path: string): string[];
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Test whether or not `path` exists.
|
|
147
|
-
*/
|
|
148
|
-
public async exists(path: string): Promise<boolean> {
|
|
149
|
-
try {
|
|
150
|
-
await this.stat(path);
|
|
151
|
-
return true;
|
|
152
|
-
} catch (e) {
|
|
153
|
-
return (e as ErrnoError).code != 'ENOENT';
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Test whether or not `path` exists.
|
|
159
|
-
*/
|
|
160
|
-
public existsSync(path: string): boolean {
|
|
161
|
-
try {
|
|
162
|
-
this.statSync(path);
|
|
163
|
-
return true;
|
|
164
|
-
} catch (e) {
|
|
165
|
-
return (e as ErrnoError).code != 'ENOENT';
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
public abstract link(target: string, link: string): Promise<void>;
|
|
170
|
-
public abstract linkSync(target: string, link: string): void;
|
|
171
|
-
|
|
172
|
-
public abstract sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
173
|
-
public abstract syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
174
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export * from './error.js';
|
|
2
|
-
export * from './backends/port/fs.js';
|
|
3
|
-
export * from './backends/fetch.js';
|
|
4
|
-
export * from './backends/memory.js';
|
|
5
|
-
export * from './backends/file_index.js';
|
|
6
|
-
export * from './backends/overlay.js';
|
|
7
|
-
export * from './backends/store/fs.js';
|
|
8
|
-
export * from './backends/store/simple.js';
|
|
9
|
-
export * from './backends/store/store.js';
|
|
10
|
-
export * from './backends/backend.js';
|
|
11
|
-
export * from './config.js';
|
|
12
|
-
export * from './credentials.js';
|
|
13
|
-
export * from './devices.js';
|
|
14
|
-
export { default as devices } from './devices.js';
|
|
15
|
-
export * from './file.js';
|
|
16
|
-
export * from './filesystem.js';
|
|
17
|
-
export * from './inode.js';
|
|
18
|
-
export * from './mixins/index.js';
|
|
19
|
-
export * from './stats.js';
|
|
20
|
-
export * from './utils.js';
|
|
21
|
-
|
|
22
|
-
export * from './emulation/index.js';
|
|
23
|
-
import * as fs from './emulation/index.js';
|
|
24
|
-
export { fs };
|
|
25
|
-
export default fs;
|
|
26
|
-
|
|
27
|
-
declare global {
|
|
28
|
-
/**
|
|
29
|
-
* Global FS emulation. Do not use unless absolutely needed.
|
|
30
|
-
* @hidden
|
|
31
|
-
*/
|
|
32
|
-
// eslint-disable-next-line no-var
|
|
33
|
-
var __zenfs__: typeof fs;
|
|
34
|
-
}
|
|
35
|
-
globalThis.__zenfs__ = fs;
|
package/src/inode.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { deserialize, sizeof, struct, types as t } from 'utilium';
|
|
2
|
-
import { Stats, type StatsLike } from './stats.js';
|
|
3
|
-
import { randomBigInt } from './utils.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Room inode
|
|
7
|
-
* @hidden
|
|
8
|
-
*/
|
|
9
|
-
export const rootIno = 0n;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generic inode definition that can easily be serialized.
|
|
13
|
-
* @internal
|
|
14
|
-
* @todo [BREAKING]
|
|
15
|
-
*/
|
|
16
|
-
@struct()
|
|
17
|
-
export class Inode implements StatsLike {
|
|
18
|
-
public constructor(buffer?: ArrayBufferLike | ArrayBufferView) {
|
|
19
|
-
if (buffer) {
|
|
20
|
-
const sz_inode = sizeof(Inode);
|
|
21
|
-
const oldSize = sz_inode - sizeof('uint64');
|
|
22
|
-
if (buffer.byteLength < oldSize) {
|
|
23
|
-
throw new RangeError(`Can not create an inode from a buffer less than ${oldSize} bytes`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Expand the buffer so it is the right size
|
|
27
|
-
if (buffer.byteLength < sz_inode) {
|
|
28
|
-
const newBuffer = new Uint8Array(sz_inode);
|
|
29
|
-
// Fill the new buffer with current data
|
|
30
|
-
newBuffer.set(new Uint8Array(ArrayBuffer.isView(buffer) ? buffer.buffer : buffer));
|
|
31
|
-
/* Add a random ino.
|
|
32
|
-
This will be different from the actual one,
|
|
33
|
-
but `ino` isn't used anywhere so it should be fine.
|
|
34
|
-
*/
|
|
35
|
-
const randomIno = crypto.getRandomValues(new Uint32Array(2));
|
|
36
|
-
newBuffer.set(randomIno, sz_inode - 2);
|
|
37
|
-
buffer = newBuffer;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
deserialize(this, buffer);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// set defaults on a fresh inode
|
|
45
|
-
this.ino = randomBigInt();
|
|
46
|
-
this.data = randomBigInt();
|
|
47
|
-
this.nlink = 1;
|
|
48
|
-
this.size = 4096;
|
|
49
|
-
const now = Date.now();
|
|
50
|
-
this.atimeMs = now;
|
|
51
|
-
this.mtimeMs = now;
|
|
52
|
-
this.ctimeMs = now;
|
|
53
|
-
this.birthtimeMs = now;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@t.uint64 public data!: bigint;
|
|
57
|
-
@t.uint32 public size!: number;
|
|
58
|
-
@t.uint16 public mode!: number;
|
|
59
|
-
@t.uint32 public nlink!: number;
|
|
60
|
-
@t.uint32 public uid!: number;
|
|
61
|
-
@t.uint32 public gid!: number;
|
|
62
|
-
@t.float64 public atimeMs!: number;
|
|
63
|
-
@t.float64 public birthtimeMs!: number;
|
|
64
|
-
@t.float64 public mtimeMs!: number;
|
|
65
|
-
@t.float64 public ctimeMs!: number;
|
|
66
|
-
@t.uint64 public ino!: bigint;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Handy function that converts the Inode to a Node Stats object.
|
|
70
|
-
*/
|
|
71
|
-
public toStats(): Stats {
|
|
72
|
-
return new Stats(this);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Updates the Inode using information from the stats object. Used by file
|
|
77
|
-
* systems at sync time, e.g.:
|
|
78
|
-
* - Program opens file and gets a File object.
|
|
79
|
-
* - Program mutates file. File object is responsible for maintaining
|
|
80
|
-
* metadata changes locally -- typically in a Stats object.
|
|
81
|
-
* - Program closes file. File object's metadata changes are synced with the
|
|
82
|
-
* file system.
|
|
83
|
-
* @return True if any changes have occurred.
|
|
84
|
-
*/
|
|
85
|
-
public update(stats: Readonly<Stats>): boolean {
|
|
86
|
-
let hasChanged = false;
|
|
87
|
-
if (this.size !== stats.size) {
|
|
88
|
-
this.size = stats.size;
|
|
89
|
-
hasChanged = true;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (this.mode !== stats.mode) {
|
|
93
|
-
this.mode = stats.mode;
|
|
94
|
-
hasChanged = true;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (this.nlink !== stats.nlink) {
|
|
98
|
-
this.nlink = stats.nlink;
|
|
99
|
-
hasChanged = true;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (this.uid !== stats.uid) {
|
|
103
|
-
this.uid = stats.uid;
|
|
104
|
-
hasChanged = true;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (this.gid !== stats.gid) {
|
|
108
|
-
this.gid = stats.gid;
|
|
109
|
-
hasChanged = true;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (this.atimeMs !== stats.atimeMs) {
|
|
113
|
-
this.atimeMs = stats.atimeMs;
|
|
114
|
-
hasChanged = true;
|
|
115
|
-
}
|
|
116
|
-
if (this.mtimeMs !== stats.mtimeMs) {
|
|
117
|
-
this.mtimeMs = stats.mtimeMs;
|
|
118
|
-
hasChanged = true;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (this.ctimeMs !== stats.ctimeMs) {
|
|
122
|
-
this.ctimeMs = stats.ctimeMs;
|
|
123
|
-
hasChanged = true;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return hasChanged;
|
|
127
|
-
}
|
|
128
|
-
}
|
package/src/mixins/async.ts
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { StoreFS } from '../backends/store/fs.js';
|
|
2
|
-
import type { Store } from '../backends/store/store.js';
|
|
3
|
-
import { join } from '../emulation/path.js';
|
|
4
|
-
import { Errno, ErrnoError } from '../error.js';
|
|
5
|
-
import { parseFlag, PreloadFile, type File } from '../file.js';
|
|
6
|
-
import type { FileSystem } from '../filesystem.js';
|
|
7
|
-
import type { Stats } from '../stats.js';
|
|
8
|
-
import type { AsyncFSMethods, Mixin } from './shared.js';
|
|
9
|
-
|
|
10
|
-
/** @internal */
|
|
11
|
-
export type AsyncOperation = {
|
|
12
|
-
[K in keyof AsyncFSMethods]: [K, ...Parameters<FileSystem[K]>];
|
|
13
|
-
}[keyof AsyncFSMethods];
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @internal
|
|
17
|
-
*/
|
|
18
|
-
export interface Async {
|
|
19
|
-
/**
|
|
20
|
-
* @internal @protected
|
|
21
|
-
*/
|
|
22
|
-
_sync?: FileSystem;
|
|
23
|
-
queueDone(): Promise<void>;
|
|
24
|
-
ready(): Promise<void>;
|
|
25
|
-
renameSync(oldPath: string, newPath: string): void;
|
|
26
|
-
statSync(path: string): Stats;
|
|
27
|
-
createFileSync(path: string, flag: string, mode: number): File;
|
|
28
|
-
openFileSync(path: string, flag: string): File;
|
|
29
|
-
unlinkSync(path: string): void;
|
|
30
|
-
rmdirSync(path: string): void;
|
|
31
|
-
mkdirSync(path: string, mode: number): void;
|
|
32
|
-
readdirSync(path: string): string[];
|
|
33
|
-
linkSync(srcpath: string, dstpath: string): void;
|
|
34
|
-
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Async() implements synchronous methods on an asynchronous file system
|
|
39
|
-
*
|
|
40
|
-
* Implementing classes must define `_sync` for the synchronous file system used as a cache.
|
|
41
|
-
*
|
|
42
|
-
* Synchronous methods on an asynchronous FS are implemented by performing operations over the in-memory copy,
|
|
43
|
-
* while asynchronously pipelining them to the backing store.
|
|
44
|
-
* During loading, the contents of the async file system are preloaded into the synchronous store.
|
|
45
|
-
*
|
|
46
|
-
*/
|
|
47
|
-
export function Async<const T extends typeof FileSystem>(FS: T): Mixin<T, Async> {
|
|
48
|
-
abstract class AsyncFS extends FS {
|
|
49
|
-
/**
|
|
50
|
-
* Queue of pending asynchronous operations.
|
|
51
|
-
*/
|
|
52
|
-
private _queue: AsyncOperation[] = [];
|
|
53
|
-
private get _queueRunning(): boolean {
|
|
54
|
-
return !!this._queue.length;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public queueDone(): Promise<void> {
|
|
58
|
-
return new Promise(resolve => {
|
|
59
|
-
const check = (): unknown => (this._queueRunning ? setTimeout(check) : resolve());
|
|
60
|
-
check();
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private _isInitialized: boolean = false;
|
|
65
|
-
|
|
66
|
-
abstract _sync?: FileSystem;
|
|
67
|
-
|
|
68
|
-
public async ready(): Promise<void> {
|
|
69
|
-
await super.ready();
|
|
70
|
-
await this.queueDone();
|
|
71
|
-
if (this._isInitialized || this._disableSync) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
this.checkSync();
|
|
75
|
-
|
|
76
|
-
await this._sync.ready();
|
|
77
|
-
|
|
78
|
-
// optimization: for 2 storeFS', we copy at a lower abstraction level.
|
|
79
|
-
if (this._sync instanceof StoreFS && this instanceof StoreFS) {
|
|
80
|
-
const sync = (this._sync as StoreFS<Store>)['store'].transaction();
|
|
81
|
-
const async = (this as StoreFS<Store>)['store'].transaction();
|
|
82
|
-
|
|
83
|
-
const promises = [];
|
|
84
|
-
for (const key of await async.keys()) {
|
|
85
|
-
promises.push(async.get(key).then(data => sync.setSync(key, data)));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
await Promise.all(promises);
|
|
89
|
-
|
|
90
|
-
this._isInitialized = true;
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
await this.crossCopy('/');
|
|
96
|
-
this._isInitialized = true;
|
|
97
|
-
} catch (e) {
|
|
98
|
-
this._isInitialized = false;
|
|
99
|
-
throw e;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
protected checkSync(path?: string, syscall?: string): asserts this is { _sync: FileSystem } {
|
|
104
|
-
if (this._disableSync) {
|
|
105
|
-
throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
|
|
106
|
-
}
|
|
107
|
-
if (!this._sync) {
|
|
108
|
-
throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
public renameSync(oldPath: string, newPath: string): void {
|
|
113
|
-
this.checkSync(oldPath, 'rename');
|
|
114
|
-
this._sync.renameSync(oldPath, newPath);
|
|
115
|
-
this.queue('rename', oldPath, newPath);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
public statSync(path: string): Stats {
|
|
119
|
-
this.checkSync(path, 'stat');
|
|
120
|
-
return this._sync.statSync(path);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
public createFileSync(path: string, flag: string, mode: number): PreloadFile<this> {
|
|
124
|
-
this.checkSync(path, 'createFile');
|
|
125
|
-
this._sync.createFileSync(path, flag, mode);
|
|
126
|
-
this.queue('createFile', path, flag, mode);
|
|
127
|
-
return this.openFileSync(path, flag);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public openFileSync(path: string, flag: string): PreloadFile<this> {
|
|
131
|
-
this.checkSync(path, 'openFile');
|
|
132
|
-
const file = this._sync.openFileSync(path, flag + '+');
|
|
133
|
-
const stats = file.statSync();
|
|
134
|
-
const buffer = new Uint8Array(stats.size);
|
|
135
|
-
file.readSync(buffer);
|
|
136
|
-
return new PreloadFile(this, path, flag, stats, buffer);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
public unlinkSync(path: string): void {
|
|
140
|
-
this.checkSync(path, 'unlinkSync');
|
|
141
|
-
this._sync.unlinkSync(path);
|
|
142
|
-
this.queue('unlink', path);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
public rmdirSync(path: string): void {
|
|
146
|
-
this.checkSync(path, 'rmdir');
|
|
147
|
-
this._sync.rmdirSync(path);
|
|
148
|
-
this.queue('rmdir', path);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
public mkdirSync(path: string, mode: number): void {
|
|
152
|
-
this.checkSync(path, 'mkdir');
|
|
153
|
-
this._sync.mkdirSync(path, mode);
|
|
154
|
-
this.queue('mkdir', path, mode);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public readdirSync(path: string): string[] {
|
|
158
|
-
this.checkSync(path, 'readdir');
|
|
159
|
-
return this._sync.readdirSync(path);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
public linkSync(srcpath: string, dstpath: string): void {
|
|
163
|
-
this.checkSync(srcpath, 'link');
|
|
164
|
-
this._sync.linkSync(srcpath, dstpath);
|
|
165
|
-
this.queue('link', srcpath, dstpath);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
|
|
169
|
-
this.checkSync(path, 'sync');
|
|
170
|
-
this._sync.syncSync(path, data, stats);
|
|
171
|
-
this.queue('sync', path, data, stats);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
public existsSync(path: string): boolean {
|
|
175
|
-
this.checkSync(path, 'exists');
|
|
176
|
-
return this._sync.existsSync(path);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* @internal
|
|
181
|
-
*/
|
|
182
|
-
protected async crossCopy(path: string): Promise<void> {
|
|
183
|
-
this.checkSync(path, 'crossCopy');
|
|
184
|
-
const stats = await this.stat(path);
|
|
185
|
-
if (!stats.isDirectory()) {
|
|
186
|
-
await using asyncFile = await this.openFile(path, parseFlag('r'));
|
|
187
|
-
using syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode);
|
|
188
|
-
const buffer = new Uint8Array(stats.size);
|
|
189
|
-
await asyncFile.read(buffer);
|
|
190
|
-
syncFile.writeSync(buffer, 0, stats.size);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
if (path !== '/') {
|
|
194
|
-
const stats = await this.stat(path);
|
|
195
|
-
this._sync.mkdirSync(path, stats.mode);
|
|
196
|
-
}
|
|
197
|
-
const promises = [];
|
|
198
|
-
for (const file of await this.readdir(path)) {
|
|
199
|
-
promises.push(this.crossCopy(join(path, file)));
|
|
200
|
-
}
|
|
201
|
-
await Promise.all(promises);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* @internal
|
|
206
|
-
*/
|
|
207
|
-
private async _next(): Promise<void> {
|
|
208
|
-
if (!this._queueRunning) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const [method, ...args] = this._queue.shift()!;
|
|
213
|
-
// @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
|
|
214
|
-
await this[method](...args);
|
|
215
|
-
await this._next();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @internal
|
|
220
|
-
*/
|
|
221
|
-
private queue(...op: AsyncOperation) {
|
|
222
|
-
this._queue.push(op);
|
|
223
|
-
void this._next();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return AsyncFS;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function asyncPatch<T extends typeof FileSystem>(fs: Mixin<T, Async>) {}
|