@zenfs/core 1.2.4 → 1.2.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.
package/dist/config.d.ts CHANGED
@@ -61,6 +61,15 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
61
61
  * @default false
62
62
  */
63
63
  disableUpdateOnRead: boolean;
64
+ /**
65
+ * If true, files will only sync to the file system when closed.
66
+ *
67
+ * This can increase performance.
68
+ * @experimental
69
+ * @overrides `disableUpdateOnRead`
70
+ * @default false
71
+ */
72
+ onlySyncOnClose: boolean;
64
73
  }
65
74
  /**
66
75
  * Configures ZenFS with single mount point /
package/dist/config.js CHANGED
@@ -70,7 +70,8 @@ export async function configure(configuration) {
70
70
  Object.assign(credentials, { uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
71
71
  cache.setEnabled(configuration.cacheStats ?? false);
72
72
  config.checkAccess = !configuration.disableAccessChecks;
73
- config.updateOnRead = !configuration.disableUpdateOnRead;
73
+ config.syncOnRead = !configuration.onlySyncOnClose || !configuration.disableUpdateOnRead;
74
+ config.syncOnWrite = !configuration.onlySyncOnClose;
74
75
  if (configuration.addDevices) {
75
76
  const devfs = new DeviceFS();
76
77
  devfs.createDevice('/null', nullDevice);
@@ -6,5 +6,13 @@ export declare const config: {
6
6
  /**
7
7
  * Whether to sync atime updates immediately when reading from a file
8
8
  */
9
- updateOnRead: boolean;
9
+ syncOnRead: boolean;
10
+ /**
11
+ * Whether to immediately sync when files are written to
12
+ */
13
+ syncOnWrite: boolean;
14
+ /**
15
+ * If a file's buffer is not large enough to store content when writing and the buffer can't be resized, reuse the buffer passed to write()
16
+ */
17
+ unsafeBufferReplace: boolean;
10
18
  };
@@ -6,5 +6,13 @@ export const config = {
6
6
  /**
7
7
  * Whether to sync atime updates immediately when reading from a file
8
8
  */
9
- updateOnRead: true,
9
+ syncOnRead: true,
10
+ /**
11
+ * Whether to immediately sync when files are written to
12
+ */
13
+ syncOnWrite: true,
14
+ /**
15
+ * If a file's buffer is not large enough to store content when writing and the buffer can't be resized, reuse the buffer passed to write()
16
+ */
17
+ unsafeBufferReplace: false,
10
18
  };
@@ -485,7 +485,6 @@ async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
485
485
  */
486
486
  if (isTruncating(flag)) {
487
487
  await handle.truncate(0);
488
- await handle.sync();
489
488
  }
490
489
  return handle;
491
490
  }
@@ -738,24 +737,17 @@ link;
738
737
  * @param type can be either `'dir'` or `'file'` (default is `'file'`)
739
738
  */
740
739
  export async function symlink(target, path, type = 'file') {
741
- if (!['file', 'dir', 'junction'].includes(type)) {
742
- throw new ErrnoError(Errno.EINVAL, 'Invalid symlink type: ' + type);
743
- }
744
- if (await exists(path)) {
745
- throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
746
- }
747
- await writeFile(path, target.toString());
748
- const handle = await _open(path, 'r+', 0o644, false);
749
- await handle.file._setType(constants.S_IFLNK);
750
- }
751
- symlink;
752
- export async function readlink(path, options) {
753
740
  const env_5 = { stack: [], error: void 0, hasError: false };
754
741
  try {
755
- const handle = __addDisposableResource(env_5, await _open(normalizePath(path), 'r', 0o644, false), true);
756
- const value = await handle.readFile();
757
- const encoding = typeof options == 'object' ? options?.encoding : options;
758
- return encoding == 'buffer' ? value : value.toString(encoding);
742
+ if (!['file', 'dir', 'junction'].includes(type)) {
743
+ throw new ErrnoError(Errno.EINVAL, 'Invalid symlink type: ' + type);
744
+ }
745
+ if (await exists(path)) {
746
+ throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
747
+ }
748
+ const handle = __addDisposableResource(env_5, await _open(path, 'w+', 0o644, false), true);
749
+ await handle.writeFile(target.toString());
750
+ await handle.file._setType(constants.S_IFLNK);
759
751
  }
760
752
  catch (e_5) {
761
753
  env_5.error = e_5;
@@ -767,13 +759,14 @@ export async function readlink(path, options) {
767
759
  await result_5;
768
760
  }
769
761
  }
770
- readlink;
771
- // PROPERTY OPERATIONS
772
- export async function chown(path, uid, gid) {
762
+ symlink;
763
+ export async function readlink(path, options) {
773
764
  const env_6 = { stack: [], error: void 0, hasError: false };
774
765
  try {
775
- const handle = __addDisposableResource(env_6, await open(path, 'r+'), true);
776
- await handle.chown(uid, gid);
766
+ const handle = __addDisposableResource(env_6, await _open(normalizePath(path), 'r', 0o644, false), true);
767
+ const value = await handle.readFile();
768
+ const encoding = typeof options == 'object' ? options?.encoding : options;
769
+ return encoding == 'buffer' ? value : value.toString(encoding);
777
770
  }
778
771
  catch (e_6) {
779
772
  env_6.error = e_6;
@@ -785,11 +778,12 @@ export async function chown(path, uid, gid) {
785
778
  await result_6;
786
779
  }
787
780
  }
788
- chown;
789
- export async function lchown(path, uid, gid) {
781
+ readlink;
782
+ // PROPERTY OPERATIONS
783
+ export async function chown(path, uid, gid) {
790
784
  const env_7 = { stack: [], error: void 0, hasError: false };
791
785
  try {
792
- const handle = __addDisposableResource(env_7, await _open(path, 'r+', 0o644, false), true);
786
+ const handle = __addDisposableResource(env_7, await open(path, 'r+'), true);
793
787
  await handle.chown(uid, gid);
794
788
  }
795
789
  catch (e_7) {
@@ -802,12 +796,12 @@ export async function lchown(path, uid, gid) {
802
796
  await result_7;
803
797
  }
804
798
  }
805
- lchown;
806
- export async function chmod(path, mode) {
799
+ chown;
800
+ export async function lchown(path, uid, gid) {
807
801
  const env_8 = { stack: [], error: void 0, hasError: false };
808
802
  try {
809
- const handle = __addDisposableResource(env_8, await open(path, 'r+'), true);
810
- await handle.chmod(mode);
803
+ const handle = __addDisposableResource(env_8, await _open(path, 'r+', 0o644, false), true);
804
+ await handle.chown(uid, gid);
811
805
  }
812
806
  catch (e_8) {
813
807
  env_8.error = e_8;
@@ -819,11 +813,11 @@ export async function chmod(path, mode) {
819
813
  await result_8;
820
814
  }
821
815
  }
822
- chmod;
823
- export async function lchmod(path, mode) {
816
+ lchown;
817
+ export async function chmod(path, mode) {
824
818
  const env_9 = { stack: [], error: void 0, hasError: false };
825
819
  try {
826
- const handle = __addDisposableResource(env_9, await _open(path, 'r+', 0o644, false), true);
820
+ const handle = __addDisposableResource(env_9, await open(path, 'r+'), true);
827
821
  await handle.chmod(mode);
828
822
  }
829
823
  catch (e_9) {
@@ -836,15 +830,12 @@ export async function lchmod(path, mode) {
836
830
  await result_9;
837
831
  }
838
832
  }
839
- lchmod;
840
- /**
841
- * Change file timestamps of the file referenced by the supplied path.
842
- */
843
- export async function utimes(path, atime, mtime) {
833
+ chmod;
834
+ export async function lchmod(path, mode) {
844
835
  const env_10 = { stack: [], error: void 0, hasError: false };
845
836
  try {
846
- const handle = __addDisposableResource(env_10, await open(path, 'r+'), true);
847
- await handle.utimes(atime, mtime);
837
+ const handle = __addDisposableResource(env_10, await _open(path, 'r+', 0o644, false), true);
838
+ await handle.chmod(mode);
848
839
  }
849
840
  catch (e_10) {
850
841
  env_10.error = e_10;
@@ -856,15 +847,15 @@ export async function utimes(path, atime, mtime) {
856
847
  await result_10;
857
848
  }
858
849
  }
859
- utimes;
850
+ lchmod;
860
851
  /**
861
852
  * Change file timestamps of the file referenced by the supplied path.
862
853
  */
863
- export async function lutimes(path, atime, mtime) {
854
+ export async function utimes(path, atime, mtime) {
864
855
  const env_11 = { stack: [], error: void 0, hasError: false };
865
856
  try {
866
- const handle = __addDisposableResource(env_11, await _open(path, 'r+', 0o644, false), true);
867
- await handle.utimes(new Date(atime), new Date(mtime));
857
+ const handle = __addDisposableResource(env_11, await open(path, 'r+'), true);
858
+ await handle.utimes(atime, mtime);
868
859
  }
869
860
  catch (e_11) {
870
861
  env_11.error = e_11;
@@ -876,6 +867,26 @@ export async function lutimes(path, atime, mtime) {
876
867
  await result_11;
877
868
  }
878
869
  }
870
+ utimes;
871
+ /**
872
+ * Change file timestamps of the file referenced by the supplied path.
873
+ */
874
+ export async function lutimes(path, atime, mtime) {
875
+ const env_12 = { stack: [], error: void 0, hasError: false };
876
+ try {
877
+ const handle = __addDisposableResource(env_12, await _open(path, 'r+', 0o644, false), true);
878
+ await handle.utimes(new Date(atime), new Date(mtime));
879
+ }
880
+ catch (e_12) {
881
+ env_12.error = e_12;
882
+ env_12.hasError = true;
883
+ }
884
+ finally {
885
+ const result_12 = __disposeResources(env_12);
886
+ if (result_12)
887
+ await result_12;
888
+ }
889
+ }
879
890
  lutimes;
880
891
  export async function realpath(path, options) {
881
892
  path = normalizePath(path);
@@ -193,7 +193,6 @@ function _openSync(path, _flag, _mode, resolveSymlinks = true) {
193
193
  const file = fs.openFileSync(resolved, flag);
194
194
  if (isTruncating(flag)) {
195
195
  file.truncateSync(0);
196
- file.syncSync();
197
196
  }
198
197
  return file;
199
198
  }
package/dist/file.js CHANGED
@@ -289,27 +289,33 @@ export class PreloadFile extends File {
289
289
  }
290
290
  async truncate(length) {
291
291
  this._truncate(length);
292
- await this.sync();
292
+ if (config.syncOnWrite)
293
+ await this.sync();
293
294
  }
294
295
  truncateSync(length) {
295
296
  this._truncate(length);
296
- this.syncSync();
297
+ if (config.syncOnWrite)
298
+ this.syncSync();
297
299
  }
298
300
  _write(buffer, offset = 0, length = this.stats.size, position = this.position) {
299
301
  if (this.closed) {
300
302
  throw ErrnoError.With('EBADF', this.path, 'File.write');
301
303
  }
302
- this.dirty = true;
303
304
  if (!isWriteable(this.flag)) {
304
305
  throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
305
306
  }
307
+ this.dirty = true;
306
308
  const end = position + length;
309
+ const slice = buffer.slice(offset, offset + length);
307
310
  if (end > this.stats.size) {
308
311
  this.stats.size = end;
309
312
  if (end > this._buffer.byteLength) {
310
313
  if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength <= end) {
311
314
  this._buffer.buffer.resize(end);
312
315
  }
316
+ else if (config.unsafeBufferReplace) {
317
+ this._buffer = slice;
318
+ }
313
319
  else {
314
320
  // Extend the buffer!
315
321
  const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
@@ -318,7 +324,6 @@ export class PreloadFile extends File {
318
324
  }
319
325
  }
320
326
  }
321
- const slice = buffer.slice(offset, offset + length);
322
327
  this._buffer.set(slice, position);
323
328
  this.stats.mtimeMs = Date.now();
324
329
  this.position = position + slice.byteLength;
@@ -334,7 +339,8 @@ export class PreloadFile extends File {
334
339
  */
335
340
  async write(buffer, offset, length, position) {
336
341
  const bytesWritten = this._write(buffer, offset, length, position);
337
- await this.sync();
342
+ if (config.syncOnWrite)
343
+ await this.sync();
338
344
  return bytesWritten;
339
345
  }
340
346
  /**
@@ -348,7 +354,8 @@ export class PreloadFile extends File {
348
354
  */
349
355
  writeSync(buffer, offset = 0, length = this.stats.size, position = this.position) {
350
356
  const bytesWritten = this._write(buffer, offset, length, position);
351
- this.syncSync();
357
+ if (config.syncOnWrite)
358
+ this.syncSync();
352
359
  return bytesWritten;
353
360
  }
354
361
  _read(buffer, offset = 0, length = this.stats.size, position) {
@@ -358,10 +365,8 @@ export class PreloadFile extends File {
358
365
  if (!isReadable(this.flag)) {
359
366
  throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
360
367
  }
361
- if (config.updateOnRead) {
362
- this.dirty = true;
363
- this.stats.atimeMs = Date.now();
364
- }
368
+ this.dirty = true;
369
+ this.stats.atimeMs = Date.now();
365
370
  position ?? (position = this.position);
366
371
  let end = position + length;
367
372
  if (end > this.stats.size) {
@@ -370,7 +375,7 @@ export class PreloadFile extends File {
370
375
  this._position = end;
371
376
  const bytesRead = end - position;
372
377
  if (bytesRead == 0) {
373
- // No copy/read. Return immediatly for better performance
378
+ // No copy/read. Return immediately for better performance
374
379
  return bytesRead;
375
380
  }
376
381
  new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
@@ -386,7 +391,8 @@ export class PreloadFile extends File {
386
391
  */
387
392
  async read(buffer, offset, length, position) {
388
393
  const bytesRead = this._read(buffer, offset, length, position);
389
- await this.sync();
394
+ if (config.syncOnRead)
395
+ await this.sync();
390
396
  return { bytesRead, buffer };
391
397
  }
392
398
  /**
@@ -400,7 +406,8 @@ export class PreloadFile extends File {
400
406
  */
401
407
  readSync(buffer, offset, length, position) {
402
408
  const bytesRead = this._read(buffer, offset, length, position);
403
- this.syncSync();
409
+ if (config.syncOnRead)
410
+ this.syncSync();
404
411
  return bytesRead;
405
412
  }
406
413
  async chmod(mode) {
@@ -409,7 +416,8 @@ export class PreloadFile extends File {
409
416
  }
410
417
  this.dirty = true;
411
418
  this.stats.chmod(mode);
412
- await this.sync();
419
+ if (config.syncOnWrite)
420
+ await this.sync();
413
421
  }
414
422
  chmodSync(mode) {
415
423
  if (this.closed) {
@@ -417,7 +425,8 @@ export class PreloadFile extends File {
417
425
  }
418
426
  this.dirty = true;
419
427
  this.stats.chmod(mode);
420
- this.syncSync();
428
+ if (config.syncOnWrite)
429
+ this.syncSync();
421
430
  }
422
431
  async chown(uid, gid) {
423
432
  if (this.closed) {
@@ -425,7 +434,8 @@ export class PreloadFile extends File {
425
434
  }
426
435
  this.dirty = true;
427
436
  this.stats.chown(uid, gid);
428
- await this.sync();
437
+ if (config.syncOnWrite)
438
+ await this.sync();
429
439
  }
430
440
  chownSync(uid, gid) {
431
441
  if (this.closed) {
@@ -433,7 +443,8 @@ export class PreloadFile extends File {
433
443
  }
434
444
  this.dirty = true;
435
445
  this.stats.chown(uid, gid);
436
- this.syncSync();
446
+ if (config.syncOnWrite)
447
+ this.syncSync();
437
448
  }
438
449
  async utimes(atime, mtime) {
439
450
  if (this.closed) {
@@ -442,7 +453,8 @@ export class PreloadFile extends File {
442
453
  this.dirty = true;
443
454
  this.stats.atime = atime;
444
455
  this.stats.mtime = mtime;
445
- await this.sync();
456
+ if (config.syncOnWrite)
457
+ await this.sync();
446
458
  }
447
459
  utimesSync(atime, mtime) {
448
460
  if (this.closed) {
@@ -451,7 +463,8 @@ export class PreloadFile extends File {
451
463
  this.dirty = true;
452
464
  this.stats.atime = atime;
453
465
  this.stats.mtime = mtime;
454
- this.syncSync();
466
+ if (config.syncOnWrite)
467
+ this.syncSync();
455
468
  }
456
469
  async _setType(type) {
457
470
  if (this.closed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
package/src/config.ts CHANGED
@@ -126,6 +126,16 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
126
126
  * @default false
127
127
  */
128
128
  disableUpdateOnRead: boolean;
129
+
130
+ /**
131
+ * If true, files will only sync to the file system when closed.
132
+ *
133
+ * This can increase performance.
134
+ * @experimental
135
+ * @overrides `disableUpdateOnRead`
136
+ * @default false
137
+ */
138
+ onlySyncOnClose: boolean;
129
139
  }
130
140
 
131
141
  /**
@@ -153,7 +163,8 @@ export async function configure<T extends ConfigMounts>(configuration: Partial<C
153
163
 
154
164
  cache.setEnabled(configuration.cacheStats ?? false);
155
165
  config.checkAccess = !configuration.disableAccessChecks;
156
- config.updateOnRead = !configuration.disableUpdateOnRead;
166
+ config.syncOnRead = !configuration.onlySyncOnClose || !configuration.disableUpdateOnRead;
167
+ config.syncOnWrite = !configuration.onlySyncOnClose;
157
168
 
158
169
  if (configuration.addDevices) {
159
170
  const devfs = new DeviceFS();
@@ -7,5 +7,15 @@ export const config = {
7
7
  /**
8
8
  * Whether to sync atime updates immediately when reading from a file
9
9
  */
10
- updateOnRead: true,
10
+ syncOnRead: true,
11
+
12
+ /**
13
+ * Whether to immediately sync when files are written to
14
+ */
15
+ syncOnWrite: true,
16
+
17
+ /**
18
+ * If a file's buffer is not large enough to store content when writing and the buffer can't be resized, reuse the buffer passed to write()
19
+ */
20
+ unsafeBufferReplace: false,
11
21
  };
@@ -529,7 +529,6 @@ async function _open(path: fs.PathLike, _flag: fs.OpenMode, _mode: fs.Mode = 0o6
529
529
  */
530
530
  if (isTruncating(flag)) {
531
531
  await handle.truncate(0);
532
- await handle.sync();
533
532
  }
534
533
 
535
534
  return handle;
@@ -832,8 +831,8 @@ export async function symlink(target: fs.PathLike, path: fs.PathLike, type: fs.s
832
831
  throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
833
832
  }
834
833
 
835
- await writeFile(path, target.toString());
836
- const handle = await _open(path, 'r+', 0o644, false);
834
+ await using handle = await _open(path, 'w+', 0o644, false);
835
+ await handle.writeFile(target.toString());
837
836
  await handle.file._setType(constants.S_IFLNK);
838
837
  }
839
838
  symlink satisfies typeof promises.symlink;
@@ -159,7 +159,6 @@ function _openSync(path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | null
159
159
 
160
160
  if (isTruncating(flag)) {
161
161
  file.truncateSync(0);
162
- file.syncSync();
163
162
  }
164
163
 
165
164
  return file;
package/src/file.ts CHANGED
@@ -441,29 +441,34 @@ export class PreloadFile<FS extends FileSystem> extends File {
441
441
 
442
442
  public async truncate(length: number): Promise<void> {
443
443
  this._truncate(length);
444
- await this.sync();
444
+ if (config.syncOnWrite) await this.sync();
445
445
  }
446
446
 
447
447
  public truncateSync(length: number): void {
448
448
  this._truncate(length);
449
- this.syncSync();
449
+ if (config.syncOnWrite) this.syncSync();
450
450
  }
451
451
 
452
452
  protected _write(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
453
453
  if (this.closed) {
454
454
  throw ErrnoError.With('EBADF', this.path, 'File.write');
455
455
  }
456
- this.dirty = true;
456
+
457
457
  if (!isWriteable(this.flag)) {
458
458
  throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
459
459
  }
460
+
461
+ this.dirty = true;
460
462
  const end = position + length;
463
+ const slice = buffer.slice(offset, offset + length);
461
464
 
462
465
  if (end > this.stats.size) {
463
466
  this.stats.size = end;
464
467
  if (end > this._buffer.byteLength) {
465
468
  if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength! <= end) {
466
469
  this._buffer.buffer.resize(end);
470
+ } else if (config.unsafeBufferReplace) {
471
+ this._buffer = slice;
467
472
  } else {
468
473
  // Extend the buffer!
469
474
  const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
@@ -472,7 +477,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
472
477
  }
473
478
  }
474
479
  }
475
- const slice = buffer.slice(offset, offset + length);
480
+
476
481
  this._buffer.set(slice, position);
477
482
  this.stats.mtimeMs = Date.now();
478
483
  this.position = position + slice.byteLength;
@@ -489,7 +494,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
489
494
  */
490
495
  public async write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number> {
491
496
  const bytesWritten = this._write(buffer, offset, length, position);
492
- await this.sync();
497
+ if (config.syncOnWrite) await this.sync();
493
498
  return bytesWritten;
494
499
  }
495
500
 
@@ -504,7 +509,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
504
509
  */
505
510
  public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = this.position): number {
506
511
  const bytesWritten = this._write(buffer, offset, length, position);
507
- this.syncSync();
512
+ if (config.syncOnWrite) this.syncSync();
508
513
  return bytesWritten;
509
514
  }
510
515
 
@@ -515,10 +520,8 @@ export class PreloadFile<FS extends FileSystem> extends File {
515
520
  if (!isReadable(this.flag)) {
516
521
  throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
517
522
  }
518
- if (config.updateOnRead) {
519
- this.dirty = true;
520
- this.stats.atimeMs = Date.now();
521
- }
523
+ this.dirty = true;
524
+ this.stats.atimeMs = Date.now();
522
525
  position ??= this.position;
523
526
  let end = position + length;
524
527
  if (end > this.stats.size) {
@@ -527,7 +530,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
527
530
  this._position = end;
528
531
  const bytesRead = end - position;
529
532
  if (bytesRead == 0) {
530
- // No copy/read. Return immediatly for better performance
533
+ // No copy/read. Return immediately for better performance
531
534
  return bytesRead;
532
535
  }
533
536
  new Uint8Array(buffer.buffer, offset, length).set(this._buffer.slice(position, end));
@@ -544,7 +547,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
544
547
  */
545
548
  public async read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{ bytesRead: number; buffer: TBuffer }> {
546
549
  const bytesRead = this._read(buffer, offset, length, position);
547
- await this.sync();
550
+ if (config.syncOnRead) await this.sync();
548
551
  return { bytesRead, buffer };
549
552
  }
550
553
 
@@ -559,7 +562,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
559
562
  */
560
563
  public readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number {
561
564
  const bytesRead = this._read(buffer, offset, length, position);
562
- this.syncSync();
565
+ if (config.syncOnRead) this.syncSync();
563
566
  return bytesRead;
564
567
  }
565
568
 
@@ -569,7 +572,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
569
572
  }
570
573
  this.dirty = true;
571
574
  this.stats.chmod(mode);
572
- await this.sync();
575
+ if (config.syncOnWrite) await this.sync();
573
576
  }
574
577
 
575
578
  public chmodSync(mode: number): void {
@@ -578,7 +581,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
578
581
  }
579
582
  this.dirty = true;
580
583
  this.stats.chmod(mode);
581
- this.syncSync();
584
+ if (config.syncOnWrite) this.syncSync();
582
585
  }
583
586
 
584
587
  public async chown(uid: number, gid: number): Promise<void> {
@@ -587,7 +590,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
587
590
  }
588
591
  this.dirty = true;
589
592
  this.stats.chown(uid, gid);
590
- await this.sync();
593
+ if (config.syncOnWrite) await this.sync();
591
594
  }
592
595
 
593
596
  public chownSync(uid: number, gid: number): void {
@@ -596,7 +599,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
596
599
  }
597
600
  this.dirty = true;
598
601
  this.stats.chown(uid, gid);
599
- this.syncSync();
602
+ if (config.syncOnWrite) this.syncSync();
600
603
  }
601
604
 
602
605
  public async utimes(atime: Date, mtime: Date): Promise<void> {
@@ -606,7 +609,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
606
609
  this.dirty = true;
607
610
  this.stats.atime = atime;
608
611
  this.stats.mtime = mtime;
609
- await this.sync();
612
+ if (config.syncOnWrite) await this.sync();
610
613
  }
611
614
 
612
615
  public utimesSync(atime: Date, mtime: Date): void {
@@ -616,7 +619,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
616
619
  this.dirty = true;
617
620
  this.stats.atime = atime;
618
621
  this.stats.mtime = mtime;
619
- this.syncSync();
622
+ if (config.syncOnWrite) this.syncSync();
620
623
  }
621
624
 
622
625
  public async _setType(type: FileType): Promise<void> {
@@ -4,45 +4,41 @@ import { fs } from '../common.js';
4
4
 
5
5
  const asyncMode = 0o777;
6
6
  const syncMode = 0o644;
7
+ const file = 'a.js';
7
8
 
8
9
  suite('chmod tests', () => {
9
10
  test('chmod', async () => {
10
- const file1 = 'a.js';
11
+ await fs.promises.chmod(file, asyncMode.toString(8));
11
12
 
12
- await fs.promises.chmod(file1, asyncMode.toString(8));
13
+ const stats = await fs.promises.stat(file);
14
+ assert.equal(stats.mode & 0o777, asyncMode);
13
15
 
14
- const stats = await fs.promises.stat(file1);
15
- assert((stats.mode & 0o777) === asyncMode);
16
-
17
- fs.chmodSync(file1, syncMode);
18
- assert((fs.statSync(file1).mode & 0o777) === syncMode);
16
+ fs.chmodSync(file, syncMode);
17
+ assert.equal(fs.statSync(file).mode & 0o777, syncMode);
19
18
  });
20
19
 
21
20
  test('fchmod', async () => {
22
- const file2 = 'a1.js';
23
-
24
- const handle = await fs.promises.open(file2, 'a', 0o644);
21
+ const handle = await fs.promises.open(file, 'a', 0o644);
25
22
 
26
23
  await handle.chmod(asyncMode);
27
24
  const stats = await handle.stat();
28
25
 
29
- assert((stats.mode & 0o777) === asyncMode);
26
+ assert.equal(stats.mode & 0o777, asyncMode);
30
27
 
31
28
  fs.fchmodSync(handle.fd, syncMode);
32
- assert((fs.statSync(file2).mode & 0o777) === syncMode);
29
+ assert.equal(fs.statSync(file).mode & 0o777, syncMode);
33
30
  });
34
31
 
35
32
  test('lchmod', async () => {
36
33
  const link = 'symbolic-link';
37
- const target = 'a1.js';
38
34
 
39
- await fs.promises.symlink(target, link);
35
+ await fs.promises.symlink(file, link);
40
36
  await fs.promises.lchmod(link, asyncMode);
41
37
 
42
38
  const stats = await fs.promises.lstat(link);
43
- assert((stats.mode & 0o777) === asyncMode);
39
+ assert.equal(stats.mode & 0o777, asyncMode);
44
40
 
45
41
  fs.lchmodSync(link, syncMode);
46
- assert((fs.lstatSync(link).mode & 0o777) === syncMode);
42
+ assert.equal(fs.lstatSync(link).mode & 0o777, syncMode);
47
43
  });
48
44
  });
@@ -10,22 +10,22 @@ const path: string = 'truncate-file.txt',
10
10
  suite('Truncate, sync', () => {
11
11
  test('initial write', () => {
12
12
  fs.writeFileSync(path, data);
13
- assert(fs.statSync(path).size === size);
13
+ assert.equal(fs.statSync(path).size, size);
14
14
  });
15
15
 
16
16
  test('truncate to 1024', () => {
17
17
  fs.truncateSync(path, 1024);
18
- assert(fs.statSync(path).size === 1024);
18
+ assert.equal(fs.statSync(path).size, 1024);
19
19
  });
20
20
 
21
21
  test('truncate to 0', () => {
22
22
  fs.truncateSync(path);
23
- assert(fs.statSync(path).size === 0);
23
+ assert.equal(fs.statSync(path).size, 0);
24
24
  });
25
25
 
26
26
  test('write', () => {
27
27
  fs.writeFileSync(path, data);
28
- assert(fs.statSync(path).size === size);
28
+ assert.equal(fs.statSync(path).size, size);
29
29
  });
30
30
 
31
31
  let fd: number;
@@ -35,12 +35,12 @@ suite('Truncate, sync', () => {
35
35
 
36
36
  test('ftruncate to 1024', () => {
37
37
  fs.ftruncateSync(fd, 1024);
38
- assert(fs.fstatSync(fd).size === 1024);
38
+ assert.equal(fs.fstatSync(fd).size, 1024);
39
39
  });
40
40
 
41
41
  test('ftruncate to 0', () => {
42
42
  fs.ftruncateSync(fd);
43
- assert(fs.fstatSync(fd).size === 0);
43
+ assert.equal(fs.fstatSync(fd).size, 0);
44
44
  });
45
45
 
46
46
  test('close fd', () => {
@@ -53,22 +53,22 @@ suite('Truncate, async', () => {
53
53
  test('initial write', async () => {
54
54
  await fs.promises.writeFile(path, data);
55
55
 
56
- assert((await statSize(path)) === 1024 * 16);
56
+ assert.equal(await statSize(path), 1024 * 16);
57
57
  });
58
58
 
59
59
  test('truncate to 1024', async () => {
60
60
  await fs.promises.truncate(path, 1024);
61
- assert((await statSize(path)) === 1024);
61
+ assert.equal(await statSize(path), 1024);
62
62
  });
63
63
 
64
64
  test('truncate to 0', async () => {
65
65
  await fs.promises.truncate(path);
66
- assert((await statSize(path)) === 0);
66
+ assert.equal(await statSize(path), 0);
67
67
  });
68
68
 
69
69
  test('write', async () => {
70
70
  await fs.promises.writeFile(path, data);
71
- assert((await statSize(path)) === size);
71
+ assert.equal(await statSize(path), size);
72
72
  });
73
73
 
74
74
  let handle: FileHandle;
@@ -79,13 +79,13 @@ suite('Truncate, async', () => {
79
79
  test('handle.truncate to 1024', async () => {
80
80
  await handle.truncate(1024);
81
81
  await handle.sync();
82
- assert((await statSize(path)) === 1024);
82
+ assert.equal(await statSize(path), 1024);
83
83
  });
84
84
 
85
85
  test('handle.truncate to 0', async () => {
86
86
  await handle.truncate();
87
87
  await handle.sync();
88
- assert((await statSize(path)) === 0);
88
+ assert.equal(await statSize(path), 0);
89
89
  });
90
90
 
91
91
  test('close handle', async () => {