@zenfs/core 0.0.12 → 0.2.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/ApiError.d.ts +52 -15
- package/dist/ApiError.js +77 -50
- package/dist/FileIndex.d.ts +32 -35
- package/dist/FileIndex.js +93 -109
- package/dist/backends/AsyncMirror.d.ts +42 -43
- package/dist/backends/AsyncMirror.js +154 -147
- package/dist/backends/AsyncStore.d.ts +29 -28
- package/dist/backends/AsyncStore.js +375 -482
- package/dist/backends/FolderAdapter.js +8 -19
- package/dist/backends/InMemory.d.ts +16 -13
- package/dist/backends/InMemory.js +29 -14
- package/dist/backends/Locked.d.ts +8 -28
- package/dist/backends/Locked.js +74 -224
- package/dist/backends/OverlayFS.d.ts +26 -34
- package/dist/backends/OverlayFS.js +303 -511
- package/dist/backends/SyncStore.d.ts +54 -72
- package/dist/backends/SyncStore.js +159 -161
- package/dist/backends/backend.d.ts +45 -29
- package/dist/backends/backend.js +83 -13
- package/dist/backends/index.d.ts +6 -7
- package/dist/backends/index.js +5 -6
- package/dist/browser.min.js +21 -6
- package/dist/browser.min.js.map +4 -4
- package/dist/emulation/callbacks.d.ts +119 -113
- package/dist/emulation/callbacks.js +129 -92
- package/dist/emulation/constants.js +1 -1
- package/dist/emulation/dir.d.ts +55 -0
- package/dist/emulation/dir.js +104 -0
- package/dist/emulation/fs.d.ts +1 -2
- package/dist/emulation/fs.js +0 -1
- package/dist/emulation/index.d.ts +3 -0
- package/dist/emulation/index.js +3 -0
- package/dist/emulation/promises.d.ts +265 -145
- package/dist/emulation/promises.js +526 -383
- package/dist/emulation/shared.d.ts +20 -6
- package/dist/emulation/shared.js +22 -23
- package/dist/emulation/streams.d.ts +102 -0
- package/dist/emulation/streams.js +55 -0
- package/dist/emulation/sync.d.ts +98 -69
- package/dist/emulation/sync.js +280 -133
- package/dist/file.d.ts +175 -173
- package/dist/file.js +257 -273
- package/dist/filesystem.d.ts +71 -244
- package/dist/filesystem.js +67 -472
- package/dist/index.d.ts +7 -44
- package/dist/index.js +22 -75
- package/dist/inode.d.ts +37 -28
- package/dist/inode.js +123 -65
- package/dist/stats.d.ts +91 -36
- package/dist/stats.js +138 -110
- package/dist/utils.d.ts +26 -13
- package/dist/utils.js +79 -107
- package/package.json +7 -4
- package/readme.md +2 -40
package/dist/file.js
CHANGED
|
@@ -1,80 +1,111 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { ApiError, ErrorCode } from './ApiError.js';
|
|
11
2
|
import { Stats } from './stats.js';
|
|
12
|
-
import {
|
|
3
|
+
import { O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_SYNC, S_IFMT } from './emulation/constants.js';
|
|
4
|
+
import { size_max } from './inode.js';
|
|
13
5
|
export var ActionType;
|
|
14
6
|
(function (ActionType) {
|
|
15
7
|
// Indicates that the code should not do anything.
|
|
16
8
|
ActionType[ActionType["NOP"] = 0] = "NOP";
|
|
17
9
|
// Indicates that the code should throw an exception.
|
|
18
|
-
ActionType[ActionType["
|
|
10
|
+
ActionType[ActionType["THROW"] = 1] = "THROW";
|
|
19
11
|
// Indicates that the code should truncate the file, but only if it is a file.
|
|
20
|
-
ActionType[ActionType["
|
|
12
|
+
ActionType[ActionType["TRUNCATE"] = 2] = "TRUNCATE";
|
|
21
13
|
// Indicates that the code should create the file.
|
|
22
|
-
ActionType[ActionType["
|
|
14
|
+
ActionType[ActionType["CREATE"] = 3] = "CREATE";
|
|
23
15
|
})(ActionType = ActionType || (ActionType = {}));
|
|
24
16
|
/**
|
|
25
17
|
* Represents one of the following file flags. A convenience object.
|
|
26
18
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
19
|
+
* - r: Open file for reading. An exception occurs if the file does not exist.
|
|
20
|
+
* - r+: Open file for reading and writing. An exception occurs if the file does not exist.
|
|
21
|
+
* - rs: Open file for reading in synchronous mode. Instructs the filesystem to not cache writes.
|
|
22
|
+
* - rs+: Open file for reading and writing, and opens the file in synchronous mode.
|
|
23
|
+
* - w: Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
|
|
24
|
+
* - wx: Like 'w' but opens the file in exclusive mode.
|
|
25
|
+
* - w+: Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
|
|
26
|
+
* - wx+: Like 'w+' but opens the file in exclusive mode.
|
|
27
|
+
* - a: Open file for appending. The file is created if it does not exist.
|
|
28
|
+
* - ax: Like 'a' but opens the file in exclusive mode.
|
|
29
|
+
* - a+: Open file for reading and appending. The file is created if it does not exist.
|
|
30
|
+
* - ax+: Like 'a+' but opens the file in exclusive mode.
|
|
39
31
|
*
|
|
40
32
|
* Exclusive mode ensures that the file path is newly created.
|
|
41
33
|
*/
|
|
42
34
|
export class FileFlag {
|
|
43
35
|
/**
|
|
44
36
|
* Get an object representing the given file flag.
|
|
45
|
-
* @param
|
|
37
|
+
* @param flag The string or number representing the flag
|
|
46
38
|
* @return The FileFlag object representing the flag
|
|
47
39
|
* @throw when the flag string is invalid
|
|
48
40
|
*/
|
|
49
|
-
static
|
|
41
|
+
static FromString(flag) {
|
|
50
42
|
// Check cache first.
|
|
51
|
-
if (!FileFlag.flagCache.has(
|
|
52
|
-
FileFlag.flagCache.set(
|
|
43
|
+
if (!FileFlag.flagCache.has(flag)) {
|
|
44
|
+
FileFlag.flagCache.set(flag, new FileFlag(flag));
|
|
53
45
|
}
|
|
54
|
-
return FileFlag.flagCache.get(
|
|
46
|
+
return FileFlag.flagCache.get(flag);
|
|
55
47
|
}
|
|
56
48
|
/**
|
|
57
49
|
* This should never be called directly.
|
|
58
|
-
* @param
|
|
59
|
-
* @throw when the
|
|
50
|
+
* @param flag The string or number representing the flag
|
|
51
|
+
* @throw when the flag is invalid
|
|
60
52
|
*/
|
|
61
|
-
constructor(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
constructor(flag) {
|
|
54
|
+
if (typeof flag === 'number') {
|
|
55
|
+
flag = FileFlag.NumberToString(flag);
|
|
56
|
+
}
|
|
57
|
+
if (FileFlag.validFlagStrs.indexOf(flag) < 0) {
|
|
58
|
+
throw new ApiError(ErrorCode.EINVAL, 'Invalid flag string: ' + flag);
|
|
59
|
+
}
|
|
60
|
+
this.flagStr = flag;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @param flag The number representing the flag
|
|
64
|
+
* @return The string representing the flag
|
|
65
|
+
* @throw when the flag number is invalid
|
|
66
|
+
*/
|
|
67
|
+
static NumberToString(flag) {
|
|
68
|
+
// based on https://github.com/nodejs/node/blob/abbdc3efaa455e6c907ebef5409ac8b0f222f969/lib/internal/fs/utils.js#L619
|
|
69
|
+
switch (flag) {
|
|
70
|
+
case O_RDONLY:
|
|
71
|
+
return 'r';
|
|
72
|
+
case O_RDONLY | O_SYNC:
|
|
73
|
+
return 'rs';
|
|
74
|
+
case O_RDWR:
|
|
75
|
+
return 'r+';
|
|
76
|
+
case O_RDWR | O_SYNC:
|
|
77
|
+
return 'rs+';
|
|
78
|
+
case O_TRUNC | O_CREAT | O_WRONLY:
|
|
79
|
+
return 'w';
|
|
80
|
+
case O_TRUNC | O_CREAT | O_WRONLY | O_EXCL:
|
|
81
|
+
return 'wx';
|
|
82
|
+
case O_TRUNC | O_CREAT | O_RDWR:
|
|
83
|
+
return 'w+';
|
|
84
|
+
case O_TRUNC | O_CREAT | O_RDWR | O_EXCL:
|
|
85
|
+
return 'wx+';
|
|
86
|
+
case O_APPEND | O_CREAT | O_WRONLY:
|
|
87
|
+
return 'a';
|
|
88
|
+
case O_APPEND | O_CREAT | O_WRONLY | O_EXCL:
|
|
89
|
+
return 'ax';
|
|
90
|
+
case O_APPEND | O_CREAT | O_RDWR:
|
|
91
|
+
return 'a+';
|
|
92
|
+
case O_APPEND | O_CREAT | O_RDWR | O_EXCL:
|
|
93
|
+
return 'ax+';
|
|
94
|
+
default:
|
|
95
|
+
throw new ApiError(ErrorCode.EINVAL, 'Invalid flag number: ' + flag);
|
|
65
96
|
}
|
|
66
97
|
}
|
|
67
98
|
/**
|
|
68
99
|
* Get the underlying flag string for this flag.
|
|
69
100
|
*/
|
|
70
|
-
|
|
101
|
+
toString() {
|
|
71
102
|
return this.flagStr;
|
|
72
103
|
}
|
|
73
104
|
/**
|
|
74
105
|
* Get the equivalent mode (0b0xxx: read, write, execute)
|
|
75
106
|
* Note: Execute will always be 0
|
|
76
107
|
*/
|
|
77
|
-
|
|
108
|
+
get mode() {
|
|
78
109
|
let mode = 0;
|
|
79
110
|
mode <<= 1;
|
|
80
111
|
mode += +this.isReadable();
|
|
@@ -125,14 +156,12 @@ export class FileFlag {
|
|
|
125
156
|
*/
|
|
126
157
|
pathExistsAction() {
|
|
127
158
|
if (this.isExclusive()) {
|
|
128
|
-
return ActionType.
|
|
129
|
-
}
|
|
130
|
-
else if (this.isTruncating()) {
|
|
131
|
-
return ActionType.TRUNCATE_FILE;
|
|
159
|
+
return ActionType.THROW;
|
|
132
160
|
}
|
|
133
|
-
|
|
134
|
-
return ActionType.
|
|
161
|
+
if (this.isTruncating()) {
|
|
162
|
+
return ActionType.TRUNCATE;
|
|
135
163
|
}
|
|
164
|
+
return ActionType.NOP;
|
|
136
165
|
}
|
|
137
166
|
/**
|
|
138
167
|
* Returns one of the static fields on this object that indicates the
|
|
@@ -140,10 +169,10 @@ export class FileFlag {
|
|
|
140
169
|
*/
|
|
141
170
|
pathNotExistsAction() {
|
|
142
171
|
if ((this.isWriteable() || this.isAppendable()) && this.flagStr !== 'r+') {
|
|
143
|
-
return ActionType.
|
|
172
|
+
return ActionType.CREATE;
|
|
144
173
|
}
|
|
145
174
|
else {
|
|
146
|
-
return ActionType.
|
|
175
|
+
return ActionType.THROW;
|
|
147
176
|
}
|
|
148
177
|
}
|
|
149
178
|
}
|
|
@@ -151,51 +180,23 @@ export class FileFlag {
|
|
|
151
180
|
FileFlag.flagCache = new Map();
|
|
152
181
|
// Array of valid mode strings.
|
|
153
182
|
FileFlag.validFlagStrs = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
syncSync() {
|
|
165
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
166
|
-
}
|
|
183
|
+
export class File {
|
|
184
|
+
/**
|
|
185
|
+
* Asynchronous `datasync`.
|
|
186
|
+
*
|
|
187
|
+
* Default implementation maps to `sync`.
|
|
188
|
+
*/
|
|
167
189
|
datasync() {
|
|
168
|
-
return
|
|
169
|
-
return this.sync();
|
|
170
|
-
});
|
|
190
|
+
return this.sync();
|
|
171
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Synchronous `datasync`.
|
|
194
|
+
*
|
|
195
|
+
* Default implementation maps to `syncSync`.
|
|
196
|
+
*/
|
|
172
197
|
datasyncSync() {
|
|
173
198
|
return this.syncSync();
|
|
174
199
|
}
|
|
175
|
-
chown(uid, gid) {
|
|
176
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
chownSync(uid, gid) {
|
|
181
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
182
|
-
}
|
|
183
|
-
chmod(mode) {
|
|
184
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
chmodSync(mode) {
|
|
189
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
190
|
-
}
|
|
191
|
-
utimes(atime, mtime) {
|
|
192
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
193
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
utimesSync(atime, mtime) {
|
|
197
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
198
|
-
}
|
|
199
200
|
}
|
|
200
201
|
/**
|
|
201
202
|
* An implementation of the File interface that operates on a file that is
|
|
@@ -206,59 +207,54 @@ export class BaseFile {
|
|
|
206
207
|
* extend this class and implement those two methods.
|
|
207
208
|
* @todo 'close' lever that disables functionality once closed.
|
|
208
209
|
*/
|
|
209
|
-
export class PreloadFile extends
|
|
210
|
+
export class PreloadFile extends File {
|
|
210
211
|
/**
|
|
211
212
|
* Creates a file with the given path and, optionally, the given contents. Note
|
|
212
213
|
* that, if contents is specified, it will be mutated by the file!
|
|
213
|
-
* @param _fs The file system that created the file.
|
|
214
|
-
* @param _path
|
|
215
214
|
* @param _mode The mode that the file was opened using.
|
|
216
215
|
* Dictates permissions and where the file pointer starts.
|
|
217
|
-
* @param
|
|
216
|
+
* @param stats The stats object for the given file.
|
|
218
217
|
* PreloadFile will mutate this object. Note that this object must contain
|
|
219
218
|
* the appropriate mode that the file was opened as.
|
|
220
|
-
* @param
|
|
219
|
+
* @param buffer A buffer containing the entire
|
|
221
220
|
* contents of the file. PreloadFile will mutate this buffer. If not
|
|
222
221
|
* specified, we assume it is a new file.
|
|
223
222
|
*/
|
|
224
|
-
constructor(
|
|
225
|
-
super();
|
|
226
|
-
this._pos = 0;
|
|
227
|
-
this._dirty = false;
|
|
228
|
-
this._fs = _fs;
|
|
229
|
-
this._path = _path;
|
|
230
|
-
this._flag = _flag;
|
|
231
|
-
this._stat = _stat;
|
|
232
|
-
this._buffer = contents ? contents : new Uint8Array(0);
|
|
233
|
-
// Note: This invariant is *not* maintained once the file starts getting
|
|
234
|
-
// modified.
|
|
235
|
-
// Note: Only actually matters if file is readable, as writeable modes may
|
|
236
|
-
// truncate/append to file.
|
|
237
|
-
if (this._stat.size !== this._buffer.length && this._flag.isReadable()) {
|
|
238
|
-
throw new Error(`Invalid buffer: Uint8Array is ${this._buffer.length} long, yet Stats object specifies that file is ${this._stat.size} long.`);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
223
|
+
constructor(
|
|
241
224
|
/**
|
|
242
|
-
*
|
|
225
|
+
* The file system that created the file.
|
|
243
226
|
*/
|
|
244
|
-
|
|
245
|
-
return this._buffer;
|
|
246
|
-
}
|
|
227
|
+
fs,
|
|
247
228
|
/**
|
|
248
|
-
*
|
|
229
|
+
* Path to the file
|
|
249
230
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
231
|
+
path, flag, stats, _buffer = new Uint8Array(new ArrayBuffer(0, { maxByteLength: size_max }))) {
|
|
232
|
+
super();
|
|
233
|
+
this.fs = fs;
|
|
234
|
+
this.path = path;
|
|
235
|
+
this.flag = flag;
|
|
236
|
+
this.stats = stats;
|
|
237
|
+
this._buffer = _buffer;
|
|
238
|
+
this._position = 0;
|
|
239
|
+
this._dirty = false;
|
|
240
|
+
/*
|
|
241
|
+
Note:
|
|
242
|
+
This invariant is *not* maintained once the file starts getting modified.
|
|
243
|
+
It only actually matters if file is readable, as writeable modes may truncate/append to file.
|
|
244
|
+
*/
|
|
245
|
+
if (this.stats.size == _buffer.byteLength) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (this.flag.isReadable()) {
|
|
249
|
+
throw new Error(`Size mismatch: buffer length ${_buffer.byteLength}, stats size ${this.stats.size}`);
|
|
250
|
+
}
|
|
251
|
+
this._dirty = true;
|
|
255
252
|
}
|
|
256
253
|
/**
|
|
257
|
-
* Get the
|
|
258
|
-
* @return [String] The path to the file.
|
|
254
|
+
* Get the underlying buffer for this file. Mutating not recommended and will mess up dirty tracking.
|
|
259
255
|
*/
|
|
260
|
-
|
|
261
|
-
return this.
|
|
256
|
+
get buffer() {
|
|
257
|
+
return this._buffer;
|
|
262
258
|
}
|
|
263
259
|
/**
|
|
264
260
|
* Get the current file position.
|
|
@@ -267,109 +263,66 @@ export class PreloadFile extends BaseFile {
|
|
|
267
263
|
* > On Linux, positional writes don't work when the file is opened in append
|
|
268
264
|
* mode. The kernel ignores the position argument and always appends the data
|
|
269
265
|
* to the end of the file.
|
|
270
|
-
* @return
|
|
266
|
+
* @return The current file position.
|
|
271
267
|
*/
|
|
272
|
-
|
|
273
|
-
if (this.
|
|
274
|
-
return this.
|
|
268
|
+
get position() {
|
|
269
|
+
if (this.flag.isAppendable()) {
|
|
270
|
+
return this.stats.size;
|
|
275
271
|
}
|
|
276
|
-
return this.
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Advance the current file position by the indicated number of positions.
|
|
280
|
-
* @param [Number] delta
|
|
281
|
-
*/
|
|
282
|
-
advancePos(delta) {
|
|
283
|
-
return (this._pos += delta);
|
|
272
|
+
return this._position;
|
|
284
273
|
}
|
|
285
274
|
/**
|
|
286
275
|
* Set the file position.
|
|
287
|
-
* @param
|
|
276
|
+
* @param newPos new position
|
|
288
277
|
*/
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* **Core**: Asynchronous sync. Must be implemented by subclasses of this
|
|
294
|
-
* class.
|
|
295
|
-
* @param [Function(ZenFS.ApiError)] cb
|
|
296
|
-
*/
|
|
297
|
-
sync() {
|
|
298
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
299
|
-
this.syncSync();
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* **Core**: Synchronous sync.
|
|
304
|
-
*/
|
|
305
|
-
syncSync() {
|
|
306
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* **Core**: Asynchronous close. Must be implemented by subclasses of this
|
|
310
|
-
* class.
|
|
311
|
-
* @param [Function(ZenFS.ApiError)] cb
|
|
312
|
-
*/
|
|
313
|
-
close() {
|
|
314
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
315
|
-
this.closeSync();
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* **Core**: Synchronous close.
|
|
320
|
-
*/
|
|
321
|
-
closeSync() {
|
|
322
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
278
|
+
set position(newPos) {
|
|
279
|
+
this._position = newPos;
|
|
323
280
|
}
|
|
324
281
|
/**
|
|
325
282
|
* Asynchronous `stat`.
|
|
326
|
-
* @param [Function(ZenFS.ApiError, ZenFS.node.fs.Stats)] cb
|
|
327
283
|
*/
|
|
328
|
-
stat() {
|
|
329
|
-
return
|
|
330
|
-
return Stats.clone(this._stat);
|
|
331
|
-
});
|
|
284
|
+
async stat() {
|
|
285
|
+
return Stats.clone(this.stats);
|
|
332
286
|
}
|
|
333
287
|
/**
|
|
334
288
|
* Synchronous `stat`.
|
|
335
289
|
*/
|
|
336
290
|
statSync() {
|
|
337
|
-
return Stats.clone(this.
|
|
291
|
+
return Stats.clone(this.stats);
|
|
338
292
|
}
|
|
339
293
|
/**
|
|
340
294
|
* Asynchronous truncate.
|
|
341
|
-
* @param
|
|
342
|
-
* @param [Function(ZenFS.ApiError)] cb
|
|
295
|
+
* @param len
|
|
343
296
|
*/
|
|
344
297
|
truncate(len) {
|
|
345
298
|
this.truncateSync(len);
|
|
346
|
-
if (this.
|
|
299
|
+
if (this.flag.isSynchronous() && !this.fs.metadata.synchronous) {
|
|
347
300
|
return this.sync();
|
|
348
301
|
}
|
|
349
302
|
}
|
|
350
303
|
/**
|
|
351
304
|
* Synchronous truncate.
|
|
352
|
-
* @param
|
|
305
|
+
* @param len
|
|
353
306
|
*/
|
|
354
307
|
truncateSync(len) {
|
|
355
308
|
this._dirty = true;
|
|
356
|
-
if (!this.
|
|
309
|
+
if (!this.flag.isWriteable()) {
|
|
357
310
|
throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
|
|
358
311
|
}
|
|
359
|
-
this.
|
|
312
|
+
this.stats.mtimeMs = Date.now();
|
|
360
313
|
if (len > this._buffer.length) {
|
|
361
314
|
const buf = new Uint8Array(len - this._buffer.length);
|
|
362
|
-
// Write will set
|
|
315
|
+
// Write will set stats.size for us.
|
|
363
316
|
this.writeSync(buf, 0, buf.length, this._buffer.length);
|
|
364
|
-
if (this.
|
|
317
|
+
if (this.flag.isSynchronous() && this.fs.metadata.synchronous) {
|
|
365
318
|
this.syncSync();
|
|
366
319
|
}
|
|
367
320
|
return;
|
|
368
321
|
}
|
|
369
|
-
this.
|
|
322
|
+
this.stats.size = len;
|
|
370
323
|
// Truncate buffer to 'len'.
|
|
371
324
|
this._buffer = this._buffer.subarray(0, len);
|
|
372
|
-
if (this.
|
|
325
|
+
if (this.flag.isSynchronous() && this.fs.metadata.synchronous) {
|
|
373
326
|
this.syncSync();
|
|
374
327
|
}
|
|
375
328
|
}
|
|
@@ -377,150 +330,155 @@ export class PreloadFile extends BaseFile {
|
|
|
377
330
|
* Write buffer to the file.
|
|
378
331
|
* Note that it is unsafe to use fs.write multiple times on the same file
|
|
379
332
|
* without waiting for the callback.
|
|
380
|
-
* @param
|
|
333
|
+
* @param buffer Uint8Array containing the data to write to
|
|
381
334
|
* the file.
|
|
382
|
-
* @param
|
|
383
|
-
* @param
|
|
384
|
-
* @param
|
|
335
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
336
|
+
* @param length The amount of bytes to write to the file.
|
|
337
|
+
* @param position Offset from the beginning of the file where this
|
|
385
338
|
* data should be written. If position is null, the data will be written at
|
|
386
339
|
* the current position.
|
|
387
|
-
* @param [Function(ZenFS.ApiError, Number, ZenFS.node.Uint8Array)]
|
|
388
|
-
* cb The number specifies the number of bytes written into the file.
|
|
389
340
|
*/
|
|
390
|
-
write(buffer, offset, length, position) {
|
|
391
|
-
return
|
|
392
|
-
return this.writeSync(buffer, offset, length, position);
|
|
393
|
-
});
|
|
341
|
+
async write(buffer, offset = 0, length = this.stats.size, position = 0) {
|
|
342
|
+
return this.writeSync(buffer, offset, length, position);
|
|
394
343
|
}
|
|
395
344
|
/**
|
|
396
345
|
* Write buffer to the file.
|
|
397
346
|
* Note that it is unsafe to use fs.writeSync multiple times on the same file
|
|
398
347
|
* without waiting for the callback.
|
|
399
|
-
* @param
|
|
348
|
+
* @param buffer Uint8Array containing the data to write to
|
|
400
349
|
* the file.
|
|
401
|
-
* @param
|
|
402
|
-
* @param
|
|
403
|
-
* @param
|
|
350
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
351
|
+
* @param length The amount of bytes to write to the file.
|
|
352
|
+
* @param position Offset from the beginning of the file where this
|
|
404
353
|
* data should be written. If position is null, the data will be written at
|
|
405
354
|
* the current position.
|
|
406
|
-
* @
|
|
355
|
+
* @returns bytes written
|
|
407
356
|
*/
|
|
408
|
-
writeSync(buffer, offset, length, position) {
|
|
357
|
+
writeSync(buffer, offset = 0, length = this.stats.size, position = 0) {
|
|
409
358
|
this._dirty = true;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
if (!this._flag.isWriteable()) {
|
|
359
|
+
position ?? (position = this.position);
|
|
360
|
+
if (!this.flag.isWriteable()) {
|
|
414
361
|
throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
|
|
415
362
|
}
|
|
416
363
|
const endFp = position + length;
|
|
417
|
-
if (endFp > this.
|
|
418
|
-
this.
|
|
419
|
-
if (endFp > this._buffer.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
364
|
+
if (endFp > this.stats.size) {
|
|
365
|
+
this.stats.size = endFp;
|
|
366
|
+
if (endFp > this._buffer.byteLength) {
|
|
367
|
+
if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength <= endFp) {
|
|
368
|
+
this._buffer.buffer.resize(endFp);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
// Extend the buffer!
|
|
372
|
+
const newBuffer = new Uint8Array(new ArrayBuffer(endFp, { maxByteLength: size_max }));
|
|
373
|
+
newBuffer.set(this._buffer);
|
|
374
|
+
this._buffer = newBuffer;
|
|
375
|
+
}
|
|
424
376
|
}
|
|
425
377
|
}
|
|
426
378
|
this._buffer.set(buffer.slice(offset, offset + length), position);
|
|
427
|
-
const len = this._buffer.
|
|
428
|
-
this.
|
|
429
|
-
if (this.
|
|
379
|
+
const len = this._buffer.byteOffset;
|
|
380
|
+
this.stats.mtimeMs = Date.now();
|
|
381
|
+
if (this.flag.isSynchronous()) {
|
|
430
382
|
this.syncSync();
|
|
431
383
|
return len;
|
|
432
384
|
}
|
|
433
|
-
this.
|
|
385
|
+
this.position = position + len;
|
|
434
386
|
return len;
|
|
435
387
|
}
|
|
436
388
|
/**
|
|
437
389
|
* Read data from the file.
|
|
438
|
-
* @param
|
|
390
|
+
* @param buffer The buffer that the data will be
|
|
439
391
|
* written to.
|
|
440
|
-
* @param
|
|
392
|
+
* @param offset The offset within the buffer where writing will
|
|
441
393
|
* start.
|
|
442
|
-
* @param
|
|
443
|
-
* @param
|
|
394
|
+
* @param length An integer specifying the number of bytes to read.
|
|
395
|
+
* @param position An integer specifying where to begin reading from
|
|
444
396
|
* in the file. If position is null, data will be read from the current file
|
|
445
397
|
* position.
|
|
446
|
-
* @param [Function(ZenFS.ApiError, Number, ZenFS.node.Uint8Array)] cb The
|
|
447
|
-
* number is the number of bytes read
|
|
448
398
|
*/
|
|
449
|
-
read(buffer, offset, length, position) {
|
|
450
|
-
return
|
|
451
|
-
return { bytesRead: this.readSync(buffer, offset, length, position), buffer };
|
|
452
|
-
});
|
|
399
|
+
async read(buffer, offset = 0, length = this.stats.size, position = 0) {
|
|
400
|
+
return { bytesRead: this.readSync(buffer, offset, length, position), buffer };
|
|
453
401
|
}
|
|
454
402
|
/**
|
|
455
403
|
* Read data from the file.
|
|
456
|
-
* @param
|
|
404
|
+
* @param buffer The buffer that the data will be
|
|
457
405
|
* written to.
|
|
458
|
-
* @param
|
|
459
|
-
*
|
|
460
|
-
* @param
|
|
461
|
-
* @param [Number] position An integer specifying where to begin reading from
|
|
406
|
+
* @param offset The offset within the buffer where writing will start.
|
|
407
|
+
* @param length An integer specifying the number of bytes to read.
|
|
408
|
+
* @param position An integer specifying where to begin reading from
|
|
462
409
|
* in the file. If position is null, data will be read from the current file
|
|
463
410
|
* position.
|
|
464
|
-
* @
|
|
411
|
+
* @returns number of bytes written
|
|
465
412
|
*/
|
|
466
|
-
readSync(buffer, offset, length, position) {
|
|
467
|
-
if (!this.
|
|
413
|
+
readSync(buffer, offset = 0, length = this.stats.size, position = 0) {
|
|
414
|
+
if (!this.flag.isReadable()) {
|
|
468
415
|
throw new ApiError(ErrorCode.EPERM, 'File not opened with a readable mode.');
|
|
469
416
|
}
|
|
470
|
-
|
|
471
|
-
|
|
417
|
+
position ?? (position = this.position);
|
|
418
|
+
let end = position + length;
|
|
419
|
+
if (end > this.stats.size) {
|
|
420
|
+
end = position + Math.max(this.stats.size - position, 0);
|
|
472
421
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
422
|
+
this.stats.atimeMs = Date.now();
|
|
423
|
+
this._position = end;
|
|
424
|
+
const bytesRead = end - position;
|
|
425
|
+
if (bytesRead == 0) {
|
|
426
|
+
// No copy/read. Return immediatly for better performance
|
|
427
|
+
return bytesRead;
|
|
476
428
|
}
|
|
477
|
-
this._buffer.
|
|
478
|
-
|
|
479
|
-
this._pos = position + length;
|
|
480
|
-
return this._buffer.length;
|
|
429
|
+
buffer.set(this._buffer.slice(position, end), offset);
|
|
430
|
+
return bytesRead;
|
|
481
431
|
}
|
|
482
432
|
/**
|
|
483
433
|
* Asynchronous `fchmod`.
|
|
484
|
-
* @param
|
|
434
|
+
* @param mode the mode
|
|
485
435
|
*/
|
|
486
|
-
chmod(mode) {
|
|
487
|
-
|
|
488
|
-
this.chmodSync(mode);
|
|
489
|
-
});
|
|
436
|
+
async chmod(mode) {
|
|
437
|
+
this.chmodSync(mode);
|
|
490
438
|
}
|
|
491
439
|
/**
|
|
492
440
|
* Synchronous `fchmod`.
|
|
493
|
-
* @param
|
|
441
|
+
* @param mode
|
|
494
442
|
*/
|
|
495
443
|
chmodSync(mode) {
|
|
496
|
-
if (!this.
|
|
444
|
+
if (!this.fs.metadata.supportsProperties) {
|
|
497
445
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
498
446
|
}
|
|
499
447
|
this._dirty = true;
|
|
500
|
-
this.
|
|
448
|
+
this.stats.chmod(mode);
|
|
501
449
|
this.syncSync();
|
|
502
450
|
}
|
|
503
451
|
/**
|
|
504
452
|
* Asynchronous `fchown`.
|
|
505
|
-
* @param
|
|
506
|
-
* @param
|
|
453
|
+
* @param uid
|
|
454
|
+
* @param gid
|
|
507
455
|
*/
|
|
508
|
-
chown(uid, gid) {
|
|
509
|
-
|
|
510
|
-
this.chownSync(uid, gid);
|
|
511
|
-
});
|
|
456
|
+
async chown(uid, gid) {
|
|
457
|
+
this.chownSync(uid, gid);
|
|
512
458
|
}
|
|
513
459
|
/**
|
|
514
460
|
* Synchronous `fchown`.
|
|
515
|
-
* @param
|
|
516
|
-
* @param
|
|
461
|
+
* @param uid
|
|
462
|
+
* @param gid
|
|
517
463
|
*/
|
|
518
464
|
chownSync(uid, gid) {
|
|
519
|
-
if (!this.
|
|
465
|
+
if (!this.fs.metadata.supportsProperties) {
|
|
520
466
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
521
467
|
}
|
|
522
468
|
this._dirty = true;
|
|
523
|
-
this.
|
|
469
|
+
this.stats.chown(uid, gid);
|
|
470
|
+
this.syncSync();
|
|
471
|
+
}
|
|
472
|
+
async utimes(atime, mtime) {
|
|
473
|
+
this.utimesSync(atime, mtime);
|
|
474
|
+
}
|
|
475
|
+
utimesSync(atime, mtime) {
|
|
476
|
+
if (!this.fs.metadata.supportsProperties) {
|
|
477
|
+
throw new ApiError(ErrorCode.ENOTSUP);
|
|
478
|
+
}
|
|
479
|
+
this._dirty = true;
|
|
480
|
+
this.stats.atime = atime;
|
|
481
|
+
this.stats.mtime = mtime;
|
|
524
482
|
this.syncSync();
|
|
525
483
|
}
|
|
526
484
|
isDirty() {
|
|
@@ -532,10 +490,42 @@ export class PreloadFile extends BaseFile {
|
|
|
532
490
|
resetDirty() {
|
|
533
491
|
this._dirty = false;
|
|
534
492
|
}
|
|
493
|
+
_setType(type) {
|
|
494
|
+
this._dirty = true;
|
|
495
|
+
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
496
|
+
return this.sync();
|
|
497
|
+
}
|
|
498
|
+
_setTypeSync(type) {
|
|
499
|
+
this._dirty = true;
|
|
500
|
+
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
501
|
+
this.syncSync();
|
|
502
|
+
}
|
|
535
503
|
}
|
|
536
504
|
/**
|
|
537
|
-
*
|
|
538
|
-
|
|
505
|
+
* For synchronous file systems
|
|
506
|
+
*/
|
|
507
|
+
export class SyncFile extends PreloadFile {
|
|
508
|
+
constructor(_fs, _path, _flag, _stat, contents) {
|
|
509
|
+
super(_fs, _path, _flag, _stat, contents);
|
|
510
|
+
}
|
|
511
|
+
async sync() {
|
|
512
|
+
this.syncSync();
|
|
513
|
+
}
|
|
514
|
+
syncSync() {
|
|
515
|
+
if (this.isDirty()) {
|
|
516
|
+
this.fs.syncSync(this.path, this._buffer, this.stats);
|
|
517
|
+
this.resetDirty();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async close() {
|
|
521
|
+
this.closeSync();
|
|
522
|
+
}
|
|
523
|
+
closeSync() {
|
|
524
|
+
this.syncSync();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* For the filesystems which do not sync to anything..
|
|
539
529
|
*/
|
|
540
530
|
export class NoSyncFile extends PreloadFile {
|
|
541
531
|
constructor(_fs, _path, _flag, _stat, contents) {
|
|
@@ -543,12 +533,9 @@ export class NoSyncFile extends PreloadFile {
|
|
|
543
533
|
}
|
|
544
534
|
/**
|
|
545
535
|
* Asynchronous sync. Doesn't do anything, simply calls the cb.
|
|
546
|
-
* @param [Function(ZenFS.ApiError)] cb
|
|
547
536
|
*/
|
|
548
|
-
sync() {
|
|
549
|
-
return
|
|
550
|
-
return;
|
|
551
|
-
});
|
|
537
|
+
async sync() {
|
|
538
|
+
return;
|
|
552
539
|
}
|
|
553
540
|
/**
|
|
554
541
|
* Synchronous sync. Doesn't do anything.
|
|
@@ -558,12 +545,9 @@ export class NoSyncFile extends PreloadFile {
|
|
|
558
545
|
}
|
|
559
546
|
/**
|
|
560
547
|
* Asynchronous close. Doesn't do anything, simply calls the cb.
|
|
561
|
-
* @param [Function(ZenFS.ApiError)] cb
|
|
562
548
|
*/
|
|
563
|
-
close() {
|
|
564
|
-
return
|
|
565
|
-
return;
|
|
566
|
-
});
|
|
549
|
+
async close() {
|
|
550
|
+
return;
|
|
567
551
|
}
|
|
568
552
|
/**
|
|
569
553
|
* Synchronous close. Doesn't do anything.
|