@zenfs/core 1.8.0 → 1.8.2

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.
@@ -1,5 +1,5 @@
1
1
  import { ErrnoError } from '../../error.js';
2
- import { PreloadFile } from '../../file.js';
2
+ import { LazyFile } from '../../file.js';
3
3
  import { Stats } from '../../stats.js';
4
4
  import { S_IFREG } from '../../vfs/constants.js';
5
5
  import { Index } from './file_index.js';
@@ -43,13 +43,13 @@ export class IndexFS extends StoreFS {
43
43
  }
44
44
  async createFile(path, flag, mode, options) {
45
45
  const node = await this.commitNew(path, S_IFREG, { mode, ...options }, new Uint8Array(), 'createFile');
46
- const file = new PreloadFile(this, path, flag, node.toStats(), new Uint8Array());
46
+ const file = new LazyFile(this, path, flag, node.toStats());
47
47
  this.index.set(path, node);
48
48
  return file;
49
49
  }
50
50
  createFileSync(path, flag, mode, options) {
51
51
  const node = this.commitNewSync(path, S_IFREG, { mode, ...options }, new Uint8Array(), 'createFile');
52
- const file = new PreloadFile(this, path, flag, node.toStats(), new Uint8Array());
52
+ const file = new LazyFile(this, path, flag, node.toStats());
53
53
  this.index.set(path, node);
54
54
  return file;
55
55
  }
@@ -20,7 +20,7 @@ export declare const _inode_fields: readonly ["ino", "data", "size", "mode", "fl
20
20
  * @todo [BREAKING] Remove 58 byte Inode upgrade path
21
21
  */
22
22
  export declare class Inode implements InodeLike {
23
- constructor(data?: ArrayBufferLike | ArrayBufferView | Readonly<InodeLike>);
23
+ constructor(data?: ArrayBufferLike | ArrayBufferView | Readonly<Partial<InodeLike>>);
24
24
  data: number;
25
25
  /** For future use */
26
26
  __data_old: number;
package/dist/devices.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import type { FileReadResult } from './file.js';
2
- import type { InodeLike } from './backends/index.js';
1
+ import { Inode } from './backends/index.js';
3
2
  import { InMemoryStore } from './backends/memory.js';
4
3
  import { StoreFS } from './backends/store/fs.js';
4
+ import type { FileReadResult } from './file.js';
5
5
  import { File } from './file.js';
6
6
  import type { CreationOptions } from './filesystem.js';
7
7
  import { Stats } from './stats.js';
@@ -15,7 +15,7 @@ export interface Device<TData = any> {
15
15
  /**
16
16
  * The device's driver
17
17
  */
18
- driver: DeviceDriver;
18
+ driver: DeviceDriver<TData>;
19
19
  /**
20
20
  * Which inode the device is assigned
21
21
  */
@@ -34,6 +34,12 @@ export interface Device<TData = any> {
34
34
  */
35
35
  minor: number;
36
36
  }
37
+ export interface DeviceInit<TData = any> {
38
+ data?: TData;
39
+ minor?: number;
40
+ major?: number;
41
+ name?: string;
42
+ }
37
43
  /**
38
44
  * A device driver
39
45
  */
@@ -56,22 +62,36 @@ export interface DeviceDriver<TData = any> {
56
62
  * Initializes a new device.
57
63
  * @returns `Device.data`
58
64
  */
59
- init?(ino: number, options: object): {
60
- data?: TData;
61
- minor?: number;
62
- major?: number;
63
- name?: string;
64
- };
65
+ init?(ino: number, options: object): DeviceInit<TData>;
65
66
  /**
66
- * Synchronously read from the device
67
+ * Synchronously read from a device file
67
68
  * @group File operations
69
+ * @deprecated
70
+ * @todo [BREAKING] Remove
71
+ */
72
+ read?(file: DeviceFile<TData>, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
73
+ /**
74
+ * Synchronously read from a device.
75
+ * @privateRemarks
76
+ * For many devices there is no concept of an offset or end.
77
+ * For example, /dev/random will be "the same" regardless of where you read from- random data.
78
+ * @group File operations
79
+ * @todo [BREAKING] Rename to `read`
80
+ */
81
+ readD(device: Device<TData>, buffer: Uint8Array, offset: number, end: number): void;
82
+ /**
83
+ * Synchronously write to a device file
84
+ * @group File operations
85
+ * @deprecated
86
+ * @todo [BREAKING] Remove
68
87
  */
69
- read(file: DeviceFile<TData>, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
88
+ write?(file: DeviceFile<TData>, buffer: Uint8Array, offset: number, length: number, position?: number): number;
70
89
  /**
71
- * Synchronously write to the device
90
+ * Synchronously write to a device
72
91
  * @group File operations
92
+ * @todo [BREAKING] Rename to `write`
73
93
  */
74
- write(file: DeviceFile<TData>, buffer: Uint8Array, offset: number, length: number, position?: number): number;
94
+ writeD(device: Device<TData>, buffer: Uint8Array, offset: number): void;
75
95
  /**
76
96
  * Sync the device
77
97
  * @group File operations
@@ -95,7 +115,7 @@ export declare class DeviceFile<TData = any> extends File {
95
115
  position: number;
96
116
  constructor(fs: DeviceFS, path: string, device: Device<TData>);
97
117
  get driver(): DeviceDriver<TData>;
98
- protected get stats(): Partial<InodeLike>;
118
+ protected stats: Inode;
99
119
  stat(): Promise<Stats>;
100
120
  statSync(): Stats;
101
121
  readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
@@ -114,8 +134,6 @@ export declare class DeviceFile<TData = any> extends File {
114
134
  chmodSync(): void;
115
135
  utimes(): Promise<void>;
116
136
  utimesSync(): void;
117
- _setType(): Promise<void>;
118
- _setTypeSync(): void;
119
137
  }
120
138
  /**
121
139
  * A temporary file system that manages and interfaces with devices
@@ -157,6 +175,10 @@ export declare class DeviceFS extends StoreFS<InMemoryStore> {
157
175
  linkSync(target: string, link: string): void;
158
176
  sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
159
177
  syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
178
+ read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
179
+ readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
180
+ write(path: string, data: Uint8Array, offset: number): Promise<void>;
181
+ writeSync(path: string, data: Uint8Array, offset: number): void;
160
182
  }
161
183
  /**
162
184
  * Simulates the `/dev/null` device.
@@ -199,6 +221,6 @@ export declare const devices: {
199
221
  full: DeviceDriver<any>;
200
222
  random: DeviceDriver<any>;
201
223
  console: DeviceDriver<{
202
- output: (text: string) => unknown;
224
+ output: (text: string, offset: number) => unknown;
203
225
  }>;
204
226
  };
package/dist/devices.js CHANGED
@@ -53,6 +53,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
53
53
  var e = new Error(message);
54
54
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
55
55
  });
56
+ import { Inode } from './backends/index.js';
56
57
  import { InMemoryStore } from './backends/memory.js';
57
58
  import { StoreFS } from './backends/store/fs.js';
58
59
  import { Errno, ErrnoError } from './error.js';
@@ -73,28 +74,40 @@ export class DeviceFile extends File {
73
74
  this.fs = fs;
74
75
  this.device = device;
75
76
  this.position = 0;
77
+ this.stats = new Inode({
78
+ mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666,
79
+ });
76
80
  }
77
81
  get driver() {
78
82
  return this.device.driver;
79
83
  }
80
- get stats() {
81
- return { mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666 };
82
- }
83
84
  async stat() {
84
85
  return Promise.resolve(new Stats(this.stats));
85
86
  }
86
87
  statSync() {
87
88
  return new Stats(this.stats);
88
89
  }
89
- readSync(buffer, offset, length, position) {
90
- return this.driver.read(this, buffer, offset, length, position);
90
+ readSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
91
+ this.stats.atimeMs = Date.now();
92
+ const end = position + length;
93
+ this.position = end;
94
+ const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
95
+ this.driver.readD(this.device, uint8.subarray(offset, length), position, end);
96
+ return length;
91
97
  }
92
98
  // eslint-disable-next-line @typescript-eslint/require-await
93
99
  async read(buffer, offset, length) {
94
100
  return { bytesRead: this.readSync(buffer, offset, length), buffer };
95
101
  }
96
- writeSync(buffer, offset = 0, length = buffer.length, position) {
97
- return this.driver.write(this, buffer, offset, length, position);
102
+ writeSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
103
+ const end = position + length;
104
+ if (end > this.stats.size)
105
+ this.stats.size = end;
106
+ this.stats.mtimeMs = Date.now();
107
+ this.position = end;
108
+ const data = buffer.subarray(offset, offset + length);
109
+ this.driver.writeD(this.device, data, position);
110
+ return length;
98
111
  }
99
112
  // eslint-disable-next-line @typescript-eslint/require-await
100
113
  async write(buffer, offset, length, position) {
@@ -144,12 +157,6 @@ export class DeviceFile extends File {
144
157
  utimesSync() {
145
158
  throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
146
159
  }
147
- _setType() {
148
- throw ErrnoError.With('ENOTSUP', this.path, '_setType');
149
- }
150
- _setTypeSync() {
151
- throw ErrnoError.With('ENOTSUP', this.path, '_setType');
152
- }
153
160
  }
154
161
  /**
155
162
  * A temporary file system that manages and interfaces with devices
@@ -389,11 +396,41 @@ export class DeviceFS extends StoreFS {
389
396
  }
390
397
  return super.syncSync(path, data, stats);
391
398
  }
399
+ async read(path, buffer, offset, end) {
400
+ const device = this.devices.get(path);
401
+ if (!device) {
402
+ await super.read(path, buffer, offset, end);
403
+ return;
404
+ }
405
+ device.driver.readD(device, buffer, offset, end);
406
+ }
407
+ readSync(path, buffer, offset, end) {
408
+ const device = this.devices.get(path);
409
+ if (!device) {
410
+ super.readSync(path, buffer, offset, end);
411
+ return;
412
+ }
413
+ device.driver.readD(device, buffer, offset, end);
414
+ }
415
+ async write(path, data, offset) {
416
+ const device = this.devices.get(path);
417
+ if (!device) {
418
+ return await super.write(path, data, offset);
419
+ }
420
+ device.driver.writeD(device, data, offset);
421
+ }
422
+ writeSync(path, data, offset) {
423
+ const device = this.devices.get(path);
424
+ if (!device) {
425
+ return super.writeSync(path, data, offset);
426
+ }
427
+ device.driver.writeD(device, data, offset);
428
+ }
392
429
  }
393
- function defaultWrite(file, buffer, offset, length) {
394
- file.position += length;
395
- return length;
430
+ function defaultWrite(device, data, offset) {
431
+ return;
396
432
  }
433
+ const emptyBuffer = new Uint8Array();
397
434
  /**
398
435
  * Simulates the `/dev/null` device.
399
436
  * - Reads return 0 bytes (EOF).
@@ -409,7 +446,10 @@ export const nullDevice = {
409
446
  read() {
410
447
  return 0;
411
448
  },
412
- write: defaultWrite,
449
+ readD() {
450
+ return emptyBuffer;
451
+ },
452
+ writeD: defaultWrite,
413
453
  };
414
454
  /**
415
455
  * Simulates the `/dev/zero` device
@@ -427,15 +467,10 @@ export const zeroDevice = {
427
467
  init() {
428
468
  return { major: 1, minor: 5 };
429
469
  },
430
- read(file, buffer, offset = 0, length = buffer.byteLength) {
431
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
432
- for (let i = offset; i < offset + length; i++) {
433
- data[i] = 0;
434
- }
435
- file.position += length;
436
- return length;
470
+ readD(device, buffer, offset, end) {
471
+ buffer.fill(0, offset, end);
437
472
  },
438
- write: defaultWrite,
473
+ writeD: defaultWrite,
439
474
  };
440
475
  /**
441
476
  * Simulates the `/dev/full` device.
@@ -449,17 +484,15 @@ export const fullDevice = {
449
484
  init() {
450
485
  return { major: 1, minor: 7 };
451
486
  },
452
- read(file, buffer, offset = 0, length = buffer.byteLength) {
453
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
454
- for (let i = offset; i < offset + length; i++) {
455
- data[i] = 0;
456
- }
457
- file.position += length;
458
- return length;
487
+ readD(device, buffer, offset, end) {
488
+ buffer.fill(0, offset, end);
459
489
  },
460
490
  write(file) {
461
491
  throw ErrnoError.With('ENOSPC', file.path, 'write');
462
492
  },
493
+ writeD() {
494
+ throw ErrnoError.With('ENOSPC', undefined, 'write');
495
+ },
463
496
  };
464
497
  /**
465
498
  * Simulates the `/dev/random` device.
@@ -473,15 +506,12 @@ export const randomDevice = {
473
506
  init() {
474
507
  return { major: 1, minor: 8 };
475
508
  },
476
- read(file, buffer, offset = 0, length = buffer.byteLength) {
477
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
478
- for (let i = offset; i < offset + length; i++) {
479
- data[i] = Math.floor(Math.random() * 256);
509
+ readD(device, buffer) {
510
+ for (let i = 0; i < buffer.length; i++) {
511
+ buffer[i] = Math.floor(Math.random() * 256);
480
512
  }
481
- file.position += length;
482
- return length;
483
513
  },
484
- write: defaultWrite,
514
+ writeD: defaultWrite,
485
515
  };
486
516
  /**
487
517
  * Simulates the `/dev/console` device.
@@ -490,17 +520,15 @@ export const randomDevice = {
490
520
  const consoleDevice = {
491
521
  name: 'console',
492
522
  singleton: true,
493
- init(ino, { output = console.log } = {}) {
523
+ init(ino, { output = text => console.log(text) } = {}) {
494
524
  return { major: 5, minor: 1, data: { output } };
495
525
  },
496
- read() {
497
- return 0;
526
+ readD() {
527
+ return emptyBuffer;
498
528
  },
499
- write(file, buffer, offset, length) {
500
- const text = decodeUTF8(buffer.slice(offset, offset + length));
501
- file.device.data.output(text);
502
- file.position += length;
503
- return length;
529
+ writeD(device, buffer, offset) {
530
+ const text = decodeUTF8(buffer);
531
+ device.data.output(text, offset);
504
532
  },
505
533
  };
506
534
  /**
package/dist/file.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Errno, ErrnoError } from './error.js';
2
2
  import './polyfills.js';
3
3
  import { _chown, Stats } from './stats.js';
4
+ import { growBuffer } from './utils.js';
4
5
  import { config } from './vfs/config.js';
5
6
  import * as c from './vfs/constants.js';
6
7
  const maxByteLength = 0x100000; // 1 MiB
@@ -269,7 +270,7 @@ export class PreloadFile extends File {
269
270
  }
270
271
  this.stats.size = length;
271
272
  // Truncate.
272
- this._buffer = length ? this._buffer.slice(0, length) : new Uint8Array();
273
+ this._buffer = length ? this._buffer.subarray(0, length) : new Uint8Array();
273
274
  }
274
275
  async truncate(length) {
275
276
  this._truncate(length);
@@ -289,28 +290,10 @@ export class PreloadFile extends File {
289
290
  }
290
291
  this.dirty = true;
291
292
  const end = position + length;
292
- const slice = buffer.slice(offset, offset + length);
293
- if (end > this.stats.size) {
293
+ const slice = buffer.subarray(offset, offset + length);
294
+ this._buffer = growBuffer(this._buffer, end);
295
+ if (end > this.stats.size)
294
296
  this.stats.size = end;
295
- if (end > this._buffer.byteLength) {
296
- const { buffer } = this._buffer;
297
- if ('resizable' in buffer && buffer.resizable && buffer.maxByteLength <= end) {
298
- buffer.resize(end);
299
- }
300
- else if ('growable' in buffer && buffer.growable && buffer.maxByteLength <= end) {
301
- buffer.grow(end);
302
- }
303
- else if (config.unsafeBufferReplace) {
304
- this._buffer = slice;
305
- }
306
- else {
307
- // Extend the buffer!
308
- const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength }));
309
- newBuffer.set(this._buffer);
310
- this._buffer = newBuffer;
311
- }
312
- }
313
- }
314
297
  this._buffer.set(slice, position);
315
298
  this.stats.mtimeMs = Date.now();
316
299
  this.position = position + slice.byteLength;
@@ -366,7 +349,7 @@ export class PreloadFile extends File {
366
349
  // No copy/read. Return immediately for better performance
367
350
  return bytesRead;
368
351
  }
369
- const slice = this._buffer.slice(position, end);
352
+ const slice = this._buffer.subarray(position, end);
370
353
  new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength).set(slice, offset);
371
354
  return bytesRead;
372
355
  }
@@ -589,10 +572,9 @@ export class LazyFile extends File {
589
572
  }
590
573
  this.dirty = true;
591
574
  const end = position + length;
592
- const slice = buffer.slice(offset, offset + length);
593
- if (end > this.stats.size) {
575
+ const slice = buffer.subarray(offset, offset + length);
576
+ if (end > this.stats.size)
594
577
  this.stats.size = end;
595
- }
596
578
  this.stats.mtimeMs = Date.now();
597
579
  this._position = position + slice.byteLength;
598
580
  return slice;
@@ -607,7 +589,7 @@ export class LazyFile extends File {
607
589
  */
608
590
  async write(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
609
591
  const slice = this.prepareWrite(buffer, offset, length, position);
610
- await this.fs.write(this.path, slice, offset);
592
+ await this.fs.write(this.path, slice, position);
611
593
  if (config.syncImmediately)
612
594
  await this.sync();
613
595
  return slice.byteLength;
@@ -623,7 +605,7 @@ export class LazyFile extends File {
623
605
  */
624
606
  writeSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
625
607
  const slice = this.prepareWrite(buffer, offset, length, position);
626
- this.fs.writeSync(this.path, slice, offset);
608
+ this.fs.writeSync(this.path, slice, position);
627
609
  if (config.syncImmediately)
628
610
  this.syncSync();
629
611
  return slice.byteLength;
@@ -656,7 +638,8 @@ export class LazyFile extends File {
656
638
  */
657
639
  async read(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
658
640
  const bytesRead = this.prepareRead(length, position);
659
- new Uint8Array(buffer.buffer, offset, length).set(await this.fs.read(this.path, position, bytesRead));
641
+ const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
642
+ await this.fs.read(this.path, uint8.subarray(offset, offset + length), position, bytesRead);
660
643
  if (config.syncImmediately)
661
644
  await this.sync();
662
645
  return { bytesRead, buffer };
@@ -672,7 +655,8 @@ export class LazyFile extends File {
672
655
  */
673
656
  readSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
674
657
  const bytesRead = this.prepareRead(length, position);
675
- new Uint8Array(buffer.buffer, offset, length).set(this.fs.readSync(this.path, position, bytesRead));
658
+ const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
659
+ this.fs.readSync(this.path, uint8.subarray(offset, offset + length), position, bytesRead);
676
660
  if (config.syncImmediately)
677
661
  this.syncSync();
678
662
  return bytesRead;
@@ -151,8 +151,30 @@ export declare abstract class FileSystem {
151
151
  abstract linkSync(target: string, link: string): void;
152
152
  abstract sync(path: string, data?: Uint8Array, stats?: Partial<Readonly<StatsLike>>): Promise<void>;
153
153
  abstract syncSync(path: string, data?: Uint8Array, stats?: Partial<Readonly<StatsLike>>): void;
154
- abstract read(path: string, offset: number, length: number): Promise<Uint8Array>;
155
- abstract readSync(path: string, offset: number, length: number): Uint8Array;
154
+ /**
155
+ * Reads into a buffer
156
+ * @param buffer The buffer to read into. You must set the `byteOffset` and `byteLength` appropriately!
157
+ * @param offset The offset into the file to start reading from
158
+ * @param end The position in the file to stop reading
159
+ */
160
+ abstract read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
161
+ /**
162
+ * Reads into a buffer
163
+ * @param buffer The buffer to read into. You must set the `byteOffset` and `byteLength` appropriately!
164
+ * @param offset The offset into the file to start reading from
165
+ * @param end The position in the file to stop reading
166
+ */
167
+ abstract readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
168
+ /**
169
+ * Writes a buffer to a file
170
+ * @param buffer The buffer to write. You must set the `byteOffset` and `byteLength` appropriately!
171
+ * @param offset The offset in the file to start writing
172
+ */
156
173
  abstract write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
174
+ /**
175
+ * Writes a buffer to a file
176
+ * @param buffer The buffer to write. You must set the `byteOffset` and `byteLength` appropriately!
177
+ * @param offset The offset in the file to start writing
178
+ */
157
179
  abstract writeSync(path: string, buffer: Uint8Array, offset: number): void;
158
180
  }
@@ -52,7 +52,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
52
52
  });
53
53
  import { StoreFS } from '../backends/store/fs.js';
54
54
  import { Errno, ErrnoError } from '../error.js';
55
- import { parseFlag, PreloadFile } from '../file.js';
55
+ import { LazyFile, parseFlag } from '../file.js';
56
56
  import { join } from '../vfs/path.js';
57
57
  /**
58
58
  * Async() implements synchronous methods on an asynchronous file system
@@ -138,11 +138,8 @@ export function Async(FS) {
138
138
  }
139
139
  openFileSync(path, flag) {
140
140
  this.checkSync(path, 'openFile');
141
- const file = this._sync.openFileSync(path, flag + '+');
142
- const stats = file.statSync();
143
- const buffer = new Uint8Array(stats.size);
144
- file.readSync(buffer);
145
- return new PreloadFile(this, path, flag, stats, buffer);
141
+ const stats = this._sync.statSync(path);
142
+ return new LazyFile(this, path, flag, stats);
146
143
  }
147
144
  unlinkSync(path) {
148
145
  this.checkSync(path, 'unlinkSync');
@@ -177,6 +174,15 @@ export function Async(FS) {
177
174
  this.checkSync(path, 'exists');
178
175
  return this._sync.existsSync(path);
179
176
  }
177
+ readSync(path, buffer, offset, end) {
178
+ this.checkSync(path, 'read');
179
+ this._sync.readSync(path, buffer, offset, end);
180
+ }
181
+ writeSync(path, buffer, offset) {
182
+ this.checkSync(path, 'write');
183
+ this._sync.writeSync(path, buffer, offset);
184
+ this.queue('write', path, buffer, offset);
185
+ }
180
186
  /**
181
187
  * @internal
182
188
  */
@@ -71,8 +71,8 @@ export declare class _MutexedFS<T extends FileSystem> implements FileSystem {
71
71
  linkSync(srcpath: string, dstpath: string): void;
72
72
  sync(path: string, data?: Uint8Array, stats?: Readonly<InodeLike>): Promise<void>;
73
73
  syncSync(path: string, data?: Uint8Array, stats?: Readonly<InodeLike>): void;
74
- read(path: string, offset: number, length: number): Promise<Uint8Array>;
75
- readSync(path: string, offset: number, length: number): Uint8Array;
74
+ read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
75
+ readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
76
76
  write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
77
77
  writeSync(path: string, buffer: Uint8Array, offset: number): void;
78
78
  }
@@ -81,7 +81,7 @@ export declare class _MutexedFS<T extends FileSystem> implements FileSystem {
81
81
  * For example, on an OverlayFS instance with an async lower
82
82
  * directory operations like rename and rmdir may involve multiple
83
83
  * requests involving both the upper and lower file systems -- they
84
- * are not executed in a single atomic step. OverlayFS uses this
84
+ * are not executed in a single atomic step. OverlayFS used to use this
85
85
  * to avoid having to reason about the correctness of
86
86
  * multiple requests interleaving.
87
87
  *
@@ -448,11 +448,11 @@ export class _MutexedFS {
448
448
  __disposeResources(env_22);
449
449
  }
450
450
  }
451
- async read(path, offset, length) {
451
+ async read(path, buffer, offset, end) {
452
452
  const env_23 = { stack: [], error: void 0, hasError: false };
453
453
  try {
454
454
  const _ = __addDisposableResource(env_23, await this.lock(path, 'read'), false);
455
- return await this._fs.read(path, offset, length);
455
+ return await this._fs.read(path, buffer, offset, end);
456
456
  }
457
457
  catch (e_23) {
458
458
  env_23.error = e_23;
@@ -462,11 +462,11 @@ export class _MutexedFS {
462
462
  __disposeResources(env_23);
463
463
  }
464
464
  }
465
- readSync(path, offset, length) {
465
+ readSync(path, buffer, offset, end) {
466
466
  const env_24 = { stack: [], error: void 0, hasError: false };
467
467
  try {
468
468
  const _ = __addDisposableResource(env_24, this.lockSync(path, 'read'), false);
469
- return this._fs.readSync(path, offset, length);
469
+ return this._fs.readSync(path, buffer, offset, end);
470
470
  }
471
471
  catch (e_24) {
472
472
  env_24.error = e_24;
@@ -510,7 +510,7 @@ export class _MutexedFS {
510
510
  * For example, on an OverlayFS instance with an async lower
511
511
  * directory operations like rename and rmdir may involve multiple
512
512
  * requests involving both the upper and lower file systems -- they
513
- * are not executed in a single atomic step. OverlayFS uses this
513
+ * are not executed in a single atomic step. OverlayFS used to use this
514
514
  * to avoid having to reason about the correctness of
515
515
  * multiple requests interleaving.
516
516
  *
@@ -1,26 +1,27 @@
1
- import type { File } from '../file.js';
2
1
  import type { FileSystem, FileSystemMetadata } from '../filesystem.js';
3
- import type { Stats } from '../stats.js';
2
+ import type { StatsLike } from '../stats.js';
4
3
  import type { Mixin } from './shared.js';
5
4
  /**
6
5
  * @internal
7
6
  */
8
7
  export interface ReadonlyMixin {
9
8
  metadata(): FileSystemMetadata;
10
- rename(oldPath: string, newPath: string): Promise<void>;
11
- renameSync(oldPath: string, newPath: string): void;
12
- createFile(path: string, flag: string, mode: number): Promise<File>;
13
- createFileSync(path: string, flag: string, mode: number): File;
14
- unlink(path: string): Promise<void>;
15
- unlinkSync(path: string): void;
16
- rmdir(path: string): Promise<void>;
17
- rmdirSync(path: string): void;
18
- mkdir(path: string, mode: number): Promise<void>;
19
- mkdirSync(path: string, mode: number): void;
20
- link(srcpath: string, dstpath: string): Promise<void>;
21
- linkSync(srcpath: string, dstpath: string): void;
22
- sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
23
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
9
+ rename(oldPath: string, newPath: string): Promise<never>;
10
+ renameSync(oldPath: string, newPath: string): never;
11
+ createFile(path: string, flag: string, mode: number): Promise<never>;
12
+ createFileSync(path: string, flag: string, mode: number): never;
13
+ unlink(path: string): Promise<never>;
14
+ unlinkSync(path: string): never;
15
+ rmdir(path: string): Promise<never>;
16
+ rmdirSync(path: string): never;
17
+ mkdir(path: string, mode: number): Promise<never>;
18
+ mkdirSync(path: string, mode: number): never;
19
+ link(srcpath: string, dstpath: string): Promise<never>;
20
+ linkSync(srcpath: string, dstpath: string): never;
21
+ sync(path: string, data: Uint8Array, stats: Readonly<StatsLike<number>>): Promise<never>;
22
+ syncSync(path: string, data: Uint8Array, stats: Readonly<StatsLike<number>>): never;
23
+ write(path: string, buffer: Uint8Array, offset: number): Promise<never>;
24
+ writeSync(path: string, buffer: Uint8Array, offset: number): Promise<never>;
24
25
  }
25
26
  /**
26
27
  * Implements the non-readonly methods to throw `EROFS`
@@ -50,6 +50,12 @@ export function Readonly(FS) {
50
50
  syncSync() {
51
51
  throw new ErrnoError(Errno.EROFS);
52
52
  }
53
+ async write() {
54
+ throw new ErrnoError(Errno.EROFS);
55
+ }
56
+ writeSync() {
57
+ throw new ErrnoError(Errno.EROFS);
58
+ }
53
59
  }
54
60
  return ReadonlyFS;
55
61
  }
package/dist/utils.d.ts CHANGED
@@ -89,3 +89,9 @@ export declare function canary(path?: string, syscall?: string): () => void;
89
89
  * @internal @hidden
90
90
  */
91
91
  export declare function _throw(e: unknown): never;
92
+ /**
93
+ * Grows a buffer if it isn't large enough
94
+ * @returns The original buffer if resized successfully, or a newly created buffer
95
+ * @internal Not for external use!
96
+ */
97
+ export declare function growBuffer<T extends ArrayBufferLike | ArrayBufferView>(buffer: T, newByteLength: number): T;