@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/file.ts
DELETED
|
@@ -1,631 +0,0 @@
|
|
|
1
|
-
import type { FileReadResult } from 'node:fs/promises';
|
|
2
|
-
import { config } from './emulation/config.js';
|
|
3
|
-
import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT, size_max } from './emulation/constants.js';
|
|
4
|
-
import { Errno, ErrnoError } from './error.js';
|
|
5
|
-
import type { FileSystem } from './filesystem.js';
|
|
6
|
-
import './polyfills.js';
|
|
7
|
-
import { _chown, Stats } from './stats.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
Typescript does not include a type declaration for resizable array buffers.
|
|
11
|
-
It has been standardized into ECMAScript though
|
|
12
|
-
@todo Remove this if TS adds them to lib declarations
|
|
13
|
-
*/
|
|
14
|
-
declare global {
|
|
15
|
-
interface ArrayBuffer {
|
|
16
|
-
readonly resizable: boolean;
|
|
17
|
-
|
|
18
|
-
readonly maxByteLength?: number;
|
|
19
|
-
|
|
20
|
-
resize(newLength: number): void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface SharedArrayBuffer {
|
|
24
|
-
readonly resizable: boolean;
|
|
25
|
-
|
|
26
|
-
readonly maxByteLength?: number;
|
|
27
|
-
|
|
28
|
-
resize(newLength: number): void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface ArrayBufferConstructor {
|
|
32
|
-
new (byteLength: number, options: { maxByteLength?: number }): ArrayBuffer;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
|
|
37
|
-
|
|
38
|
-
export function parseFlag(flag: string | number): string {
|
|
39
|
-
if (typeof flag === 'number') {
|
|
40
|
-
return flagToString(flag);
|
|
41
|
-
}
|
|
42
|
-
if (!validFlags.includes(flag)) {
|
|
43
|
-
throw new Error('Invalid flag string: ' + flag);
|
|
44
|
-
}
|
|
45
|
-
return flag;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function flagToString(flag: number): string {
|
|
49
|
-
switch (flag) {
|
|
50
|
-
case O_RDONLY:
|
|
51
|
-
return 'r';
|
|
52
|
-
case O_RDONLY | O_SYNC:
|
|
53
|
-
return 'rs';
|
|
54
|
-
case O_RDWR:
|
|
55
|
-
return 'r+';
|
|
56
|
-
case O_RDWR | O_SYNC:
|
|
57
|
-
return 'rs+';
|
|
58
|
-
case O_TRUNC | O_CREAT | O_WRONLY:
|
|
59
|
-
return 'w';
|
|
60
|
-
case O_TRUNC | O_CREAT | O_WRONLY | O_EXCL:
|
|
61
|
-
return 'wx';
|
|
62
|
-
case O_TRUNC | O_CREAT | O_RDWR:
|
|
63
|
-
return 'w+';
|
|
64
|
-
case O_TRUNC | O_CREAT | O_RDWR | O_EXCL:
|
|
65
|
-
return 'wx+';
|
|
66
|
-
case O_APPEND | O_CREAT | O_WRONLY:
|
|
67
|
-
return 'a';
|
|
68
|
-
case O_APPEND | O_CREAT | O_WRONLY | O_EXCL:
|
|
69
|
-
return 'ax';
|
|
70
|
-
case O_APPEND | O_CREAT | O_RDWR:
|
|
71
|
-
return 'a+';
|
|
72
|
-
case O_APPEND | O_CREAT | O_RDWR | O_EXCL:
|
|
73
|
-
return 'ax+';
|
|
74
|
-
default:
|
|
75
|
-
throw new Error('Invalid flag number: ' + flag);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function flagToNumber(flag: string): number {
|
|
80
|
-
switch (flag) {
|
|
81
|
-
case 'r':
|
|
82
|
-
return O_RDONLY;
|
|
83
|
-
case 'rs':
|
|
84
|
-
return O_RDONLY | O_SYNC;
|
|
85
|
-
case 'r+':
|
|
86
|
-
return O_RDWR;
|
|
87
|
-
case 'rs+':
|
|
88
|
-
return O_RDWR | O_SYNC;
|
|
89
|
-
case 'w':
|
|
90
|
-
return O_TRUNC | O_CREAT | O_WRONLY;
|
|
91
|
-
case 'wx':
|
|
92
|
-
return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
|
|
93
|
-
case 'w+':
|
|
94
|
-
return O_TRUNC | O_CREAT | O_RDWR;
|
|
95
|
-
case 'wx+':
|
|
96
|
-
return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
|
|
97
|
-
case 'a':
|
|
98
|
-
return O_APPEND | O_CREAT | O_WRONLY;
|
|
99
|
-
case 'ax':
|
|
100
|
-
return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
|
|
101
|
-
case 'a+':
|
|
102
|
-
return O_APPEND | O_CREAT | O_RDWR;
|
|
103
|
-
case 'ax+':
|
|
104
|
-
return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
|
|
105
|
-
default:
|
|
106
|
-
throw new Error('Invalid flag string: ' + flag);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Parses a flag as a mode (W_OK, R_OK, and/or X_OK)
|
|
112
|
-
* @param flag the flag to parse
|
|
113
|
-
*/
|
|
114
|
-
export function flagToMode(flag: string): number {
|
|
115
|
-
let mode = 0;
|
|
116
|
-
mode <<= 1;
|
|
117
|
-
mode += +isReadable(flag);
|
|
118
|
-
mode <<= 1;
|
|
119
|
-
mode += +isWriteable(flag);
|
|
120
|
-
mode <<= 1;
|
|
121
|
-
return mode;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function isReadable(flag: string): boolean {
|
|
125
|
-
return flag.indexOf('r') !== -1 || flag.indexOf('+') !== -1;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function isWriteable(flag: string): boolean {
|
|
129
|
-
return flag.indexOf('w') !== -1 || flag.indexOf('a') !== -1 || flag.indexOf('+') !== -1;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function isTruncating(flag: string): boolean {
|
|
133
|
-
return flag.indexOf('w') !== -1;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function isAppendable(flag: string): boolean {
|
|
137
|
-
return flag.indexOf('a') !== -1;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function isSynchronous(flag: string): boolean {
|
|
141
|
-
return flag.indexOf('s') !== -1;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function isExclusive(flag: string): boolean {
|
|
145
|
-
return flag.indexOf('x') !== -1;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export abstract class File<FS extends FileSystem = FileSystem> {
|
|
149
|
-
public constructor(
|
|
150
|
-
/**
|
|
151
|
-
* @internal
|
|
152
|
-
* The file system that created the file
|
|
153
|
-
*/
|
|
154
|
-
public fs: FileSystem,
|
|
155
|
-
public readonly path: string
|
|
156
|
-
) {}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Get the current file position.
|
|
160
|
-
*/
|
|
161
|
-
public abstract position: number;
|
|
162
|
-
|
|
163
|
-
public abstract stat(): Promise<Stats>;
|
|
164
|
-
public abstract statSync(): Stats;
|
|
165
|
-
|
|
166
|
-
public abstract close(): Promise<void>;
|
|
167
|
-
public abstract closeSync(): void;
|
|
168
|
-
|
|
169
|
-
public async [Symbol.asyncDispose](): Promise<void> {
|
|
170
|
-
await this.close();
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
public [Symbol.dispose](): void {
|
|
174
|
-
this.closeSync();
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
public abstract truncate(len: number): Promise<void>;
|
|
178
|
-
public abstract truncateSync(len: number): void;
|
|
179
|
-
|
|
180
|
-
public abstract sync(): Promise<void>;
|
|
181
|
-
public abstract syncSync(): void;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Write buffer to the file.
|
|
185
|
-
* @param buffer Uint8Array containing the data to write to the file.
|
|
186
|
-
* @param offset Offset in the buffer to start reading data from.
|
|
187
|
-
* @param length The amount of bytes to write to the file.
|
|
188
|
-
* @param position Offset from the beginning of the file where this data should be written.
|
|
189
|
-
* If position is null, the data will be written at the current position.
|
|
190
|
-
* @returns Promise resolving to the new length of the buffer
|
|
191
|
-
*/
|
|
192
|
-
public abstract write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Write buffer to the file.
|
|
196
|
-
* @param buffer Uint8Array containing the data to write to the file.
|
|
197
|
-
* @param offset Offset in the buffer to start reading data from.
|
|
198
|
-
* @param length The amount of bytes to write to the file.
|
|
199
|
-
* @param position Offset from the beginning of the file where this data should be written.
|
|
200
|
-
* If position is null, the data will be written at the current position.
|
|
201
|
-
*/
|
|
202
|
-
public abstract writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Read data from the file.
|
|
206
|
-
* @param buffer The buffer that the data will be written to.
|
|
207
|
-
* @param offset The offset within the buffer where writing will start.
|
|
208
|
-
* @param length An integer specifying the number of bytes to read.
|
|
209
|
-
* @param position An integer specifying where to begin reading from in the file.
|
|
210
|
-
* If position is null, data will be read from the current file position.
|
|
211
|
-
* @returns Promise resolving to the new length of the buffer
|
|
212
|
-
*/
|
|
213
|
-
public abstract read<TBuffer extends NodeJS.ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<FileReadResult<TBuffer>>;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Read data from the file.
|
|
217
|
-
* @param buffer The buffer that the data will be written to.
|
|
218
|
-
* @param offset The offset within the buffer where writing will start.
|
|
219
|
-
* @param length An integer specifying the number of bytes to read.
|
|
220
|
-
* @param position An integer specifying where to begin reading from in the file.
|
|
221
|
-
* If position is null, data will be read from the current file position.
|
|
222
|
-
*/
|
|
223
|
-
public abstract readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Default implementation maps to `sync`.
|
|
227
|
-
*/
|
|
228
|
-
public datasync(): Promise<void> {
|
|
229
|
-
return this.sync();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Default implementation maps to `syncSync`.
|
|
234
|
-
*/
|
|
235
|
-
public datasyncSync(): void {
|
|
236
|
-
return this.syncSync();
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
public abstract chown(uid: number, gid: number): Promise<void>;
|
|
240
|
-
public abstract chownSync(uid: number, gid: number): void;
|
|
241
|
-
|
|
242
|
-
public abstract chmod(mode: number): Promise<void>;
|
|
243
|
-
public abstract chmodSync(mode: number): void;
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Change the file timestamps of the file.
|
|
247
|
-
*/
|
|
248
|
-
public abstract utimes(atime: Date, mtime: Date): Promise<void>;
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Change the file timestamps of the file.
|
|
252
|
-
*/
|
|
253
|
-
public abstract utimesSync(atime: Date, mtime: Date): void;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* An implementation of `File` that operates completely in-memory.
|
|
258
|
-
* `PreloadFile`s are backed by a `Uint8Array`.
|
|
259
|
-
*/
|
|
260
|
-
export class PreloadFile<FS extends FileSystem> extends File<FS> {
|
|
261
|
-
/**
|
|
262
|
-
* Current position
|
|
263
|
-
*/
|
|
264
|
-
protected _position: number = 0;
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Whether the file has changes which have not been written to the FS
|
|
268
|
-
*/
|
|
269
|
-
protected dirty: boolean = false;
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Whether the file is open or closed
|
|
273
|
-
*/
|
|
274
|
-
protected closed: boolean = false;
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Creates a file with `path` and, optionally, the given contents.
|
|
278
|
-
* Note that, if contents is specified, it will be mutated by the file.
|
|
279
|
-
*/
|
|
280
|
-
public constructor(
|
|
281
|
-
fs: FS,
|
|
282
|
-
path: string,
|
|
283
|
-
public readonly flag: string,
|
|
284
|
-
public readonly stats: Stats,
|
|
285
|
-
/**
|
|
286
|
-
* A buffer containing the entire contents of the file.
|
|
287
|
-
*/
|
|
288
|
-
protected _buffer: Uint8Array = new Uint8Array(new ArrayBuffer(0, fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }))
|
|
289
|
-
) {
|
|
290
|
-
super(fs, path);
|
|
291
|
-
|
|
292
|
-
/*
|
|
293
|
-
Note:
|
|
294
|
-
This invariant is *not* maintained once the file starts getting modified.
|
|
295
|
-
It only actually matters if file is readable, as writeable modes may truncate/append to file.
|
|
296
|
-
*/
|
|
297
|
-
if (this.stats.size == _buffer.byteLength) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (isReadable(this.flag)) {
|
|
302
|
-
throw new Error(`Size mismatch: buffer length ${_buffer.byteLength}, stats size ${this.stats.size}`);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
this.dirty = true;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Get the underlying buffer for this file. Mutating not recommended and will mess up dirty tracking.
|
|
310
|
-
*/
|
|
311
|
-
public get buffer(): Uint8Array {
|
|
312
|
-
return this._buffer;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Get the current file position.
|
|
317
|
-
*
|
|
318
|
-
* We emulate the following bug mentioned in the Node documentation:
|
|
319
|
-
*
|
|
320
|
-
* On Linux, positional writes don't work when the file is opened in append mode.
|
|
321
|
-
* The kernel ignores the position argument and always appends the data to the end of the file.
|
|
322
|
-
* @returns The current file position.
|
|
323
|
-
*/
|
|
324
|
-
public get position(): number {
|
|
325
|
-
if (isAppendable(this.flag)) {
|
|
326
|
-
return this.stats.size;
|
|
327
|
-
}
|
|
328
|
-
return this._position;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
public set position(value: number) {
|
|
332
|
-
this._position = value;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
public async sync(): Promise<void> {
|
|
336
|
-
if (this.closed) {
|
|
337
|
-
throw ErrnoError.With('EBADF', this.path, 'File.sync');
|
|
338
|
-
}
|
|
339
|
-
if (!this.dirty) {
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
await this.fs.sync(this.path, this._buffer, this.stats);
|
|
343
|
-
this.dirty = false;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
public syncSync(): void {
|
|
347
|
-
if (this.closed) {
|
|
348
|
-
throw ErrnoError.With('EBADF', this.path, 'File.sync');
|
|
349
|
-
}
|
|
350
|
-
if (!this.dirty) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
this.fs.syncSync(this.path, this._buffer, this.stats);
|
|
354
|
-
this.dirty = false;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
public async close(): Promise<void> {
|
|
358
|
-
if (this.closed) {
|
|
359
|
-
throw ErrnoError.With('EBADF', this.path, 'File.close');
|
|
360
|
-
}
|
|
361
|
-
await this.sync();
|
|
362
|
-
this.dispose();
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
public closeSync(): void {
|
|
366
|
-
if (this.closed) {
|
|
367
|
-
throw ErrnoError.With('EBADF', this.path, 'File.close');
|
|
368
|
-
}
|
|
369
|
-
this.syncSync();
|
|
370
|
-
this.dispose();
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Cleans up. This will *not* sync the file data to the FS
|
|
375
|
-
*/
|
|
376
|
-
protected dispose(force?: boolean): void {
|
|
377
|
-
if (this.closed) {
|
|
378
|
-
throw ErrnoError.With('EBADF', this.path, 'File.dispose');
|
|
379
|
-
}
|
|
380
|
-
if (this.dirty && !force) {
|
|
381
|
-
throw ErrnoError.With('EBUSY', this.path, 'File.dispose');
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// @ts-expect-error 2790
|
|
385
|
-
delete this._buffer;
|
|
386
|
-
// @ts-expect-error 2790
|
|
387
|
-
delete this.stats;
|
|
388
|
-
|
|
389
|
-
this.closed = true;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
public stat(): Promise<Stats> {
|
|
393
|
-
if (this.closed) {
|
|
394
|
-
throw ErrnoError.With('EBADF', this.path, 'File.stat');
|
|
395
|
-
}
|
|
396
|
-
return Promise.resolve(new Stats(this.stats));
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
public statSync(): Stats {
|
|
400
|
-
if (this.closed) {
|
|
401
|
-
throw ErrnoError.With('EBADF', this.path, 'File.stat');
|
|
402
|
-
}
|
|
403
|
-
return new Stats(this.stats);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
protected _truncate(length: number): void {
|
|
407
|
-
if (this.closed) {
|
|
408
|
-
throw ErrnoError.With('EBADF', this.path, 'File.truncate');
|
|
409
|
-
}
|
|
410
|
-
this.dirty = true;
|
|
411
|
-
if (!isWriteable(this.flag)) {
|
|
412
|
-
throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
|
|
413
|
-
}
|
|
414
|
-
this.stats.mtimeMs = Date.now();
|
|
415
|
-
if (length > this._buffer.length) {
|
|
416
|
-
const data = new Uint8Array(length - this._buffer.length);
|
|
417
|
-
// Write will set stats.size and handle syncing.
|
|
418
|
-
this._write(data, 0, data.length, this._buffer.length);
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
this.stats.size = length;
|
|
422
|
-
// Truncate.
|
|
423
|
-
this._buffer = length ? this._buffer.slice(0, length) : new Uint8Array();
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
public async truncate(length: number): Promise<void> {
|
|
427
|
-
this._truncate(length);
|
|
428
|
-
if (config.syncImmediately) await this.sync();
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
public truncateSync(length: number): void {
|
|
432
|
-
this._truncate(length);
|
|
433
|
-
if (config.syncImmediately) this.syncSync();
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
protected _write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
|
|
437
|
-
if (this.closed) {
|
|
438
|
-
throw ErrnoError.With('EBADF', this.path, 'File.write');
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (!isWriteable(this.flag)) {
|
|
442
|
-
throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
this.dirty = true;
|
|
446
|
-
const end = position + length;
|
|
447
|
-
const slice = buffer.slice(offset, offset + length);
|
|
448
|
-
|
|
449
|
-
if (end > this.stats.size) {
|
|
450
|
-
this.stats.size = end;
|
|
451
|
-
if (end > this._buffer.byteLength) {
|
|
452
|
-
if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength! <= end) {
|
|
453
|
-
this._buffer.buffer.resize(end);
|
|
454
|
-
} else if (config.unsafeBufferReplace) {
|
|
455
|
-
this._buffer = slice;
|
|
456
|
-
} else {
|
|
457
|
-
// Extend the buffer!
|
|
458
|
-
const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
|
|
459
|
-
newBuffer.set(this._buffer);
|
|
460
|
-
this._buffer = newBuffer;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
this._buffer.set(slice, position);
|
|
466
|
-
this.stats.mtimeMs = Date.now();
|
|
467
|
-
this.position = position + slice.byteLength;
|
|
468
|
-
return slice.byteLength;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Write buffer to the file.
|
|
473
|
-
* @param buffer Uint8Array containing the data to write to the file.
|
|
474
|
-
* @param offset Offset in the buffer to start reading data from.
|
|
475
|
-
* @param length The amount of bytes to write to the file.
|
|
476
|
-
* @param position Offset from the beginning of the file where this data should be written.
|
|
477
|
-
* If position is null, the data will be written at the current position.
|
|
478
|
-
*/
|
|
479
|
-
public async write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number> {
|
|
480
|
-
const bytesWritten = this._write(buffer, offset, length, position);
|
|
481
|
-
if (config.syncImmediately) await this.sync();
|
|
482
|
-
return bytesWritten;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* Write buffer to the file.
|
|
487
|
-
* @param buffer Uint8Array containing the data to write to the file.
|
|
488
|
-
* @param offset Offset in the buffer to start reading data from.
|
|
489
|
-
* @param length The amount of bytes to write to the file.
|
|
490
|
-
* @param position Offset from the beginning of the file where this data should be written.
|
|
491
|
-
* If position is null, the data will be written at the current position.
|
|
492
|
-
* @returns bytes written
|
|
493
|
-
*/
|
|
494
|
-
public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
|
|
495
|
-
const bytesWritten = this._write(buffer, offset, length, position);
|
|
496
|
-
if (config.syncImmediately) this.syncSync();
|
|
497
|
-
return bytesWritten;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
protected _read(buffer: ArrayBufferView, offset: number = 0, length: number = this.stats.size, position?: number): number {
|
|
501
|
-
if (this.closed) {
|
|
502
|
-
throw ErrnoError.With('EBADF', this.path, 'File.read');
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
if (!isReadable(this.flag)) {
|
|
506
|
-
throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (config.updateOnRead) {
|
|
510
|
-
this.dirty = true;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
this.stats.atimeMs = Date.now();
|
|
514
|
-
|
|
515
|
-
position ??= this.position;
|
|
516
|
-
let end = position + length;
|
|
517
|
-
if (end > this.stats.size) {
|
|
518
|
-
end = position + Math.max(this.stats.size - position, 0);
|
|
519
|
-
}
|
|
520
|
-
this._position = end;
|
|
521
|
-
const bytesRead = end - position;
|
|
522
|
-
if (bytesRead == 0) {
|
|
523
|
-
// No copy/read. Return immediately for better performance
|
|
524
|
-
return bytesRead;
|
|
525
|
-
}
|
|
526
|
-
new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
|
|
527
|
-
return bytesRead;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Read data from the file.
|
|
532
|
-
* @param buffer The buffer that the data will be written to.
|
|
533
|
-
* @param offset The offset within the buffer where writing will start.
|
|
534
|
-
* @param length An integer specifying the number of bytes to read.
|
|
535
|
-
* @param position An integer specifying where to begin reading from in the file.
|
|
536
|
-
* If position is null, data will be read from the current file position.
|
|
537
|
-
*/
|
|
538
|
-
public async read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{ bytesRead: number; buffer: TBuffer }> {
|
|
539
|
-
const bytesRead = this._read(buffer, offset, length, position);
|
|
540
|
-
if (config.syncImmediately) await this.sync();
|
|
541
|
-
return { bytesRead, buffer };
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* Read data from the file.
|
|
546
|
-
* @param buffer The buffer that the data will be written to.
|
|
547
|
-
* @param offset The offset within the buffer where writing will start.
|
|
548
|
-
* @param length An integer specifying the number of bytes to read.
|
|
549
|
-
* @param position An integer specifying where to begin reading from in the file.
|
|
550
|
-
* If position is null, data will be read from the current file position.
|
|
551
|
-
* @returns number of bytes written
|
|
552
|
-
*/
|
|
553
|
-
public readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number {
|
|
554
|
-
const bytesRead = this._read(buffer, offset, length, position);
|
|
555
|
-
if (config.syncImmediately) this.syncSync();
|
|
556
|
-
return bytesRead;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
public async chmod(mode: number): Promise<void> {
|
|
560
|
-
if (this.closed) {
|
|
561
|
-
throw ErrnoError.With('EBADF', this.path, 'File.chmod');
|
|
562
|
-
}
|
|
563
|
-
this.dirty = true;
|
|
564
|
-
this.stats.mode = (this.stats.mode & (mode > S_IFMT ? ~S_IFMT : S_IFMT)) | mode;
|
|
565
|
-
if (config.syncImmediately || mode > S_IFMT) await this.sync();
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
public chmodSync(mode: number): void {
|
|
569
|
-
if (this.closed) {
|
|
570
|
-
throw ErrnoError.With('EBADF', this.path, 'File.chmod');
|
|
571
|
-
}
|
|
572
|
-
this.dirty = true;
|
|
573
|
-
this.stats.mode = (this.stats.mode & (mode > S_IFMT ? ~S_IFMT : S_IFMT)) | mode;
|
|
574
|
-
if (config.syncImmediately || mode > S_IFMT) this.syncSync();
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
public async chown(uid: number, gid: number): Promise<void> {
|
|
578
|
-
if (this.closed) {
|
|
579
|
-
throw ErrnoError.With('EBADF', this.path, 'File.chown');
|
|
580
|
-
}
|
|
581
|
-
this.dirty = true;
|
|
582
|
-
_chown(this.stats, uid, gid);
|
|
583
|
-
if (config.syncImmediately) await this.sync();
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
public chownSync(uid: number, gid: number): void {
|
|
587
|
-
if (this.closed) {
|
|
588
|
-
throw ErrnoError.With('EBADF', this.path, 'File.chown');
|
|
589
|
-
}
|
|
590
|
-
this.dirty = true;
|
|
591
|
-
_chown(this.stats, uid, gid);
|
|
592
|
-
if (config.syncImmediately) this.syncSync();
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
public async utimes(atime: Date, mtime: Date): Promise<void> {
|
|
596
|
-
if (this.closed) {
|
|
597
|
-
throw ErrnoError.With('EBADF', this.path, 'File.utimes');
|
|
598
|
-
}
|
|
599
|
-
this.dirty = true;
|
|
600
|
-
this.stats.atime = atime;
|
|
601
|
-
this.stats.mtime = mtime;
|
|
602
|
-
if (config.syncImmediately) await this.sync();
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
public utimesSync(atime: Date, mtime: Date): void {
|
|
606
|
-
if (this.closed) {
|
|
607
|
-
throw ErrnoError.With('EBADF', this.path, 'File.utimes');
|
|
608
|
-
}
|
|
609
|
-
this.dirty = true;
|
|
610
|
-
this.stats.atime = atime;
|
|
611
|
-
this.stats.mtime = mtime;
|
|
612
|
-
if (config.syncImmediately) this.syncSync();
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* For the file systems which do not sync to anything.
|
|
618
|
-
*/
|
|
619
|
-
export class NoSyncFile<T extends FileSystem> extends PreloadFile<T> {
|
|
620
|
-
public sync(): Promise<void> {
|
|
621
|
-
return Promise.resolve();
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
public syncSync(): void {}
|
|
625
|
-
|
|
626
|
-
public close(): Promise<void> {
|
|
627
|
-
return Promise.resolve();
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
public closeSync(): void {}
|
|
631
|
-
}
|