@zenfs/core 0.12.4 → 0.12.6

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.
@@ -7,6 +7,7 @@ export declare class Dirent implements _Dirent {
7
7
  protected stats: Stats;
8
8
  get name(): string;
9
9
  constructor(path: string, stats: Stats);
10
+ get parentPath(): string;
10
11
  isFile(): boolean;
11
12
  isDirectory(): boolean;
12
13
  isBlockDevice(): boolean;
@@ -10,6 +10,9 @@ export class Dirent {
10
10
  this.path = path;
11
11
  this.stats = stats;
12
12
  }
13
+ get parentPath() {
14
+ return this.path;
15
+ }
13
16
  isFile() {
14
17
  return this.stats.isFile();
15
18
  }
@@ -0,0 +1,27 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
+ /// <reference types="node" resolution-mode="require"/>
4
+ import { EventEmitter } from 'eventemitter3';
5
+ import type { EventEmitter as NodeEventEmitter } from 'node:events';
6
+ import type * as fs from 'node:fs';
7
+ declare class Watcher<TEvents extends Record<string, unknown[]> = Record<string, unknown[]>> extends EventEmitter<TEvents> implements NodeEventEmitter {
8
+ off<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: ((...args: any[]) => void) | undefined, context?: any, once?: boolean | undefined): this;
9
+ removeListener<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: ((...args: any[]) => void) | undefined, context?: any, once?: boolean | undefined): this;
10
+ setMaxListeners(): never;
11
+ getMaxListeners(): never;
12
+ prependListener(): never;
13
+ prependOnceListener(): never;
14
+ rawListeners(): never;
15
+ ref(): this;
16
+ unref(): this;
17
+ }
18
+ export declare class FSWatcher extends Watcher<{
19
+ change: [eventType: string, filename: string | Buffer];
20
+ close: [];
21
+ error: [error: Error];
22
+ }> implements fs.FSWatcher {
23
+ close(): void;
24
+ }
25
+ export declare class StatWatcher extends Watcher implements fs.StatWatcher {
26
+ }
27
+ export {};
@@ -0,0 +1,38 @@
1
+ import { EventEmitter } from 'eventemitter3';
2
+ import { ErrnoError } from '../error.js';
3
+ class Watcher extends EventEmitter {
4
+ /* eslint-disable @typescript-eslint/no-explicit-any */
5
+ off(event, fn, context, once) {
6
+ return super.off(event, fn, context, once);
7
+ }
8
+ removeListener(event, fn, context, once) {
9
+ return super.removeListener(event, fn, context, once);
10
+ }
11
+ /* eslint-enable @typescript-eslint/no-explicit-any */
12
+ setMaxListeners() {
13
+ throw ErrnoError.With('ENOTSUP');
14
+ }
15
+ getMaxListeners() {
16
+ throw ErrnoError.With('ENOTSUP');
17
+ }
18
+ prependListener() {
19
+ throw ErrnoError.With('ENOTSUP');
20
+ }
21
+ prependOnceListener() {
22
+ throw ErrnoError.With('ENOTSUP');
23
+ }
24
+ rawListeners() {
25
+ throw ErrnoError.With('ENOTSUP');
26
+ }
27
+ ref() {
28
+ return this;
29
+ }
30
+ unref() {
31
+ return this;
32
+ }
33
+ }
34
+ export class FSWatcher extends Watcher {
35
+ close() { }
36
+ }
37
+ export class StatWatcher extends Watcher {
38
+ }
package/dist/file.d.ts CHANGED
@@ -246,6 +246,7 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
246
246
  * Synchronous `stat`.
247
247
  */
248
248
  statSync(): Stats;
249
+ protected _truncate(length: number): void;
249
250
  /**
250
251
  * Asynchronous truncate.
251
252
  * @param length
@@ -256,6 +257,7 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
256
257
  * @param length
257
258
  */
258
259
  truncateSync(length: number): void;
260
+ protected _write(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
259
261
  /**
260
262
  * Write buffer to the file.
261
263
  * Note that it is unsafe to use fs.write multiple times on the same file
@@ -283,6 +285,7 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
283
285
  * @returns bytes written
284
286
  */
285
287
  writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
288
+ protected _read(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
286
289
  /**
287
290
  * Read data from the file.
288
291
  * @param buffer The buffer that the data will be
package/dist/file.js CHANGED
@@ -236,34 +236,63 @@ export class PreloadFile extends File {
236
236
  statSync() {
237
237
  return new Stats(this.stats);
238
238
  }
239
+ _truncate(length) {
240
+ this.dirty = true;
241
+ if (!isWriteable(this.flag)) {
242
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
243
+ }
244
+ this.stats.mtimeMs = Date.now();
245
+ if (length > this._buffer.length) {
246
+ const data = new Uint8Array(length - this._buffer.length);
247
+ // Write will set stats.size and handle syncing.
248
+ this.writeSync(data, 0, data.length, this._buffer.length);
249
+ return;
250
+ }
251
+ this.stats.size = length;
252
+ // Truncate.
253
+ this._buffer = this._buffer.slice(0, length);
254
+ }
239
255
  /**
240
256
  * Asynchronous truncate.
241
257
  * @param length
242
258
  */
243
259
  async truncate(length) {
244
- this.truncateSync(length);
245
- return this.sync();
260
+ this._truncate(length);
261
+ await this.sync();
246
262
  }
247
263
  /**
248
264
  * Synchronous truncate.
249
265
  * @param length
250
266
  */
251
267
  truncateSync(length) {
268
+ this._truncate(length);
269
+ this.syncSync();
270
+ }
271
+ _write(buffer, offset = 0, length = this.stats.size, position = this.position) {
252
272
  this.dirty = true;
253
273
  if (!isWriteable(this.flag)) {
254
274
  throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
255
275
  }
256
- this.stats.mtimeMs = Date.now();
257
- if (length > this._buffer.length) {
258
- const data = new Uint8Array(length - this._buffer.length);
259
- // Write will set stats.size and handle syncing.
260
- this.writeSync(data, 0, data.length, this._buffer.length);
261
- return;
276
+ const end = position + length;
277
+ if (end > this.stats.size) {
278
+ this.stats.size = end;
279
+ if (end > this._buffer.byteLength) {
280
+ if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength <= end) {
281
+ this._buffer.buffer.resize(end);
282
+ }
283
+ else {
284
+ // Extend the buffer!
285
+ const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
286
+ newBuffer.set(this._buffer);
287
+ this._buffer = newBuffer;
288
+ }
289
+ }
262
290
  }
263
- this.stats.size = length;
264
- // Truncate.
265
- this._buffer = this._buffer.slice(0, length);
266
- this.syncSync();
291
+ const slice = buffer.slice(offset, offset + length);
292
+ this._buffer.set(slice, position);
293
+ this.stats.mtimeMs = Date.now();
294
+ this.position = position + slice.byteLength;
295
+ return slice.byteLength;
267
296
  }
268
297
  /**
269
298
  * Write buffer to the file.
@@ -277,8 +306,8 @@ export class PreloadFile extends File {
277
306
  * data should be written. If position is null, the data will be written at
278
307
  * the current position.
279
308
  */
280
- async write(buffer, offset = 0, length = this.stats.size, position = this.position) {
281
- const bytesWritten = this.writeSync(buffer, offset, length, position);
309
+ async write(buffer, offset, length, position) {
310
+ const bytesWritten = this._write(buffer, offset, length, position);
282
311
  await this.sync();
283
312
  return bytesWritten;
284
313
  }
@@ -296,32 +325,29 @@ export class PreloadFile extends File {
296
325
  * @returns bytes written
297
326
  */
298
327
  writeSync(buffer, offset = 0, length = this.stats.size, position = this.position) {
299
- this.dirty = true;
300
- if (!isWriteable(this.flag)) {
301
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
328
+ const bytesWritten = this._write(buffer, offset, length, position);
329
+ this.syncSync();
330
+ return bytesWritten;
331
+ }
332
+ _read(buffer, offset = 0, length = this.stats.size, position) {
333
+ if (!isReadable(this.flag)) {
334
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
302
335
  }
303
- const end = position + length;
336
+ this.dirty = true;
337
+ position ?? (position = this.position);
338
+ let end = position + length;
304
339
  if (end > this.stats.size) {
305
- this.stats.size = end;
306
- if (end > this._buffer.byteLength) {
307
- if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength <= end) {
308
- this._buffer.buffer.resize(end);
309
- }
310
- else {
311
- // Extend the buffer!
312
- const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
313
- newBuffer.set(this._buffer);
314
- this._buffer = newBuffer;
315
- }
316
- }
340
+ end = position + Math.max(this.stats.size - position, 0);
317
341
  }
318
- const slice = buffer.slice(offset, offset + length);
319
- this._buffer.set(slice, position);
320
- const bytesWritten = slice.byteLength;
321
- this.stats.mtimeMs = Date.now();
322
- this.position = position + bytesWritten;
323
- this.syncSync();
324
- return bytesWritten;
342
+ this.stats.atimeMs = Date.now();
343
+ this._position = end;
344
+ const bytesRead = end - position;
345
+ if (bytesRead == 0) {
346
+ // No copy/read. Return immediatly for better performance
347
+ return bytesRead;
348
+ }
349
+ new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
350
+ return bytesRead;
325
351
  }
326
352
  /**
327
353
  * Read data from the file.
@@ -334,8 +360,10 @@ export class PreloadFile extends File {
334
360
  * in the file. If position is null, data will be read from the current file
335
361
  * position.
336
362
  */
337
- async read(buffer, offset = 0, length = this.stats.size, position = 0) {
338
- return { bytesRead: this.readSync(buffer, offset, length, position), buffer };
363
+ async read(buffer, offset, length, position) {
364
+ const bytesRead = this._read(buffer, offset, length, position);
365
+ await this.sync();
366
+ return { bytesRead, buffer };
339
367
  }
340
368
  /**
341
369
  * Read data from the file.
@@ -348,25 +376,9 @@ export class PreloadFile extends File {
348
376
  * position.
349
377
  * @returns number of bytes written
350
378
  */
351
- readSync(buffer, offset = 0, length = this.stats.size, position) {
352
- if (!isReadable(this.flag)) {
353
- throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
354
- }
355
- this.dirty = true;
356
- position ?? (position = this.position);
357
- let end = position + length;
358
- if (end > this.stats.size) {
359
- end = position + Math.max(this.stats.size - position, 0);
360
- }
361
- this.stats.atimeMs = Date.now();
362
- this._position = end;
363
- const bytesRead = end - position;
364
- this.syncSync();
365
- if (bytesRead == 0) {
366
- // No copy/read. Return immediatly for better performance
367
- return bytesRead;
368
- }
369
- new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
379
+ readSync(buffer, offset, length, position) {
380
+ const bytesRead = this._read(buffer, offset, length, position);
381
+ this.statSync();
370
382
  return bytesRead;
371
383
  }
372
384
  /**
@@ -374,7 +386,9 @@ export class PreloadFile extends File {
374
386
  * @param mode the mode
375
387
  */
376
388
  async chmod(mode) {
377
- this.chmodSync(mode);
389
+ this.dirty = true;
390
+ this.stats.chmod(mode);
391
+ await this.sync();
378
392
  }
379
393
  /**
380
394
  * Synchronous `fchmod`.
@@ -391,7 +405,9 @@ export class PreloadFile extends File {
391
405
  * @param gid
392
406
  */
393
407
  async chown(uid, gid) {
394
- this.chownSync(uid, gid);
408
+ this.dirty = true;
409
+ this.stats.chown(uid, gid);
410
+ await this.sync();
395
411
  }
396
412
  /**
397
413
  * Synchronous `fchown`.
@@ -404,7 +420,10 @@ export class PreloadFile extends File {
404
420
  this.syncSync();
405
421
  }
406
422
  async utimes(atime, mtime) {
407
- this.utimesSync(atime, mtime);
423
+ this.dirty = true;
424
+ this.stats.atime = atime;
425
+ this.stats.mtime = mtime;
426
+ await this.sync();
408
427
  }
409
428
  utimesSync(atime, mtime) {
410
429
  this.dirty = true;
@@ -412,10 +431,10 @@ export class PreloadFile extends File {
412
431
  this.stats.mtime = mtime;
413
432
  this.syncSync();
414
433
  }
415
- _setType(type) {
434
+ async _setType(type) {
416
435
  this.dirty = true;
417
436
  this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
418
- return this.sync();
437
+ await this.sync();
419
438
  }
420
439
  _setTypeSync(type) {
421
440
  this.dirty = true;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "0.12.4",
3
+ "version": "0.12.6",
4
4
  "description": "A filesystem in your browser",
5
5
  "main": "dist/index.js",
6
- "types": "src/index.ts",
6
+ "types": "dist/index.d.ts",
7
7
  "keywords": [
8
8
  "filesystem",
9
9
  "node",
@@ -46,9 +46,10 @@
46
46
  "prepublishOnly": "npm run build"
47
47
  },
48
48
  "dependencies": {
49
- "@types/node": "^20.12.5",
49
+ "@types/node": "^20.12.12",
50
50
  "@types/readable-stream": "^4.0.10",
51
51
  "buffer": "^6.0.3",
52
+ "eventemitter3": "^5.0.1",
52
53
  "minimatch": "^9.0.3",
53
54
  "readable-stream": "^4.5.2",
54
55
  "utilium": "^0.4.0"
@@ -16,6 +16,10 @@ export class Dirent implements _Dirent {
16
16
  protected stats: Stats
17
17
  ) {}
18
18
 
19
+ get parentPath(): string {
20
+ return this.path;
21
+ }
22
+
19
23
  isFile(): boolean {
20
24
  return this.stats.isFile();
21
25
  }
@@ -0,0 +1,57 @@
1
+ import { EventEmitter } from 'eventemitter3';
2
+ import type { EventEmitter as NodeEventEmitter } from 'node:events';
3
+ import type * as fs from 'node:fs';
4
+ import { ErrnoError } from '../error.js';
5
+
6
+ class Watcher<TEvents extends Record<string, unknown[]> = Record<string, unknown[]>> extends EventEmitter<TEvents> implements NodeEventEmitter {
7
+ /* eslint-disable @typescript-eslint/no-explicit-any */
8
+ public off<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: ((...args: any[]) => void) | undefined, context?: any, once?: boolean | undefined): this {
9
+ return super.off<T>(event, fn as EventEmitter.EventListener<TEvents, T>, context, once);
10
+ }
11
+
12
+ public removeListener<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: ((...args: any[]) => void) | undefined, context?: any, once?: boolean | undefined): this {
13
+ return super.removeListener<T>(event, fn as EventEmitter.EventListener<TEvents, T>, context, once);
14
+ }
15
+ /* eslint-enable @typescript-eslint/no-explicit-any */
16
+
17
+ public setMaxListeners(): never {
18
+ throw ErrnoError.With('ENOTSUP');
19
+ }
20
+
21
+ public getMaxListeners(): never {
22
+ throw ErrnoError.With('ENOTSUP');
23
+ }
24
+
25
+ public prependListener(): never {
26
+ throw ErrnoError.With('ENOTSUP');
27
+ }
28
+
29
+ public prependOnceListener(): never {
30
+ throw ErrnoError.With('ENOTSUP');
31
+ }
32
+
33
+ public rawListeners(): never {
34
+ throw ErrnoError.With('ENOTSUP');
35
+ }
36
+
37
+ public ref(): this {
38
+ return this;
39
+ }
40
+
41
+ public unref(): this {
42
+ return this;
43
+ }
44
+ }
45
+
46
+ export class FSWatcher
47
+ extends Watcher<{
48
+ change: [eventType: string, filename: string | Buffer];
49
+ close: [];
50
+ error: [error: Error];
51
+ }>
52
+ implements fs.FSWatcher
53
+ {
54
+ public close(): void {}
55
+ }
56
+
57
+ export class StatWatcher extends Watcher implements fs.StatWatcher {}
package/src/file.ts CHANGED
@@ -439,13 +439,30 @@ export class PreloadFile<FS extends FileSystem> extends File {
439
439
  return new Stats(this.stats);
440
440
  }
441
441
 
442
+ protected _truncate(length: number): void {
443
+ this.dirty = true;
444
+ if (!isWriteable(this.flag)) {
445
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
446
+ }
447
+ this.stats.mtimeMs = Date.now();
448
+ if (length > this._buffer.length) {
449
+ const data = new Uint8Array(length - this._buffer.length);
450
+ // Write will set stats.size and handle syncing.
451
+ this.writeSync(data, 0, data.length, this._buffer.length);
452
+ return;
453
+ }
454
+ this.stats.size = length;
455
+ // Truncate.
456
+ this._buffer = this._buffer.slice(0, length);
457
+ }
458
+
442
459
  /**
443
460
  * Asynchronous truncate.
444
461
  * @param length
445
462
  */
446
463
  public async truncate(length: number): Promise<void> {
447
- this.truncateSync(length);
448
- return this.sync();
464
+ this._truncate(length);
465
+ await this.sync();
449
466
  }
450
467
 
451
468
  /**
@@ -453,21 +470,35 @@ export class PreloadFile<FS extends FileSystem> extends File {
453
470
  * @param length
454
471
  */
455
472
  public truncateSync(length: number): void {
473
+ this._truncate(length);
474
+ this.syncSync();
475
+ }
476
+
477
+ protected _write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
456
478
  this.dirty = true;
457
479
  if (!isWriteable(this.flag)) {
458
480
  throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
459
481
  }
460
- this.stats.mtimeMs = Date.now();
461
- if (length > this._buffer.length) {
462
- const data = new Uint8Array(length - this._buffer.length);
463
- // Write will set stats.size and handle syncing.
464
- this.writeSync(data, 0, data.length, this._buffer.length);
465
- return;
482
+ const end = position + length;
483
+
484
+ if (end > this.stats.size) {
485
+ this.stats.size = end;
486
+ if (end > this._buffer.byteLength) {
487
+ if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength! <= end) {
488
+ this._buffer.buffer.resize(end);
489
+ } else {
490
+ // Extend the buffer!
491
+ const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
492
+ newBuffer.set(this._buffer);
493
+ this._buffer = newBuffer;
494
+ }
495
+ }
466
496
  }
467
- this.stats.size = length;
468
- // Truncate.
469
- this._buffer = this._buffer.slice(0, length);
470
- this.syncSync();
497
+ const slice = buffer.slice(offset, offset + length);
498
+ this._buffer.set(slice, position);
499
+ this.stats.mtimeMs = Date.now();
500
+ this.position = position + slice.byteLength;
501
+ return slice.byteLength;
471
502
  }
472
503
 
473
504
  /**
@@ -482,8 +513,8 @@ export class PreloadFile<FS extends FileSystem> extends File {
482
513
  * data should be written. If position is null, the data will be written at
483
514
  * the current position.
484
515
  */
485
- public async write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): Promise<number> {
486
- const bytesWritten = this.writeSync(buffer, offset, length, position);
516
+ public async write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number> {
517
+ const bytesWritten = this._write(buffer, offset, length, position);
487
518
  await this.sync();
488
519
  return bytesWritten;
489
520
  }
@@ -502,32 +533,30 @@ export class PreloadFile<FS extends FileSystem> extends File {
502
533
  * @returns bytes written
503
534
  */
504
535
  public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
505
- this.dirty = true;
506
- if (!isWriteable(this.flag)) {
507
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
508
- }
509
- const end = position + length;
536
+ const bytesWritten = this._write(buffer, offset, length, position);
537
+ this.syncSync();
538
+ return bytesWritten;
539
+ }
510
540
 
541
+ protected _read(buffer: ArrayBufferView, offset: number = 0, length: number = this.stats.size, position?: number): number {
542
+ if (!isReadable(this.flag)) {
543
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
544
+ }
545
+ this.dirty = true;
546
+ position ??= this.position;
547
+ let end = position + length;
511
548
  if (end > this.stats.size) {
512
- this.stats.size = end;
513
- if (end > this._buffer.byteLength) {
514
- if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength! <= end) {
515
- this._buffer.buffer.resize(end);
516
- } else {
517
- // Extend the buffer!
518
- const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
519
- newBuffer.set(this._buffer);
520
- this._buffer = newBuffer;
521
- }
522
- }
549
+ end = position + Math.max(this.stats.size - position, 0);
523
550
  }
524
- const slice = buffer.slice(offset, offset + length);
525
- this._buffer.set(slice, position);
526
- const bytesWritten = slice.byteLength;
527
- this.stats.mtimeMs = Date.now();
528
- this.position = position + bytesWritten;
529
- this.syncSync();
530
- return bytesWritten;
551
+ this.stats.atimeMs = Date.now();
552
+ this._position = end;
553
+ const bytesRead = end - position;
554
+ if (bytesRead == 0) {
555
+ // No copy/read. Return immediatly for better performance
556
+ return bytesRead;
557
+ }
558
+ new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
559
+ return bytesRead;
531
560
  }
532
561
 
533
562
  /**
@@ -541,13 +570,10 @@ export class PreloadFile<FS extends FileSystem> extends File {
541
570
  * in the file. If position is null, data will be read from the current file
542
571
  * position.
543
572
  */
544
- public async read<TBuffer extends ArrayBufferView>(
545
- buffer: TBuffer,
546
- offset: number = 0,
547
- length: number = this.stats.size,
548
- position: number = 0
549
- ): Promise<{ bytesRead: number; buffer: TBuffer }> {
550
- return { bytesRead: this.readSync(buffer, offset, length, position), buffer };
573
+ public async read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{ bytesRead: number; buffer: TBuffer }> {
574
+ const bytesRead = this._read(buffer, offset, length, position);
575
+ await this.sync();
576
+ return { bytesRead, buffer };
551
577
  }
552
578
 
553
579
  /**
@@ -561,25 +587,9 @@ export class PreloadFile<FS extends FileSystem> extends File {
561
587
  * position.
562
588
  * @returns number of bytes written
563
589
  */
564
- public readSync(buffer: ArrayBufferView, offset: number = 0, length: number = this.stats.size, position?: number): number {
565
- if (!isReadable(this.flag)) {
566
- throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
567
- }
568
- this.dirty = true;
569
- position ??= this.position;
570
- let end = position + length;
571
- if (end > this.stats.size) {
572
- end = position + Math.max(this.stats.size - position, 0);
573
- }
574
- this.stats.atimeMs = Date.now();
575
- this._position = end;
576
- const bytesRead = end - position;
577
- this.syncSync();
578
- if (bytesRead == 0) {
579
- // No copy/read. Return immediatly for better performance
580
- return bytesRead;
581
- }
582
- new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
590
+ public readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number {
591
+ const bytesRead = this._read(buffer, offset, length, position);
592
+ this.statSync();
583
593
  return bytesRead;
584
594
  }
585
595
 
@@ -588,7 +598,9 @@ export class PreloadFile<FS extends FileSystem> extends File {
588
598
  * @param mode the mode
589
599
  */
590
600
  public async chmod(mode: number): Promise<void> {
591
- this.chmodSync(mode);
601
+ this.dirty = true;
602
+ this.stats.chmod(mode);
603
+ await this.sync();
592
604
  }
593
605
 
594
606
  /**
@@ -607,7 +619,9 @@ export class PreloadFile<FS extends FileSystem> extends File {
607
619
  * @param gid
608
620
  */
609
621
  public async chown(uid: number, gid: number): Promise<void> {
610
- this.chownSync(uid, gid);
622
+ this.dirty = true;
623
+ this.stats.chown(uid, gid);
624
+ await this.sync();
611
625
  }
612
626
 
613
627
  /**
@@ -622,7 +636,10 @@ export class PreloadFile<FS extends FileSystem> extends File {
622
636
  }
623
637
 
624
638
  public async utimes(atime: Date, mtime: Date): Promise<void> {
625
- this.utimesSync(atime, mtime);
639
+ this.dirty = true;
640
+ this.stats.atime = atime;
641
+ this.stats.mtime = mtime;
642
+ await this.sync();
626
643
  }
627
644
 
628
645
  public utimesSync(atime: Date, mtime: Date): void {
@@ -632,10 +649,10 @@ export class PreloadFile<FS extends FileSystem> extends File {
632
649
  this.syncSync();
633
650
  }
634
651
 
635
- public _setType(type: FileType): Promise<void> {
652
+ public async _setType(type: FileType): Promise<void> {
636
653
  this.dirty = true;
637
654
  this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
638
- return this.sync();
655
+ await this.sync();
639
656
  }
640
657
 
641
658
  public _setTypeSync(type: FileType): void {