@zenfs/core 1.11.4 → 2.0.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.
- package/dist/backends/backend.d.ts +19 -15
- package/dist/backends/backend.js +31 -15
- package/dist/backends/cow.d.ts +20 -30
- package/dist/backends/cow.js +52 -142
- package/dist/backends/fetch.d.ts +1 -0
- package/dist/backends/fetch.js +3 -1
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/backends/memory.d.ts +5 -7
- package/dist/backends/memory.js +2 -3
- package/dist/backends/passthrough.d.ts +19 -22
- package/dist/backends/passthrough.js +85 -160
- package/dist/backends/port.d.ts +207 -0
- package/dist/backends/port.js +297 -0
- package/dist/backends/single_buffer.d.ts +11 -5
- package/dist/backends/single_buffer.js +18 -12
- package/dist/backends/store/fs.d.ts +11 -27
- package/dist/backends/store/fs.js +67 -91
- package/dist/backends/store/store.d.ts +7 -12
- package/dist/config.d.ts +1 -10
- package/dist/config.js +7 -8
- package/dist/context.d.ts +8 -21
- package/dist/context.js +33 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/contexts.d.ts +63 -0
- package/dist/internal/contexts.js +15 -0
- package/dist/internal/credentials.d.ts +2 -11
- package/dist/internal/credentials.js +0 -19
- package/dist/internal/devices.d.ts +18 -80
- package/dist/internal/devices.js +76 -279
- package/dist/internal/file_index.js +3 -3
- package/dist/internal/filesystem.d.ts +31 -89
- package/dist/internal/filesystem.js +21 -20
- package/dist/internal/index.d.ts +0 -1
- package/dist/internal/index.js +0 -1
- package/dist/internal/index_fs.d.ts +12 -30
- package/dist/internal/index_fs.js +23 -55
- package/dist/internal/inode.d.ts +147 -9
- package/dist/internal/inode.js +333 -25
- package/dist/internal/log.d.ts +19 -13
- package/dist/internal/log.js +81 -80
- package/dist/mixins/async.js +26 -90
- package/dist/mixins/mutexed.d.ts +17 -16
- package/dist/mixins/mutexed.js +29 -31
- package/dist/mixins/readonly.d.ts +7 -6
- package/dist/mixins/readonly.js +6 -0
- package/dist/mixins/sync.js +8 -8
- package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
- package/dist/{vfs/path.js → path.js} +6 -9
- package/dist/readline.d.ts +134 -0
- package/dist/readline.js +623 -0
- package/dist/utils.d.ts +4 -35
- package/dist/utils.js +8 -73
- package/dist/vfs/acl.d.ts +42 -0
- package/dist/vfs/acl.js +249 -0
- package/dist/vfs/async.d.ts +7 -21
- package/dist/vfs/async.js +19 -19
- package/dist/vfs/config.d.ts +6 -18
- package/dist/vfs/config.js +8 -18
- package/dist/vfs/dir.d.ts +3 -3
- package/dist/vfs/dir.js +9 -8
- package/dist/vfs/file.d.ts +106 -0
- package/dist/vfs/file.js +235 -0
- package/dist/vfs/flags.d.ts +19 -0
- package/dist/vfs/flags.js +62 -0
- package/dist/vfs/index.d.ts +4 -10
- package/dist/vfs/index.js +4 -13
- package/dist/vfs/ioctl.d.ts +87 -0
- package/dist/vfs/ioctl.js +304 -0
- package/dist/vfs/promises.d.ts +78 -16
- package/dist/vfs/promises.js +273 -122
- package/dist/vfs/shared.d.ts +7 -26
- package/dist/vfs/shared.js +25 -53
- package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
- package/dist/{stats.js → vfs/stats.js} +11 -66
- package/dist/vfs/streams.d.ts +1 -0
- package/dist/vfs/streams.js +24 -19
- package/dist/vfs/sync.d.ts +4 -3
- package/dist/vfs/sync.js +143 -128
- package/dist/vfs/watchers.d.ts +2 -2
- package/dist/vfs/watchers.js +6 -6
- package/dist/vfs/xattr.d.ts +116 -0
- package/dist/vfs/xattr.js +218 -0
- package/package.json +3 -3
- package/readme.md +1 -1
- package/tests/backend/config.worker.js +4 -1
- package/tests/backend/fetch.test.ts +3 -0
- package/tests/backend/port.test.ts +21 -35
- package/tests/backend/remote.worker.js +4 -1
- package/tests/backend/single-buffer.test.ts +24 -0
- package/tests/common/context.test.ts +1 -1
- package/tests/common/handle.test.ts +17 -12
- package/tests/common/path.test.ts +1 -1
- package/tests/common/readline.test.ts +104 -0
- package/tests/common.ts +4 -19
- package/tests/fetch/fetch.ts +1 -1
- package/tests/fs/links.test.ts +1 -1
- package/tests/fs/permissions.test.ts +7 -6
- package/tests/fs/readFile.test.ts +3 -3
- package/tests/fs/stat.test.ts +6 -6
- package/tests/fs/streams.test.ts +2 -11
- package/tests/fs/times.test.ts +1 -1
- package/tests/fs/xattr.test.ts +85 -0
- package/tests/logs.js +22 -0
- package/tests/setup/context.ts +1 -1
- package/tests/setup/index.ts +3 -3
- package/tests/setup/port.ts +1 -1
- package/dist/backends/port/fs.d.ts +0 -84
- package/dist/backends/port/fs.js +0 -151
- package/dist/backends/port/rpc.d.ts +0 -77
- package/dist/backends/port/rpc.js +0 -100
- package/dist/backends/store/simple.d.ts +0 -20
- package/dist/backends/store/simple.js +0 -13
- package/dist/internal/file.d.ts +0 -359
- package/dist/internal/file.js +0 -751
package/dist/internal/file.js
DELETED
|
@@ -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
|
-
}
|