@zenfs/core 1.7.2 → 1.8.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.js +3 -4
- package/dist/backends/fetch.d.ts +17 -18
- package/dist/backends/fetch.js +95 -58
- package/dist/backends/index.d.ts +2 -1
- package/dist/backends/index.js +2 -1
- package/dist/backends/memory.d.ts +1 -1
- package/dist/backends/overlay.d.ts +8 -14
- package/dist/backends/overlay.js +38 -31
- package/dist/backends/passthrough.d.ts +8 -3
- package/dist/backends/passthrough.js +148 -4
- package/dist/backends/port/fs.d.ts +15 -49
- package/dist/backends/port/fs.js +28 -116
- package/dist/backends/port/rpc.d.ts +13 -6
- package/dist/backends/port/rpc.js +9 -7
- package/dist/backends/store/file_index.d.ts +38 -0
- package/dist/backends/store/file_index.js +76 -0
- package/dist/backends/store/fs.d.ts +39 -34
- package/dist/backends/store/fs.js +407 -238
- package/dist/backends/store/index_fs.d.ts +34 -0
- package/dist/backends/store/index_fs.js +67 -0
- package/dist/backends/store/inode.d.ts +26 -8
- package/dist/backends/store/inode.js +92 -91
- package/dist/backends/store/simple.d.ts +20 -20
- package/dist/backends/store/simple.js +3 -4
- package/dist/backends/store/store.d.ts +12 -12
- package/dist/backends/store/store.js +4 -6
- package/dist/devices.d.ts +44 -21
- package/dist/devices.js +110 -55
- package/dist/file.d.ts +111 -7
- package/dist/file.js +324 -92
- package/dist/filesystem.d.ts +44 -4
- package/dist/mixins/async.js +12 -6
- package/dist/mixins/mutexed.d.ts +8 -3
- package/dist/mixins/mutexed.js +57 -1
- package/dist/mixins/readonly.d.ts +17 -16
- package/dist/mixins/readonly.js +6 -0
- package/dist/mixins/sync.d.ts +1 -1
- package/dist/stats.d.ts +12 -6
- package/dist/stats.js +14 -6
- package/dist/utils.d.ts +23 -3
- package/dist/utils.js +58 -10
- package/dist/vfs/async.js +1 -1
- package/dist/vfs/constants.d.ts +2 -2
- package/dist/vfs/constants.js +2 -2
- package/dist/vfs/dir.js +3 -1
- package/dist/vfs/index.js +4 -1
- package/dist/vfs/promises.js +33 -13
- package/dist/vfs/shared.js +2 -0
- package/dist/vfs/sync.js +25 -13
- package/dist/vfs/types.d.ts +15 -0
- package/eslint.shared.js +1 -0
- package/package.json +2 -3
- package/readme.md +2 -2
- package/scripts/test.js +73 -11
- package/tests/common/mutex.test.ts +1 -1
- package/tests/fetch/run.sh +16 -0
- package/tests/fetch/server.ts +49 -0
- package/tests/fetch/setup.ts +13 -0
- package/tests/fs/read.test.ts +10 -10
- package/tests/fs/times.test.ts +2 -2
- package/tests/fs/write.test.ts +6 -11
- package/tests/setup/index.ts +38 -0
- package/tests/setup/port.ts +15 -0
- package/dist/backends/file_index.d.ts +0 -63
- package/dist/backends/file_index.js +0 -163
- package/tests/common/async.test.ts +0 -31
- package/tests/setup/cow+fetch.ts +0 -45
- /package/tests/fs/{appendFile.test.ts → append.test.ts} +0 -0
package/dist/devices.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Inode } from './backends/index.js';
|
|
2
2
|
import { InMemoryStore } from './backends/memory.js';
|
|
3
3
|
import { StoreFS } from './backends/store/fs.js';
|
|
4
|
+
import type { FileReadResult } from './file.js';
|
|
4
5
|
import { File } from './file.js';
|
|
5
|
-
import type {
|
|
6
|
+
import type { CreationOptions } from './filesystem.js';
|
|
6
7
|
import { Stats } from './stats.js';
|
|
7
8
|
/**
|
|
8
9
|
* A device
|
|
@@ -14,11 +15,11 @@ export interface Device<TData = any> {
|
|
|
14
15
|
/**
|
|
15
16
|
* The device's driver
|
|
16
17
|
*/
|
|
17
|
-
driver: DeviceDriver
|
|
18
|
+
driver: DeviceDriver<TData>;
|
|
18
19
|
/**
|
|
19
20
|
* Which inode the device is assigned
|
|
20
21
|
*/
|
|
21
|
-
ino:
|
|
22
|
+
ino: number;
|
|
22
23
|
/**
|
|
23
24
|
* Data associated with a device.
|
|
24
25
|
* This is meant to be used by device drivers.
|
|
@@ -33,6 +34,12 @@ export interface Device<TData = any> {
|
|
|
33
34
|
*/
|
|
34
35
|
minor: number;
|
|
35
36
|
}
|
|
37
|
+
export interface DeviceInit<TData = any> {
|
|
38
|
+
data?: TData;
|
|
39
|
+
minor?: number;
|
|
40
|
+
major?: number;
|
|
41
|
+
name?: string;
|
|
42
|
+
}
|
|
36
43
|
/**
|
|
37
44
|
* A device driver
|
|
38
45
|
*/
|
|
@@ -55,22 +62,36 @@ export interface DeviceDriver<TData = any> {
|
|
|
55
62
|
* Initializes a new device.
|
|
56
63
|
* @returns `Device.data`
|
|
57
64
|
*/
|
|
58
|
-
init?(ino:
|
|
59
|
-
data?: TData;
|
|
60
|
-
minor?: number;
|
|
61
|
-
major?: number;
|
|
62
|
-
name?: string;
|
|
63
|
-
};
|
|
65
|
+
init?(ino: number, options: object): DeviceInit<TData>;
|
|
64
66
|
/**
|
|
65
|
-
* Synchronously read from
|
|
67
|
+
* Synchronously read from a device file
|
|
66
68
|
* @group File operations
|
|
69
|
+
* @deprecated
|
|
70
|
+
* @todo [BREAKING] Remove
|
|
67
71
|
*/
|
|
68
72
|
read(file: DeviceFile<TData>, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
|
|
69
73
|
/**
|
|
70
|
-
* Synchronously
|
|
74
|
+
* Synchronously read from a device.
|
|
75
|
+
* @privateRemarks
|
|
76
|
+
* For many devices there is no concept of an offset or end.
|
|
77
|
+
* For example, /dev/random will be "the same" regardless of where you read from- random data.
|
|
71
78
|
* @group File operations
|
|
79
|
+
* @todo [BREAKING] Rename to `read`
|
|
80
|
+
*/
|
|
81
|
+
readD(device: Device<TData>, buffer: Uint8Array, offset: number, end: number): void;
|
|
82
|
+
/**
|
|
83
|
+
* Synchronously write to a device file
|
|
84
|
+
* @group File operations
|
|
85
|
+
* @deprecated
|
|
86
|
+
* @todo [BREAKING] Remove
|
|
72
87
|
*/
|
|
73
88
|
write(file: DeviceFile<TData>, buffer: Uint8Array, offset: number, length: number, position?: number): number;
|
|
89
|
+
/**
|
|
90
|
+
* Synchronously write to a device
|
|
91
|
+
* @group File operations
|
|
92
|
+
* @todo [BREAKING] Rename to `write`
|
|
93
|
+
*/
|
|
94
|
+
writeD(device: Device<TData>, buffer: Uint8Array, offset: number): void;
|
|
74
95
|
/**
|
|
75
96
|
* Sync the device
|
|
76
97
|
* @group File operations
|
|
@@ -94,11 +115,11 @@ export declare class DeviceFile<TData = any> extends File {
|
|
|
94
115
|
position: number;
|
|
95
116
|
constructor(fs: DeviceFS, path: string, device: Device<TData>);
|
|
96
117
|
get driver(): DeviceDriver<TData>;
|
|
97
|
-
protected
|
|
118
|
+
protected stats: Inode;
|
|
98
119
|
stat(): Promise<Stats>;
|
|
99
120
|
statSync(): Stats;
|
|
100
121
|
readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
|
|
101
|
-
read<TBuffer extends
|
|
122
|
+
read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number): Promise<FileReadResult<TBuffer>>;
|
|
102
123
|
writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
|
|
103
124
|
write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>;
|
|
104
125
|
truncate(length: number): Promise<void>;
|
|
@@ -113,8 +134,6 @@ export declare class DeviceFile<TData = any> extends File {
|
|
|
113
134
|
chmodSync(): void;
|
|
114
135
|
utimes(): Promise<void>;
|
|
115
136
|
utimesSync(): void;
|
|
116
|
-
_setType(): Promise<void>;
|
|
117
|
-
_setTypeSync(): void;
|
|
118
137
|
}
|
|
119
138
|
/**
|
|
120
139
|
* A temporary file system that manages and interfaces with devices
|
|
@@ -142,20 +161,24 @@ export declare class DeviceFS extends StoreFS<InMemoryStore> {
|
|
|
142
161
|
statSync(path: string): Stats;
|
|
143
162
|
openFile(path: string, flag: string): Promise<File>;
|
|
144
163
|
openFileSync(path: string, flag: string): File;
|
|
145
|
-
createFile(path: string, flag: string, mode: number): Promise<File>;
|
|
146
|
-
createFileSync(path: string, flag: string, mode: number): File;
|
|
164
|
+
createFile(path: string, flag: string, mode: number, options: CreationOptions): Promise<File>;
|
|
165
|
+
createFileSync(path: string, flag: string, mode: number, options: CreationOptions): File;
|
|
147
166
|
unlink(path: string): Promise<void>;
|
|
148
167
|
unlinkSync(path: string): void;
|
|
149
168
|
rmdir(path: string): Promise<void>;
|
|
150
169
|
rmdirSync(path: string): void;
|
|
151
|
-
mkdir(path: string, mode: number): Promise<void>;
|
|
152
|
-
mkdirSync(path: string, mode: number): void;
|
|
170
|
+
mkdir(path: string, mode: number, options: CreationOptions): Promise<void>;
|
|
171
|
+
mkdirSync(path: string, mode: number, options: CreationOptions): void;
|
|
153
172
|
readdir(path: string): Promise<string[]>;
|
|
154
173
|
readdirSync(path: string): string[];
|
|
155
174
|
link(target: string, link: string): Promise<void>;
|
|
156
175
|
linkSync(target: string, link: string): void;
|
|
157
176
|
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
158
177
|
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
178
|
+
read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
|
|
179
|
+
readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
|
|
180
|
+
write(path: string, data: Uint8Array, offset: number): Promise<void>;
|
|
181
|
+
writeSync(path: string, data: Uint8Array, offset: number): void;
|
|
159
182
|
}
|
|
160
183
|
/**
|
|
161
184
|
* Simulates the `/dev/null` device.
|
|
@@ -198,6 +221,6 @@ export declare const devices: {
|
|
|
198
221
|
full: DeviceDriver<any>;
|
|
199
222
|
random: DeviceDriver<any>;
|
|
200
223
|
console: DeviceDriver<{
|
|
201
|
-
output: (text: string) => unknown;
|
|
224
|
+
output: (text: string, offset: number) => unknown;
|
|
202
225
|
}>;
|
|
203
226
|
};
|
package/dist/devices.js
CHANGED
|
@@ -53,12 +53,13 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
53
53
|
var e = new Error(message);
|
|
54
54
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
55
55
|
});
|
|
56
|
+
import { Inode } from './backends/index.js';
|
|
56
57
|
import { InMemoryStore } from './backends/memory.js';
|
|
57
58
|
import { StoreFS } from './backends/store/fs.js';
|
|
58
59
|
import { Errno, ErrnoError } from './error.js';
|
|
59
60
|
import { File } from './file.js';
|
|
60
61
|
import { Stats } from './stats.js';
|
|
61
|
-
import { decodeUTF8 } from './utils.js';
|
|
62
|
+
import { canary, decodeUTF8 } from './utils.js';
|
|
62
63
|
import { S_IFBLK, S_IFCHR } from './vfs/constants.js';
|
|
63
64
|
import { basename, dirname } from './vfs/path.js';
|
|
64
65
|
/**
|
|
@@ -73,28 +74,40 @@ export class DeviceFile extends File {
|
|
|
73
74
|
this.fs = fs;
|
|
74
75
|
this.device = device;
|
|
75
76
|
this.position = 0;
|
|
77
|
+
this.stats = new Inode({
|
|
78
|
+
mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666,
|
|
79
|
+
});
|
|
76
80
|
}
|
|
77
81
|
get driver() {
|
|
78
82
|
return this.device.driver;
|
|
79
83
|
}
|
|
80
|
-
get stats() {
|
|
81
|
-
return { mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666 };
|
|
82
|
-
}
|
|
83
84
|
async stat() {
|
|
84
85
|
return Promise.resolve(new Stats(this.stats));
|
|
85
86
|
}
|
|
86
87
|
statSync() {
|
|
87
88
|
return new Stats(this.stats);
|
|
88
89
|
}
|
|
89
|
-
readSync(buffer, offset, length, position) {
|
|
90
|
-
|
|
90
|
+
readSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
|
|
91
|
+
this.stats.atimeMs = Date.now();
|
|
92
|
+
const end = position + length;
|
|
93
|
+
this.position = end;
|
|
94
|
+
const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
95
|
+
this.driver.readD(this.device, uint8.subarray(offset, length), position, end);
|
|
96
|
+
return length;
|
|
91
97
|
}
|
|
92
98
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
93
99
|
async read(buffer, offset, length) {
|
|
94
100
|
return { bytesRead: this.readSync(buffer, offset, length), buffer };
|
|
95
101
|
}
|
|
96
|
-
writeSync(buffer, offset = 0, length = buffer.
|
|
97
|
-
|
|
102
|
+
writeSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
|
|
103
|
+
const end = position + length;
|
|
104
|
+
if (end > this.stats.size)
|
|
105
|
+
this.stats.size = end;
|
|
106
|
+
this.stats.mtimeMs = Date.now();
|
|
107
|
+
this.position = end;
|
|
108
|
+
const data = buffer.subarray(offset, offset + length);
|
|
109
|
+
this.driver.writeD(this.device, data, position);
|
|
110
|
+
return length;
|
|
98
111
|
}
|
|
99
112
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
100
113
|
async write(buffer, offset, length, position) {
|
|
@@ -144,12 +157,6 @@ export class DeviceFile extends File {
|
|
|
144
157
|
utimesSync() {
|
|
145
158
|
throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
|
|
146
159
|
}
|
|
147
|
-
_setType() {
|
|
148
|
-
throw ErrnoError.With('ENOTSUP', this.path, '_setType');
|
|
149
|
-
}
|
|
150
|
-
_setTypeSync() {
|
|
151
|
-
throw ErrnoError.With('ENOTSUP', this.path, '_setType');
|
|
152
|
-
}
|
|
153
160
|
}
|
|
154
161
|
/**
|
|
155
162
|
* A temporary file system that manages and interfaces with devices
|
|
@@ -159,14 +166,17 @@ export class DeviceFS extends StoreFS {
|
|
|
159
166
|
* Creates a new device at `path` relative to the `DeviceFS` root.
|
|
160
167
|
* @deprecated
|
|
161
168
|
*/
|
|
169
|
+
/* node:coverage disable */
|
|
162
170
|
createDevice(path, driver, options = {}) {
|
|
163
171
|
var _a;
|
|
164
172
|
if (this.existsSync(path)) {
|
|
165
173
|
throw ErrnoError.With('EEXIST', path, 'mknod');
|
|
166
174
|
}
|
|
167
|
-
let ino =
|
|
175
|
+
let ino = 1;
|
|
176
|
+
const silence = canary(path, 'mknod');
|
|
168
177
|
while (this.store.has(ino))
|
|
169
178
|
ino++;
|
|
179
|
+
silence();
|
|
170
180
|
const dev = {
|
|
171
181
|
driver,
|
|
172
182
|
ino,
|
|
@@ -178,6 +188,7 @@ export class DeviceFS extends StoreFS {
|
|
|
178
188
|
this.devices.set(path, dev);
|
|
179
189
|
return dev;
|
|
180
190
|
}
|
|
191
|
+
/* node:coverage enable */
|
|
181
192
|
devicesWithDriver(driver, forceIdentity) {
|
|
182
193
|
if (forceIdentity && typeof driver == 'string') {
|
|
183
194
|
throw new ErrnoError(Errno.EINVAL, 'Can not fetch devices using only a driver name');
|
|
@@ -197,7 +208,7 @@ export class DeviceFS extends StoreFS {
|
|
|
197
208
|
*/
|
|
198
209
|
_createDevice(driver, options = {}) {
|
|
199
210
|
var _a;
|
|
200
|
-
let ino =
|
|
211
|
+
let ino = 1;
|
|
201
212
|
while (this.store.has(ino))
|
|
202
213
|
ino++;
|
|
203
214
|
const dev = {
|
|
@@ -295,17 +306,17 @@ export class DeviceFS extends StoreFS {
|
|
|
295
306
|
}
|
|
296
307
|
return super.openFileSync(path, flag);
|
|
297
308
|
}
|
|
298
|
-
async createFile(path, flag, mode) {
|
|
309
|
+
async createFile(path, flag, mode, options) {
|
|
299
310
|
if (this.devices.has(path)) {
|
|
300
311
|
throw ErrnoError.With('EEXIST', path, 'createFile');
|
|
301
312
|
}
|
|
302
|
-
return super.createFile(path, flag, mode);
|
|
313
|
+
return super.createFile(path, flag, mode, options);
|
|
303
314
|
}
|
|
304
|
-
createFileSync(path, flag, mode) {
|
|
315
|
+
createFileSync(path, flag, mode, options) {
|
|
305
316
|
if (this.devices.has(path)) {
|
|
306
317
|
throw ErrnoError.With('EEXIST', path, 'createFile');
|
|
307
318
|
}
|
|
308
|
-
return super.createFileSync(path, flag, mode);
|
|
319
|
+
return super.createFileSync(path, flag, mode, options);
|
|
309
320
|
}
|
|
310
321
|
async unlink(path) {
|
|
311
322
|
if (this.devices.has(path)) {
|
|
@@ -325,17 +336,17 @@ export class DeviceFS extends StoreFS {
|
|
|
325
336
|
rmdirSync(path) {
|
|
326
337
|
return super.rmdirSync(path);
|
|
327
338
|
}
|
|
328
|
-
async mkdir(path, mode) {
|
|
339
|
+
async mkdir(path, mode, options) {
|
|
329
340
|
if (this.devices.has(path)) {
|
|
330
341
|
throw ErrnoError.With('EEXIST', path, 'mkdir');
|
|
331
342
|
}
|
|
332
|
-
return super.mkdir(path, mode);
|
|
343
|
+
return super.mkdir(path, mode, options);
|
|
333
344
|
}
|
|
334
|
-
mkdirSync(path, mode) {
|
|
345
|
+
mkdirSync(path, mode, options) {
|
|
335
346
|
if (this.devices.has(path)) {
|
|
336
347
|
throw ErrnoError.With('EEXIST', path, 'mkdir');
|
|
337
348
|
}
|
|
338
|
-
return super.mkdirSync(path, mode);
|
|
349
|
+
return super.mkdirSync(path, mode, options);
|
|
339
350
|
}
|
|
340
351
|
async readdir(path) {
|
|
341
352
|
const entries = await super.readdir(path);
|
|
@@ -385,11 +396,56 @@ export class DeviceFS extends StoreFS {
|
|
|
385
396
|
}
|
|
386
397
|
return super.syncSync(path, data, stats);
|
|
387
398
|
}
|
|
399
|
+
async read(path, buffer, offset, end) {
|
|
400
|
+
const device = this.devices.get(path);
|
|
401
|
+
if (!device) {
|
|
402
|
+
await super.read(path, buffer, offset, end);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
device.driver.readD(device, buffer, offset, end);
|
|
406
|
+
}
|
|
407
|
+
readSync(path, buffer, offset, end) {
|
|
408
|
+
const device = this.devices.get(path);
|
|
409
|
+
if (!device) {
|
|
410
|
+
super.readSync(path, buffer, offset, end);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
device.driver.readD(device, buffer, offset, end);
|
|
414
|
+
}
|
|
415
|
+
async write(path, data, offset) {
|
|
416
|
+
const device = this.devices.get(path);
|
|
417
|
+
if (!device) {
|
|
418
|
+
return await super.write(path, data, offset);
|
|
419
|
+
}
|
|
420
|
+
device.driver.writeD(device, data, offset);
|
|
421
|
+
}
|
|
422
|
+
writeSync(path, data, offset) {
|
|
423
|
+
const device = this.devices.get(path);
|
|
424
|
+
if (!device) {
|
|
425
|
+
return super.writeSync(path, data, offset);
|
|
426
|
+
}
|
|
427
|
+
device.driver.writeD(device, data, offset);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function defaultWrite(file, buffer, offset, length, position) {
|
|
431
|
+
return file.writeSync(buffer, offset, length, position);
|
|
388
432
|
}
|
|
389
|
-
function
|
|
390
|
-
|
|
391
|
-
return length;
|
|
433
|
+
function defaultWriteD(device, data, offset) {
|
|
434
|
+
return;
|
|
392
435
|
}
|
|
436
|
+
function defaultRead(file, buffer, offset, length, position) {
|
|
437
|
+
return file.readSync(buffer, offset, length, position);
|
|
438
|
+
}
|
|
439
|
+
// 512 bytes.
|
|
440
|
+
const blockSize = 0x200;
|
|
441
|
+
function alloc(bytesNeeded, existing) {
|
|
442
|
+
const blocksNeeded = bytesNeeded / blockSize;
|
|
443
|
+
const currentBocks = existing ? existing.byteLength / blockSize : 0;
|
|
444
|
+
if (blocksNeeded <= currentBocks && existing)
|
|
445
|
+
return existing;
|
|
446
|
+
return new Uint8Array(Math.ceil(blocksNeeded));
|
|
447
|
+
}
|
|
448
|
+
const emptyBuffer = new Uint8Array();
|
|
393
449
|
/**
|
|
394
450
|
* Simulates the `/dev/null` device.
|
|
395
451
|
* - Reads return 0 bytes (EOF).
|
|
@@ -405,7 +461,11 @@ export const nullDevice = {
|
|
|
405
461
|
read() {
|
|
406
462
|
return 0;
|
|
407
463
|
},
|
|
464
|
+
readD() {
|
|
465
|
+
return emptyBuffer;
|
|
466
|
+
},
|
|
408
467
|
write: defaultWrite,
|
|
468
|
+
writeD: defaultWriteD,
|
|
409
469
|
};
|
|
410
470
|
/**
|
|
411
471
|
* Simulates the `/dev/zero` device
|
|
@@ -423,15 +483,12 @@ export const zeroDevice = {
|
|
|
423
483
|
init() {
|
|
424
484
|
return { major: 1, minor: 5 };
|
|
425
485
|
},
|
|
426
|
-
read
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
data[i] = 0;
|
|
430
|
-
}
|
|
431
|
-
file.position += length;
|
|
432
|
-
return length;
|
|
486
|
+
read: defaultRead,
|
|
487
|
+
readD(device, buffer, offset, end) {
|
|
488
|
+
buffer.fill(0, offset, end);
|
|
433
489
|
},
|
|
434
490
|
write: defaultWrite,
|
|
491
|
+
writeD: defaultWriteD,
|
|
435
492
|
};
|
|
436
493
|
/**
|
|
437
494
|
* Simulates the `/dev/full` device.
|
|
@@ -445,17 +502,16 @@ export const fullDevice = {
|
|
|
445
502
|
init() {
|
|
446
503
|
return { major: 1, minor: 7 };
|
|
447
504
|
},
|
|
448
|
-
read
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
data[i] = 0;
|
|
452
|
-
}
|
|
453
|
-
file.position += length;
|
|
454
|
-
return length;
|
|
505
|
+
read: defaultRead,
|
|
506
|
+
readD(device, buffer, offset, end) {
|
|
507
|
+
buffer.fill(0, offset, end);
|
|
455
508
|
},
|
|
456
509
|
write(file) {
|
|
457
510
|
throw ErrnoError.With('ENOSPC', file.path, 'write');
|
|
458
511
|
},
|
|
512
|
+
writeD() {
|
|
513
|
+
throw ErrnoError.With('ENOSPC', undefined, 'write');
|
|
514
|
+
},
|
|
459
515
|
};
|
|
460
516
|
/**
|
|
461
517
|
* Simulates the `/dev/random` device.
|
|
@@ -469,15 +525,14 @@ export const randomDevice = {
|
|
|
469
525
|
init() {
|
|
470
526
|
return { major: 1, minor: 8 };
|
|
471
527
|
},
|
|
472
|
-
read
|
|
473
|
-
|
|
474
|
-
for (let i =
|
|
475
|
-
|
|
528
|
+
read: defaultRead,
|
|
529
|
+
readD(device, buffer) {
|
|
530
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
531
|
+
buffer[i] = Math.floor(Math.random() * 256);
|
|
476
532
|
}
|
|
477
|
-
file.position += length;
|
|
478
|
-
return length;
|
|
479
533
|
},
|
|
480
534
|
write: defaultWrite,
|
|
535
|
+
writeD: defaultWriteD,
|
|
481
536
|
};
|
|
482
537
|
/**
|
|
483
538
|
* Simulates the `/dev/console` device.
|
|
@@ -486,17 +541,17 @@ export const randomDevice = {
|
|
|
486
541
|
const consoleDevice = {
|
|
487
542
|
name: 'console',
|
|
488
543
|
singleton: true,
|
|
489
|
-
init(ino, { output = console.log } = {}) {
|
|
544
|
+
init(ino, { output = text => console.log(text) } = {}) {
|
|
490
545
|
return { major: 5, minor: 1, data: { output } };
|
|
491
546
|
},
|
|
492
|
-
read
|
|
493
|
-
|
|
547
|
+
read: defaultRead,
|
|
548
|
+
readD() {
|
|
549
|
+
return emptyBuffer;
|
|
494
550
|
},
|
|
495
|
-
write
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
return length;
|
|
551
|
+
write: defaultWrite,
|
|
552
|
+
writeD(device, buffer, offset) {
|
|
553
|
+
const text = decodeUTF8(buffer);
|
|
554
|
+
device.data.output(text, offset);
|
|
500
555
|
},
|
|
501
556
|
};
|
|
502
557
|
/**
|
package/dist/file.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { FileReadResult } from 'node:fs/promises';
|
|
2
1
|
import type { FileSystem } from './filesystem.js';
|
|
3
2
|
import './polyfills.js';
|
|
4
|
-
import { Stats } from './stats.js';
|
|
3
|
+
import { Stats, type StatsLike } from './stats.js';
|
|
5
4
|
export declare function parseFlag(flag: string | number): string;
|
|
6
5
|
export declare function flagToString(flag: number): string;
|
|
7
6
|
export declare function flagToNumber(flag: string): number;
|
|
@@ -16,6 +15,10 @@ export declare function isTruncating(flag: string): boolean;
|
|
|
16
15
|
export declare function isAppendable(flag: string): boolean;
|
|
17
16
|
export declare function isSynchronous(flag: string): boolean;
|
|
18
17
|
export declare function isExclusive(flag: string): boolean;
|
|
18
|
+
export interface FileReadResult<T extends ArrayBufferView> {
|
|
19
|
+
bytesRead: number;
|
|
20
|
+
buffer: T;
|
|
21
|
+
}
|
|
19
22
|
export declare abstract class File<FS extends FileSystem = FileSystem> {
|
|
20
23
|
/**
|
|
21
24
|
* @internal
|
|
@@ -71,7 +74,7 @@ export declare abstract class File<FS extends FileSystem = FileSystem> {
|
|
|
71
74
|
* If position is null, data will be read from the current file position.
|
|
72
75
|
* @returns Promise resolving to the new length of the buffer
|
|
73
76
|
*/
|
|
74
|
-
abstract read<TBuffer extends
|
|
77
|
+
abstract read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<FileReadResult<TBuffer>>;
|
|
75
78
|
/**
|
|
76
79
|
* Read data from the file.
|
|
77
80
|
* @param buffer The buffer that the data will be written to.
|
|
@@ -96,11 +99,11 @@ export declare abstract class File<FS extends FileSystem = FileSystem> {
|
|
|
96
99
|
/**
|
|
97
100
|
* Change the file timestamps of the file.
|
|
98
101
|
*/
|
|
99
|
-
abstract utimes(atime:
|
|
102
|
+
abstract utimes(atime: number, mtime: number): Promise<void>;
|
|
100
103
|
/**
|
|
101
104
|
* Change the file timestamps of the file.
|
|
102
105
|
*/
|
|
103
|
-
abstract utimesSync(atime:
|
|
106
|
+
abstract utimesSync(atime: number, mtime: number): void;
|
|
104
107
|
}
|
|
105
108
|
/**
|
|
106
109
|
* An implementation of `File` that operates completely in-memory.
|
|
@@ -209,11 +212,12 @@ export declare class PreloadFile<FS extends FileSystem> extends File<FS> {
|
|
|
209
212
|
chmodSync(mode: number): void;
|
|
210
213
|
chown(uid: number, gid: number): Promise<void>;
|
|
211
214
|
chownSync(uid: number, gid: number): void;
|
|
212
|
-
utimes(atime:
|
|
213
|
-
utimesSync(atime:
|
|
215
|
+
utimes(atime: number, mtime: number): Promise<void>;
|
|
216
|
+
utimesSync(atime: number, mtime: number): void;
|
|
214
217
|
}
|
|
215
218
|
/**
|
|
216
219
|
* For the file systems which do not sync to anything.
|
|
220
|
+
* @deprecated
|
|
217
221
|
*/
|
|
218
222
|
export declare class NoSyncFile<T extends FileSystem> extends PreloadFile<T> {
|
|
219
223
|
sync(): Promise<void>;
|
|
@@ -221,3 +225,103 @@ export declare class NoSyncFile<T extends FileSystem> extends PreloadFile<T> {
|
|
|
221
225
|
close(): Promise<void>;
|
|
222
226
|
closeSync(): void;
|
|
223
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* An implementation of `File` that uses the FS
|
|
230
|
+
*/
|
|
231
|
+
export declare class LazyFile<FS extends FileSystem> extends File<FS> {
|
|
232
|
+
readonly flag: string;
|
|
233
|
+
readonly stats: StatsLike<number>;
|
|
234
|
+
protected _buffer?: Uint8Array;
|
|
235
|
+
/**
|
|
236
|
+
* Current position
|
|
237
|
+
*/
|
|
238
|
+
protected _position: number;
|
|
239
|
+
/**
|
|
240
|
+
* Get the current file position.
|
|
241
|
+
*
|
|
242
|
+
* We emulate the following bug mentioned in the Node documentation:
|
|
243
|
+
*
|
|
244
|
+
* On Linux, positional writes don't work when the file is opened in append mode.
|
|
245
|
+
* The kernel ignores the position argument and always appends the data to the end of the file.
|
|
246
|
+
* @returns The current file position.
|
|
247
|
+
*/
|
|
248
|
+
get position(): number;
|
|
249
|
+
set position(value: number);
|
|
250
|
+
/**
|
|
251
|
+
* Whether the file has changes which have not been written to the FS
|
|
252
|
+
*/
|
|
253
|
+
protected dirty: boolean;
|
|
254
|
+
/**
|
|
255
|
+
* Whether the file is open or closed
|
|
256
|
+
*/
|
|
257
|
+
protected closed: boolean;
|
|
258
|
+
/**
|
|
259
|
+
* Creates a file with `path` and, optionally, the given contents.
|
|
260
|
+
* Note that, if contents is specified, it will be mutated by the file.
|
|
261
|
+
*/
|
|
262
|
+
constructor(fs: FS, path: string, flag: string, stats: StatsLike<number>);
|
|
263
|
+
sync(): Promise<void>;
|
|
264
|
+
syncSync(): void;
|
|
265
|
+
close(): Promise<void>;
|
|
266
|
+
closeSync(): void;
|
|
267
|
+
/**
|
|
268
|
+
* Cleans up. This will *not* sync the file data to the FS
|
|
269
|
+
*/
|
|
270
|
+
protected dispose(force?: boolean): void;
|
|
271
|
+
stat(): Promise<Stats>;
|
|
272
|
+
statSync(): Stats;
|
|
273
|
+
truncate(length: number): Promise<void>;
|
|
274
|
+
truncateSync(length: number): void;
|
|
275
|
+
protected prepareWrite(buffer: Uint8Array, offset: number, length: number, position: number): Uint8Array;
|
|
276
|
+
/**
|
|
277
|
+
* Write buffer to the file.
|
|
278
|
+
* @param buffer Uint8Array containing the data to write to the file.
|
|
279
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
280
|
+
* @param length The amount of bytes to write to the file.
|
|
281
|
+
* @param position Offset from the beginning of the file where this data should be written.
|
|
282
|
+
* If position is null, the data will be written at the current position.
|
|
283
|
+
*/
|
|
284
|
+
write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>;
|
|
285
|
+
/**
|
|
286
|
+
* Write buffer to the file.
|
|
287
|
+
* @param buffer Uint8Array containing the data to write to the file.
|
|
288
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
289
|
+
* @param length The amount of bytes to write to the file.
|
|
290
|
+
* @param position Offset from the beginning of the file where this data should be written.
|
|
291
|
+
* If position is null, the data will be written at the current position.
|
|
292
|
+
* @returns bytes written
|
|
293
|
+
*/
|
|
294
|
+
writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
|
|
295
|
+
/**
|
|
296
|
+
* Computes position information for reading
|
|
297
|
+
*/
|
|
298
|
+
protected prepareRead(length: number, position: number): number;
|
|
299
|
+
/**
|
|
300
|
+
* Read data from the file.
|
|
301
|
+
* @param buffer The buffer that the data will be written to.
|
|
302
|
+
* @param offset The offset within the buffer where writing will start.
|
|
303
|
+
* @param length An integer specifying the number of bytes to read.
|
|
304
|
+
* @param position An integer specifying where to begin reading from in the file.
|
|
305
|
+
* If position is unset, data will be read from the current file position.
|
|
306
|
+
*/
|
|
307
|
+
read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{
|
|
308
|
+
bytesRead: number;
|
|
309
|
+
buffer: TBuffer;
|
|
310
|
+
}>;
|
|
311
|
+
/**
|
|
312
|
+
* Read data from the file.
|
|
313
|
+
* @param buffer The buffer that the data will be written to.
|
|
314
|
+
* @param offset The offset within the buffer where writing will start.
|
|
315
|
+
* @param length An integer specifying the number of bytes to read.
|
|
316
|
+
* @param position An integer specifying where to begin reading from in the file.
|
|
317
|
+
* If position is null, data will be read from the current file position.
|
|
318
|
+
* @returns number of bytes written
|
|
319
|
+
*/
|
|
320
|
+
readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
|
|
321
|
+
chmod(mode: number): Promise<void>;
|
|
322
|
+
chmodSync(mode: number): void;
|
|
323
|
+
chown(uid: number, gid: number): Promise<void>;
|
|
324
|
+
chownSync(uid: number, gid: number): void;
|
|
325
|
+
utimes(atime: number, mtime: number): Promise<void>;
|
|
326
|
+
utimesSync(atime: number, mtime: number): void;
|
|
327
|
+
}
|