@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.
Files changed (88) hide show
  1. package/dist/backends/memory.d.ts +4 -4
  2. package/dist/backends/memory.js +4 -4
  3. package/dist/backends/overlay.d.ts +5 -2
  4. package/dist/backends/overlay.js +7 -10
  5. package/dist/backends/port/fs.js +1 -4
  6. package/dist/config.js +4 -8
  7. package/dist/context.d.ts +32 -0
  8. package/dist/context.js +23 -0
  9. package/dist/credentials.d.ts +5 -5
  10. package/dist/credentials.js +10 -6
  11. package/dist/emulation/async.d.ts +90 -89
  12. package/dist/emulation/async.js +76 -75
  13. package/dist/emulation/dir.d.ts +3 -1
  14. package/dist/emulation/dir.js +6 -7
  15. package/dist/emulation/index.d.ts +1 -1
  16. package/dist/emulation/index.js +1 -1
  17. package/dist/emulation/promises.d.ts +50 -48
  18. package/dist/emulation/promises.js +78 -77
  19. package/dist/emulation/shared.d.ts +35 -8
  20. package/dist/emulation/shared.js +37 -11
  21. package/dist/emulation/sync.d.ts +63 -62
  22. package/dist/emulation/sync.js +72 -73
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/stats.d.ts +2 -1
  26. package/dist/stats.js +5 -4
  27. package/package.json +3 -5
  28. package/scripts/test.js +78 -17
  29. package/tests/assignment.ts +1 -1
  30. package/tests/common/context.test.ts +19 -0
  31. package/tests/{devices.test.ts → common/devices.test.ts} +3 -3
  32. package/tests/{handle.test.ts → common/handle.test.ts} +1 -1
  33. package/tests/common/mounts.test.ts +36 -0
  34. package/tests/{mutex.test.ts → common/mutex.test.ts} +3 -3
  35. package/tests/common/path.test.ts +34 -0
  36. package/tests/common.ts +4 -3
  37. package/tests/fs/dir.test.ts +11 -11
  38. package/tests/fs/directory.test.ts +17 -17
  39. package/tests/fs/errors.test.ts +29 -39
  40. package/tests/fs/watch.test.ts +2 -2
  41. package/tests/setup/context.ts +9 -0
  42. package/tests/setup/cow+fetch.ts +1 -1
  43. package/tests/setup/memory.ts +1 -1
  44. package/tests/{setup/common.ts → setup.ts} +6 -5
  45. package/src/backends/backend.ts +0 -161
  46. package/src/backends/fetch.ts +0 -180
  47. package/src/backends/file_index.ts +0 -206
  48. package/src/backends/memory.ts +0 -45
  49. package/src/backends/overlay.ts +0 -560
  50. package/src/backends/port/fs.ts +0 -329
  51. package/src/backends/port/readme.md +0 -54
  52. package/src/backends/port/rpc.ts +0 -167
  53. package/src/backends/readme.md +0 -3
  54. package/src/backends/store/fs.ts +0 -667
  55. package/src/backends/store/readme.md +0 -9
  56. package/src/backends/store/simple.ts +0 -154
  57. package/src/backends/store/store.ts +0 -189
  58. package/src/config.ts +0 -227
  59. package/src/credentials.ts +0 -49
  60. package/src/devices.ts +0 -521
  61. package/src/emulation/async.ts +0 -834
  62. package/src/emulation/cache.ts +0 -86
  63. package/src/emulation/config.ts +0 -21
  64. package/src/emulation/constants.ts +0 -182
  65. package/src/emulation/dir.ts +0 -138
  66. package/src/emulation/index.ts +0 -8
  67. package/src/emulation/path.ts +0 -440
  68. package/src/emulation/promises.ts +0 -1140
  69. package/src/emulation/shared.ts +0 -172
  70. package/src/emulation/streams.ts +0 -34
  71. package/src/emulation/sync.ts +0 -863
  72. package/src/emulation/watchers.ts +0 -194
  73. package/src/error.ts +0 -307
  74. package/src/file.ts +0 -631
  75. package/src/filesystem.ts +0 -174
  76. package/src/index.ts +0 -35
  77. package/src/inode.ts +0 -128
  78. package/src/mixins/async.ts +0 -230
  79. package/src/mixins/index.ts +0 -5
  80. package/src/mixins/mutexed.ts +0 -257
  81. package/src/mixins/readonly.ts +0 -96
  82. package/src/mixins/shared.ts +0 -25
  83. package/src/mixins/sync.ts +0 -58
  84. package/src/polyfills.ts +0 -21
  85. package/src/stats.ts +0 -405
  86. package/src/utils.ts +0 -276
  87. package/tests/mounts.test.ts +0 -18
  88. 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
- }