@zenfs/core 1.11.4 → 2.1.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 (135) hide show
  1. package/dist/backends/backend.d.ts +19 -15
  2. package/dist/backends/backend.js +36 -19
  3. package/dist/backends/cow.d.ts +20 -30
  4. package/dist/backends/cow.js +83 -192
  5. package/dist/backends/fetch.d.ts +1 -0
  6. package/dist/backends/fetch.js +30 -30
  7. package/dist/backends/index.d.ts +1 -1
  8. package/dist/backends/index.js +1 -1
  9. package/dist/backends/memory.d.ts +5 -7
  10. package/dist/backends/memory.js +2 -3
  11. package/dist/backends/passthrough.d.ts +19 -23
  12. package/dist/backends/passthrough.js +98 -288
  13. package/dist/backends/port.d.ts +220 -0
  14. package/dist/backends/port.js +328 -0
  15. package/dist/backends/single_buffer.d.ts +59 -47
  16. package/dist/backends/single_buffer.js +468 -219
  17. package/dist/backends/store/fs.d.ts +25 -35
  18. package/dist/backends/store/fs.js +276 -315
  19. package/dist/backends/store/store.d.ts +10 -15
  20. package/dist/backends/store/store.js +11 -10
  21. package/dist/config.d.ts +3 -12
  22. package/dist/config.js +17 -19
  23. package/dist/context.d.ts +8 -21
  24. package/dist/context.js +33 -10
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +2 -1
  27. package/dist/internal/contexts.d.ts +63 -0
  28. package/dist/internal/contexts.js +15 -0
  29. package/dist/internal/credentials.d.ts +2 -11
  30. package/dist/internal/credentials.js +0 -19
  31. package/dist/internal/devices.d.ts +18 -80
  32. package/dist/internal/devices.js +103 -316
  33. package/dist/internal/error.d.ts +9 -204
  34. package/dist/internal/error.js +19 -288
  35. package/dist/internal/file_index.d.ts +1 -1
  36. package/dist/internal/file_index.js +11 -11
  37. package/dist/internal/filesystem.d.ts +51 -94
  38. package/dist/internal/filesystem.js +21 -20
  39. package/dist/internal/index.d.ts +1 -2
  40. package/dist/internal/index.js +1 -2
  41. package/dist/internal/index_fs.d.ts +12 -30
  42. package/dist/internal/index_fs.js +37 -69
  43. package/dist/internal/inode.d.ts +140 -24
  44. package/dist/internal/inode.js +515 -66
  45. package/dist/mixins/async.js +52 -112
  46. package/dist/mixins/mutexed.d.ts +19 -18
  47. package/dist/mixins/mutexed.js +62 -64
  48. package/dist/mixins/readonly.d.ts +7 -6
  49. package/dist/mixins/readonly.js +24 -18
  50. package/dist/mixins/sync.js +8 -8
  51. package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
  52. package/dist/{vfs/path.js → path.js} +6 -9
  53. package/dist/polyfills.js +1 -1
  54. package/dist/readline.d.ts +134 -0
  55. package/dist/readline.js +623 -0
  56. package/dist/utils.d.ts +9 -37
  57. package/dist/utils.js +17 -85
  58. package/dist/vfs/acl.d.ts +42 -0
  59. package/dist/vfs/acl.js +268 -0
  60. package/dist/vfs/async.d.ts +9 -23
  61. package/dist/vfs/async.js +25 -27
  62. package/dist/vfs/config.d.ts +6 -18
  63. package/dist/vfs/config.js +8 -18
  64. package/dist/vfs/dir.d.ts +3 -3
  65. package/dist/vfs/dir.js +12 -12
  66. package/dist/vfs/file.d.ts +106 -0
  67. package/dist/vfs/file.js +244 -0
  68. package/dist/vfs/flags.d.ts +19 -0
  69. package/dist/vfs/flags.js +62 -0
  70. package/dist/vfs/index.d.ts +4 -10
  71. package/dist/vfs/index.js +4 -13
  72. package/dist/vfs/ioctl.d.ts +88 -0
  73. package/dist/vfs/ioctl.js +409 -0
  74. package/dist/vfs/promises.d.ts +81 -19
  75. package/dist/vfs/promises.js +404 -288
  76. package/dist/vfs/shared.d.ts +7 -37
  77. package/dist/vfs/shared.js +29 -85
  78. package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
  79. package/dist/{stats.js → vfs/stats.js} +11 -66
  80. package/dist/vfs/streams.d.ts +1 -0
  81. package/dist/vfs/streams.js +32 -27
  82. package/dist/vfs/sync.d.ts +3 -3
  83. package/dist/vfs/sync.js +263 -260
  84. package/dist/vfs/watchers.d.ts +2 -2
  85. package/dist/vfs/watchers.js +12 -12
  86. package/dist/vfs/xattr.d.ts +116 -0
  87. package/dist/vfs/xattr.js +201 -0
  88. package/package.json +5 -3
  89. package/readme.md +1 -1
  90. package/scripts/test.js +2 -2
  91. package/tests/assignment.ts +1 -1
  92. package/tests/backend/config.worker.js +4 -1
  93. package/tests/backend/fetch.test.ts +3 -0
  94. package/tests/backend/port.test.ts +19 -33
  95. package/tests/backend/remote.worker.js +4 -1
  96. package/tests/backend/single-buffer.test.ts +53 -0
  97. package/tests/backend/single-buffer.worker.js +30 -0
  98. package/tests/common/context.test.ts +3 -3
  99. package/tests/common/handle.test.ts +17 -12
  100. package/tests/common/mutex.test.ts +9 -9
  101. package/tests/common/path.test.ts +1 -1
  102. package/tests/common/readline.test.ts +104 -0
  103. package/tests/common.ts +4 -19
  104. package/tests/fetch/fetch.ts +2 -2
  105. package/tests/fs/append.test.ts +4 -4
  106. package/tests/fs/directory.test.ts +25 -25
  107. package/tests/fs/errors.test.ts +15 -19
  108. package/tests/fs/links.test.ts +4 -3
  109. package/tests/fs/open.test.ts +4 -21
  110. package/tests/fs/permissions.test.ts +14 -18
  111. package/tests/fs/read.test.ts +10 -9
  112. package/tests/fs/readFile.test.ts +10 -26
  113. package/tests/fs/rename.test.ts +4 -9
  114. package/tests/fs/stat.test.ts +8 -8
  115. package/tests/fs/streams.test.ts +2 -11
  116. package/tests/fs/times.test.ts +7 -7
  117. package/tests/fs/truncate.test.ts +8 -36
  118. package/tests/fs/watch.test.ts +10 -10
  119. package/tests/fs/write.test.ts +77 -13
  120. package/tests/fs/xattr.test.ts +85 -0
  121. package/tests/logs.js +22 -0
  122. package/tests/setup/context.ts +1 -1
  123. package/tests/setup/index.ts +3 -3
  124. package/tests/setup/port.ts +7 -1
  125. package/dist/backends/port/fs.d.ts +0 -84
  126. package/dist/backends/port/fs.js +0 -151
  127. package/dist/backends/port/rpc.d.ts +0 -77
  128. package/dist/backends/port/rpc.js +0 -100
  129. package/dist/backends/store/simple.d.ts +0 -20
  130. package/dist/backends/store/simple.js +0 -13
  131. package/dist/internal/file.d.ts +0 -359
  132. package/dist/internal/file.js +0 -751
  133. package/dist/internal/log.d.ts +0 -133
  134. package/dist/internal/log.js +0 -218
  135. package/tests/fs/writeFile.test.ts +0 -70
@@ -1,751 +0,0 @@
1
- import { extendBuffer } from 'utilium/buffer.js';
2
- import { _chown, Stats } from '../stats.js';
3
- import { config } from '../vfs/config.js';
4
- import * as c from '../vfs/constants.js';
5
- import { Errno, ErrnoError } from './error.js';
6
- import { err, log_deprecated } from './log.js';
7
- import '../polyfills.js';
8
- const maxByteLength = 0xffff; // 64 KiB
9
- const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
10
- /**
11
- * @internal @hidden
12
- */
13
- export function parseFlag(flag) {
14
- if (typeof flag === 'number') {
15
- return flagToString(flag);
16
- }
17
- if (!validFlags.includes(flag)) {
18
- throw new Error('Invalid flag string: ' + flag);
19
- }
20
- return flag;
21
- }
22
- /**
23
- * @internal @hidden
24
- */
25
- export function flagToString(flag) {
26
- switch (flag) {
27
- case c.O_RDONLY:
28
- return 'r';
29
- case c.O_RDONLY | c.O_SYNC:
30
- return 'rs';
31
- case c.O_RDWR:
32
- return 'r+';
33
- case c.O_RDWR | c.O_SYNC:
34
- return 'rs+';
35
- case c.O_TRUNC | c.O_CREAT | c.O_WRONLY:
36
- return 'w';
37
- case c.O_TRUNC | c.O_CREAT | c.O_WRONLY | c.O_EXCL:
38
- return 'wx';
39
- case c.O_TRUNC | c.O_CREAT | c.O_RDWR:
40
- return 'w+';
41
- case c.O_TRUNC | c.O_CREAT | c.O_RDWR | c.O_EXCL:
42
- return 'wx+';
43
- case c.O_APPEND | c.O_CREAT | c.O_WRONLY:
44
- return 'a';
45
- case c.O_APPEND | c.O_CREAT | c.O_WRONLY | c.O_EXCL:
46
- return 'ax';
47
- case c.O_APPEND | c.O_CREAT | c.O_RDWR:
48
- return 'a+';
49
- case c.O_APPEND | c.O_CREAT | c.O_RDWR | c.O_EXCL:
50
- return 'ax+';
51
- default:
52
- throw new Error('Invalid flag number: ' + flag);
53
- }
54
- }
55
- /**
56
- * @internal @hidden
57
- */
58
- export function flagToNumber(flag) {
59
- switch (flag) {
60
- case 'r':
61
- return c.O_RDONLY;
62
- case 'rs':
63
- return c.O_RDONLY | c.O_SYNC;
64
- case 'r+':
65
- return c.O_RDWR;
66
- case 'rs+':
67
- return c.O_RDWR | c.O_SYNC;
68
- case 'w':
69
- return c.O_TRUNC | c.O_CREAT | c.O_WRONLY;
70
- case 'wx':
71
- return c.O_TRUNC | c.O_CREAT | c.O_WRONLY | c.O_EXCL;
72
- case 'w+':
73
- return c.O_TRUNC | c.O_CREAT | c.O_RDWR;
74
- case 'wx+':
75
- return c.O_TRUNC | c.O_CREAT | c.O_RDWR | c.O_EXCL;
76
- case 'a':
77
- return c.O_APPEND | c.O_CREAT | c.O_WRONLY;
78
- case 'ax':
79
- return c.O_APPEND | c.O_CREAT | c.O_WRONLY | c.O_EXCL;
80
- case 'a+':
81
- return c.O_APPEND | c.O_CREAT | c.O_RDWR;
82
- case 'ax+':
83
- return c.O_APPEND | c.O_CREAT | c.O_RDWR | c.O_EXCL;
84
- default:
85
- throw new Error('Invalid flag string: ' + flag);
86
- }
87
- }
88
- /**
89
- * Parses a flag as a mode (W_OK, R_OK, and/or X_OK)
90
- * @param flag the flag to parse
91
- * @internal @hidden
92
- */
93
- export function flagToMode(flag) {
94
- let mode = 0;
95
- mode <<= 1;
96
- mode += +isReadable(flag);
97
- mode <<= 1;
98
- mode += +isWriteable(flag);
99
- mode <<= 1;
100
- return mode;
101
- }
102
- /** @hidden */
103
- export function isReadable(flag) {
104
- return flag.indexOf('r') !== -1 || flag.indexOf('+') !== -1;
105
- }
106
- /** @hidden */
107
- export function isWriteable(flag) {
108
- return flag.indexOf('w') !== -1 || flag.indexOf('a') !== -1 || flag.indexOf('+') !== -1;
109
- }
110
- /** @hidden */
111
- export function isTruncating(flag) {
112
- return flag.indexOf('w') !== -1;
113
- }
114
- /** @hidden */
115
- export function isAppendable(flag) {
116
- return flag.indexOf('a') !== -1;
117
- }
118
- /** @hidden */
119
- export function isSynchronous(flag) {
120
- return flag.indexOf('s') !== -1;
121
- }
122
- /** @hidden */
123
- export function isExclusive(flag) {
124
- return flag.indexOf('x') !== -1;
125
- }
126
- /**
127
- * @category Internals
128
- */
129
- export class File {
130
- constructor(
131
- /**
132
- * @internal
133
- * The file system that created the file
134
- */
135
- fs, path) {
136
- this.fs = fs;
137
- this.path = path;
138
- }
139
- async [Symbol.asyncDispose]() {
140
- await this.close();
141
- }
142
- [Symbol.dispose]() {
143
- this.closeSync();
144
- }
145
- /**
146
- * Default implementation maps to `sync`.
147
- */
148
- datasync() {
149
- return this.sync();
150
- }
151
- /**
152
- * Default implementation maps to `syncSync`.
153
- */
154
- datasyncSync() {
155
- return this.syncSync();
156
- }
157
- /**
158
- * Create a stream for reading the file.
159
- */
160
- streamRead(options) {
161
- return this.fs.streamRead(this.path, options);
162
- }
163
- /**
164
- * Create a stream for writing the file.
165
- */
166
- streamWrite(options) {
167
- return this.fs.streamWrite(this.path, options);
168
- }
169
- }
170
- /**
171
- * An implementation of `File` that operates completely in-memory.
172
- * `PreloadFile`s are backed by a `Uint8Array`.
173
- * @category Internals
174
- */
175
- export class PreloadFile extends File {
176
- /**
177
- * Creates a file with `path` and, optionally, the given contents.
178
- * Note that, if contents is specified, it will be mutated by the file.
179
- */
180
- constructor(fs, path, flag, stats,
181
- /**
182
- * A buffer containing the entire contents of the file.
183
- */
184
- _buffer = new Uint8Array(new ArrayBuffer(0, fs.attributes.has('no_buffer_resize') ? {} : { maxByteLength }))) {
185
- super(fs, path);
186
- this.flag = flag;
187
- this.stats = stats;
188
- this._buffer = _buffer;
189
- /**
190
- * Current position
191
- */
192
- this._position = 0;
193
- /**
194
- * Whether the file has changes which have not been written to the FS
195
- */
196
- this.dirty = false;
197
- /**
198
- * Whether the file is open or closed
199
- */
200
- this.closed = false;
201
- /*
202
- Note:
203
- This invariant is *not* maintained once the file starts getting modified.
204
- It only actually matters if file is readable, as writeable modes may truncate/append to file.
205
- */
206
- if (this.stats.size == _buffer.byteLength)
207
- return;
208
- if (!isWriteable(this.flag)) {
209
- throw err(new ErrnoError(Errno.EIO, `Size mismatch: buffer length ${_buffer.byteLength}, stats size ${this.stats.size}`, path));
210
- }
211
- this.stats.size = _buffer.byteLength;
212
- this.dirty = true;
213
- }
214
- /**
215
- * Get the underlying buffer for this file. Mutating not recommended and will mess up dirty tracking.
216
- */
217
- get buffer() {
218
- return this._buffer;
219
- }
220
- /**
221
- * Get the current file position.
222
- *
223
- * We emulate the following bug mentioned in the Node documentation:
224
- *
225
- * On Linux, positional writes don't work when the file is opened in append mode.
226
- * The kernel ignores the position argument and always appends the data to the end of the file.
227
- * @returns The current file position.
228
- */
229
- get position() {
230
- if (isAppendable(this.flag)) {
231
- return this.stats.size;
232
- }
233
- return this._position;
234
- }
235
- set position(value) {
236
- this._position = value;
237
- }
238
- async sync() {
239
- if (this.closed)
240
- throw ErrnoError.With('EBADF', this.path, 'sync');
241
- if (!this.dirty)
242
- return;
243
- if (!this.fs.attributes.has('no_write'))
244
- await this.fs.sync(this.path, this._buffer, this.stats);
245
- this.dirty = false;
246
- }
247
- syncSync() {
248
- if (this.closed)
249
- throw ErrnoError.With('EBADF', this.path, 'sync');
250
- if (!this.dirty)
251
- return;
252
- if (!this.fs.attributes.has('no_write'))
253
- this.fs.syncSync(this.path, this._buffer, this.stats);
254
- this.dirty = false;
255
- }
256
- async close() {
257
- if (this.closed)
258
- throw ErrnoError.With('EBADF', this.path, 'close');
259
- await this.sync();
260
- this.dispose();
261
- }
262
- closeSync() {
263
- if (this.closed)
264
- throw ErrnoError.With('EBADF', this.path, 'close');
265
- this.syncSync();
266
- this.dispose();
267
- }
268
- /**
269
- * Cleans up. This will *not* sync the file data to the FS
270
- */
271
- dispose(force) {
272
- if (this.closed)
273
- throw ErrnoError.With('EBADF', this.path, 'dispose');
274
- if (this.dirty && !force) {
275
- throw ErrnoError.With('EBUSY', this.path, 'dispose');
276
- }
277
- this.closed = true;
278
- }
279
- stat() {
280
- if (this.closed)
281
- throw ErrnoError.With('EBADF', this.path, 'stat');
282
- return Promise.resolve(new Stats(this.stats));
283
- }
284
- statSync() {
285
- if (this.closed)
286
- throw ErrnoError.With('EBADF', this.path, 'stat');
287
- return new Stats(this.stats);
288
- }
289
- _truncate(length) {
290
- if (this.closed)
291
- throw ErrnoError.With('EBADF', this.path, 'truncate');
292
- this.dirty = true;
293
- if (!isWriteable(this.flag)) {
294
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode');
295
- }
296
- this.stats.mtimeMs = Date.now();
297
- if (length > this._buffer.length) {
298
- const data = new Uint8Array(length - this._buffer.length);
299
- // Write will set stats.size and handle syncing.
300
- this._write(data, 0, data.length, this._buffer.length);
301
- return;
302
- }
303
- this.stats.size = length;
304
- // Truncate.
305
- this._buffer = length ? this._buffer.subarray(0, length) : new Uint8Array();
306
- }
307
- async truncate(length) {
308
- this._truncate(length);
309
- if (config.syncImmediately)
310
- await this.sync();
311
- }
312
- truncateSync(length) {
313
- this._truncate(length);
314
- if (config.syncImmediately)
315
- this.syncSync();
316
- }
317
- _write(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
318
- if (this.closed)
319
- throw ErrnoError.With('EBADF', this.path, 'write');
320
- if (!isWriteable(this.flag)) {
321
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode');
322
- }
323
- this.dirty = true;
324
- const end = position + length;
325
- const slice = buffer.subarray(offset, offset + length);
326
- this._buffer = extendBuffer(this._buffer, end);
327
- if (end > this.stats.size)
328
- this.stats.size = end;
329
- this._buffer.set(slice, position);
330
- this.stats.mtimeMs = Date.now();
331
- this.position = position + slice.byteLength;
332
- return slice.byteLength;
333
- }
334
- /**
335
- * Write buffer to the file.
336
- * @param buffer Uint8Array containing the data to write to the file.
337
- * @param offset Offset in the buffer to start reading data from.
338
- * @param length The amount of bytes to write to the file.
339
- * @param position Offset from the beginning of the file where this data should be written.
340
- * If position is null, the data will be written at the current position.
341
- */
342
- async write(buffer, offset, length, position) {
343
- const bytesWritten = this._write(buffer, offset, length, position);
344
- if (config.syncImmediately)
345
- await this.sync();
346
- return bytesWritten;
347
- }
348
- /**
349
- * Write buffer to the file.
350
- * @param buffer Uint8Array containing the data to write to the file.
351
- * @param offset Offset in the buffer to start reading data from.
352
- * @param length The amount of bytes to write to the file.
353
- * @param position Offset from the beginning of the file where this data should be written.
354
- * If position is null, the data will be written at the current position.
355
- * @returns bytes written
356
- */
357
- writeSync(buffer, offset, length, position) {
358
- const bytesWritten = this._write(buffer, offset, length, position);
359
- if (config.syncImmediately)
360
- this.syncSync();
361
- return bytesWritten;
362
- }
363
- _read(buffer, offset = 0, length = buffer.byteLength - offset, position) {
364
- if (this.closed)
365
- throw ErrnoError.With('EBADF', this.path, 'read');
366
- if (!isReadable(this.flag)) {
367
- throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode');
368
- }
369
- if (config.updateOnRead) {
370
- this.dirty = true;
371
- }
372
- this.stats.atimeMs = Date.now();
373
- position !== null && position !== void 0 ? position : (position = this.position);
374
- let end = position + length;
375
- if (end > this.stats.size) {
376
- end = position + Math.max(this.stats.size - position, 0);
377
- }
378
- this._position = end;
379
- const bytesRead = end - position;
380
- if (bytesRead == 0) {
381
- // No copy/read. Return immediately for better performance
382
- return bytesRead;
383
- }
384
- const slice = this._buffer.subarray(position, end);
385
- new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength).set(slice, offset);
386
- return bytesRead;
387
- }
388
- /**
389
- * Read data from the file.
390
- * @param buffer The buffer that the data will be written to.
391
- * @param offset The offset within the buffer where writing will start.
392
- * @param length An integer specifying the number of bytes to read.
393
- * @param position An integer specifying where to begin reading from in the file.
394
- * If position is null, data will be read from the current file position.
395
- */
396
- async read(buffer, offset, length, position) {
397
- const bytesRead = this._read(buffer, offset, length, position);
398
- if (config.syncImmediately)
399
- await this.sync();
400
- return { bytesRead, buffer };
401
- }
402
- /**
403
- * Read data from the file.
404
- * @param buffer The buffer that the data will be written to.
405
- * @param offset The offset within the buffer where writing will start.
406
- * @param length An integer specifying the number of bytes to read.
407
- * @param position An integer specifying where to begin reading from in the file.
408
- * If position is null, data will be read from the current file position.
409
- * @returns number of bytes written
410
- */
411
- readSync(buffer, offset, length, position) {
412
- const bytesRead = this._read(buffer, offset, length, position);
413
- if (config.syncImmediately)
414
- this.syncSync();
415
- return bytesRead;
416
- }
417
- async chmod(mode) {
418
- if (this.closed)
419
- throw ErrnoError.With('EBADF', this.path, 'chmod');
420
- this.dirty = true;
421
- this.stats.mode = (this.stats.mode & (mode > c.S_IFMT ? ~c.S_IFMT : c.S_IFMT)) | mode;
422
- if (config.syncImmediately || mode > c.S_IFMT)
423
- await this.sync();
424
- }
425
- chmodSync(mode) {
426
- if (this.closed)
427
- throw ErrnoError.With('EBADF', this.path, 'chmod');
428
- this.dirty = true;
429
- this.stats.mode = (this.stats.mode & (mode > c.S_IFMT ? ~c.S_IFMT : c.S_IFMT)) | mode;
430
- if (config.syncImmediately || mode > c.S_IFMT)
431
- this.syncSync();
432
- }
433
- async chown(uid, gid) {
434
- if (this.closed)
435
- throw ErrnoError.With('EBADF', this.path, 'chown');
436
- this.dirty = true;
437
- _chown(this.stats, uid, gid);
438
- if (config.syncImmediately)
439
- await this.sync();
440
- }
441
- chownSync(uid, gid) {
442
- if (this.closed)
443
- throw ErrnoError.With('EBADF', this.path, 'chown');
444
- this.dirty = true;
445
- _chown(this.stats, uid, gid);
446
- if (config.syncImmediately)
447
- this.syncSync();
448
- }
449
- async utimes(atime, mtime) {
450
- if (this.closed)
451
- throw ErrnoError.With('EBADF', this.path, 'utimes');
452
- this.dirty = true;
453
- this.stats.atimeMs = atime;
454
- this.stats.mtimeMs = mtime;
455
- if (config.syncImmediately)
456
- await this.sync();
457
- }
458
- utimesSync(atime, mtime) {
459
- if (this.closed)
460
- throw ErrnoError.With('EBADF', this.path, 'utimes');
461
- this.dirty = true;
462
- this.stats.atimeMs = atime;
463
- this.stats.mtimeMs = mtime;
464
- if (config.syncImmediately)
465
- this.syncSync();
466
- }
467
- }
468
- /* node:coverage disable */
469
- /**
470
- * For the file systems which do not sync to anything.
471
- * @category Internals
472
- * @deprecated
473
- */
474
- export class NoSyncFile extends PreloadFile {
475
- constructor(...args) {
476
- log_deprecated('NoSyncFile');
477
- super(...args);
478
- }
479
- sync() {
480
- return Promise.resolve();
481
- }
482
- syncSync() { }
483
- close() {
484
- return Promise.resolve();
485
- }
486
- closeSync() { }
487
- }
488
- /* node:coverage enable */
489
- /**
490
- * An implementation of `File` that uses the FS
491
- * @category Internals
492
- */
493
- export class LazyFile extends File {
494
- /**
495
- * Get the current file position.
496
- *
497
- * We emulate the following bug mentioned in the Node documentation:
498
- *
499
- * On Linux, positional writes don't work when the file is opened in append mode.
500
- * The kernel ignores the position argument and always appends the data to the end of the file.
501
- * @returns The current file position.
502
- */
503
- get position() {
504
- return isAppendable(this.flag) ? this.stats.size : this._position;
505
- }
506
- set position(value) {
507
- this._position = value;
508
- }
509
- /**
510
- * Creates a file with `path` and, optionally, the given contents.
511
- * Note that, if contents is specified, it will be mutated by the file.
512
- */
513
- constructor(fs, path, flag, stats) {
514
- super(fs, path);
515
- this.flag = flag;
516
- this.stats = stats;
517
- /**
518
- * Current position
519
- */
520
- this._position = 0;
521
- /**
522
- * Whether the file has changes which have not been written to the FS
523
- */
524
- this.dirty = false;
525
- /**
526
- * Whether the file is open or closed
527
- */
528
- this.closed = false;
529
- }
530
- async sync() {
531
- if (this.closed)
532
- throw ErrnoError.With('EBADF', this.path, 'sync');
533
- if (!this.dirty)
534
- return;
535
- if (!this.fs.attributes.has('no_write'))
536
- await this.fs.sync(this.path, undefined, this.stats);
537
- this.dirty = false;
538
- }
539
- syncSync() {
540
- if (this.closed)
541
- throw ErrnoError.With('EBADF', this.path, 'sync');
542
- if (!this.dirty)
543
- return;
544
- if (!this.fs.attributes.has('no_write'))
545
- this.fs.syncSync(this.path, undefined, this.stats);
546
- this.dirty = false;
547
- }
548
- async close() {
549
- if (this.closed)
550
- throw ErrnoError.With('EBADF', this.path, 'close');
551
- await this.sync();
552
- this.dispose();
553
- }
554
- closeSync() {
555
- if (this.closed)
556
- throw ErrnoError.With('EBADF', this.path, 'close');
557
- this.syncSync();
558
- this.dispose();
559
- }
560
- /**
561
- * Cleans up. This will *not* sync the file data to the FS
562
- */
563
- dispose(force) {
564
- if (this.closed)
565
- throw ErrnoError.With('EBADF', this.path, 'dispose');
566
- if (this.dirty && !force)
567
- throw ErrnoError.With('EBUSY', this.path, 'dispose');
568
- this.closed = true;
569
- }
570
- stat() {
571
- if (this.closed)
572
- throw ErrnoError.With('EBADF', this.path, 'stat');
573
- return Promise.resolve(new Stats(this.stats));
574
- }
575
- statSync() {
576
- if (this.closed)
577
- throw ErrnoError.With('EBADF', this.path, 'stat');
578
- return new Stats(this.stats);
579
- }
580
- async truncate(length) {
581
- if (this.closed)
582
- throw ErrnoError.With('EBADF', this.path, 'truncate');
583
- this.dirty = true;
584
- if (!isWriteable(this.flag)) {
585
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode');
586
- }
587
- this.stats.mtimeMs = Date.now();
588
- this.stats.size = length;
589
- if (config.syncImmediately)
590
- await this.sync();
591
- }
592
- truncateSync(length) {
593
- if (this.closed)
594
- throw ErrnoError.With('EBADF', this.path, 'truncate');
595
- this.dirty = true;
596
- if (!isWriteable(this.flag)) {
597
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode');
598
- }
599
- this.stats.mtimeMs = Date.now();
600
- this.stats.size = length;
601
- if (config.syncImmediately)
602
- this.syncSync();
603
- }
604
- prepareWrite(buffer, offset, length, position) {
605
- if (this.closed)
606
- throw ErrnoError.With('EBADF', this.path, 'write');
607
- if (!isWriteable(this.flag)) {
608
- throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode');
609
- }
610
- this.dirty = true;
611
- const end = position + length;
612
- const slice = buffer.subarray(offset, offset + length);
613
- if (end > this.stats.size)
614
- this.stats.size = end;
615
- this.stats.mtimeMs = Date.now();
616
- this._position = position + slice.byteLength;
617
- return slice;
618
- }
619
- /**
620
- * Write buffer to the file.
621
- * @param buffer Uint8Array containing the data to write to the file.
622
- * @param offset Offset in the buffer to start reading data from.
623
- * @param length The amount of bytes to write to the file.
624
- * @param position Offset from the beginning of the file where this data should be written.
625
- * If position is null, the data will be written at the current position.
626
- */
627
- async write(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
628
- const slice = this.prepareWrite(buffer, offset, length, position);
629
- await this.fs.write(this.path, slice, position);
630
- if (config.syncImmediately)
631
- await this.sync();
632
- return slice.byteLength;
633
- }
634
- /**
635
- * Write buffer to the file.
636
- * @param buffer Uint8Array containing the data to write to the file.
637
- * @param offset Offset in the buffer to start reading data from.
638
- * @param length The amount of bytes to write to the file.
639
- * @param position Offset from the beginning of the file where this data should be written.
640
- * If position is null, the data will be written at the current position.
641
- * @returns bytes written
642
- */
643
- writeSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
644
- const slice = this.prepareWrite(buffer, offset, length, position);
645
- this.fs.writeSync(this.path, slice, position);
646
- if (config.syncImmediately)
647
- this.syncSync();
648
- return slice.byteLength;
649
- }
650
- /**
651
- * Computes position information for reading
652
- */
653
- prepareRead(length, position) {
654
- if (this.closed)
655
- throw ErrnoError.With('EBADF', this.path, 'read');
656
- if (!isReadable(this.flag))
657
- throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode');
658
- if (config.updateOnRead)
659
- this.dirty = true;
660
- this.stats.atimeMs = Date.now();
661
- let end = position + length;
662
- if (end > this.stats.size) {
663
- end = position + Math.max(this.stats.size - position, 0);
664
- }
665
- this._position = end;
666
- return end;
667
- }
668
- /**
669
- * Read data from the file.
670
- * @param buffer The buffer that the data will be written to.
671
- * @param offset The offset within the buffer where writing will start.
672
- * @param length An integer specifying the number of bytes to read.
673
- * @param position An integer specifying where to begin reading from in the file.
674
- * If position is unset, data will be read from the current file position.
675
- */
676
- async read(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
677
- const end = this.prepareRead(length, position);
678
- const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
679
- await this.fs.read(this.path, uint8.subarray(offset, offset + length), position, end);
680
- if (config.syncImmediately)
681
- await this.sync();
682
- return { bytesRead: end - position, buffer };
683
- }
684
- /**
685
- * Read data from the file.
686
- * @param buffer The buffer that the data will be written to.
687
- * @param offset The offset within the buffer where writing will start.
688
- * @param length An integer specifying the number of bytes to read.
689
- * @param position An integer specifying where to begin reading from in the file.
690
- * If position is null, data will be read from the current file position.
691
- * @returns number of bytes written
692
- */
693
- readSync(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
694
- const end = this.prepareRead(length, position);
695
- const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
696
- this.fs.readSync(this.path, uint8.subarray(offset, offset + length), position, end);
697
- if (config.syncImmediately)
698
- this.syncSync();
699
- return end - position;
700
- }
701
- async chmod(mode) {
702
- if (this.closed)
703
- throw ErrnoError.With('EBADF', this.path, 'chmod');
704
- this.dirty = true;
705
- this.stats.mode = (this.stats.mode & (mode > c.S_IFMT ? ~c.S_IFMT : c.S_IFMT)) | mode;
706
- if (config.syncImmediately || mode > c.S_IFMT)
707
- await this.sync();
708
- }
709
- chmodSync(mode) {
710
- if (this.closed)
711
- throw ErrnoError.With('EBADF', this.path, 'chmod');
712
- this.dirty = true;
713
- this.stats.mode = (this.stats.mode & (mode > c.S_IFMT ? ~c.S_IFMT : c.S_IFMT)) | mode;
714
- if (config.syncImmediately || mode > c.S_IFMT)
715
- this.syncSync();
716
- }
717
- async chown(uid, gid) {
718
- if (this.closed)
719
- throw ErrnoError.With('EBADF', this.path, 'chown');
720
- this.dirty = true;
721
- _chown(this.stats, uid, gid);
722
- if (config.syncImmediately)
723
- await this.sync();
724
- }
725
- chownSync(uid, gid) {
726
- if (this.closed)
727
- throw ErrnoError.With('EBADF', this.path, 'chown');
728
- this.dirty = true;
729
- _chown(this.stats, uid, gid);
730
- if (config.syncImmediately)
731
- this.syncSync();
732
- }
733
- async utimes(atime, mtime) {
734
- if (this.closed)
735
- throw ErrnoError.With('EBADF', this.path, 'utimes');
736
- this.dirty = true;
737
- this.stats.atimeMs = atime;
738
- this.stats.mtimeMs = mtime;
739
- if (config.syncImmediately)
740
- await this.sync();
741
- }
742
- utimesSync(atime, mtime) {
743
- if (this.closed)
744
- throw ErrnoError.With('EBADF', this.path, 'utimes');
745
- this.dirty = true;
746
- this.stats.atimeMs = atime;
747
- this.stats.mtimeMs = mtime;
748
- if (config.syncImmediately)
749
- this.syncSync();
750
- }
751
- }