@zenfs/core 0.1.0 → 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.
Files changed (44) hide show
  1. package/dist/ApiError.d.ts +51 -14
  2. package/dist/ApiError.js +60 -34
  3. package/dist/FileIndex.d.ts +32 -35
  4. package/dist/FileIndex.js +93 -109
  5. package/dist/backends/AsyncMirror.d.ts +42 -43
  6. package/dist/backends/AsyncMirror.js +146 -133
  7. package/dist/backends/AsyncStore.d.ts +29 -28
  8. package/dist/backends/AsyncStore.js +139 -189
  9. package/dist/backends/InMemory.d.ts +16 -13
  10. package/dist/backends/InMemory.js +29 -14
  11. package/dist/backends/Locked.d.ts +8 -28
  12. package/dist/backends/Locked.js +44 -148
  13. package/dist/backends/OverlayFS.d.ts +26 -34
  14. package/dist/backends/OverlayFS.js +208 -371
  15. package/dist/backends/SyncStore.d.ts +54 -72
  16. package/dist/backends/SyncStore.js +159 -161
  17. package/dist/backends/backend.d.ts +45 -29
  18. package/dist/backends/backend.js +83 -13
  19. package/dist/backends/index.d.ts +6 -7
  20. package/dist/backends/index.js +5 -6
  21. package/dist/browser.min.js +5 -7
  22. package/dist/browser.min.js.map +4 -4
  23. package/dist/emulation/callbacks.d.ts +36 -67
  24. package/dist/emulation/callbacks.js +90 -46
  25. package/dist/emulation/constants.js +1 -1
  26. package/dist/emulation/promises.d.ts +228 -129
  27. package/dist/emulation/promises.js +414 -172
  28. package/dist/emulation/shared.d.ts +10 -10
  29. package/dist/emulation/shared.js +18 -20
  30. package/dist/emulation/sync.d.ts +25 -25
  31. package/dist/emulation/sync.js +187 -73
  32. package/dist/file.d.ts +166 -170
  33. package/dist/file.js +199 -218
  34. package/dist/filesystem.d.ts +68 -241
  35. package/dist/filesystem.js +59 -383
  36. package/dist/index.d.ts +7 -44
  37. package/dist/index.js +13 -52
  38. package/dist/inode.d.ts +37 -28
  39. package/dist/inode.js +123 -65
  40. package/dist/stats.d.ts +21 -19
  41. package/dist/stats.js +35 -56
  42. package/dist/utils.d.ts +26 -9
  43. package/dist/utils.js +73 -102
  44. package/package.json +4 -3
@@ -1,10 +1,10 @@
1
1
  import { ApiError, ErrorCode } from '../ApiError.js';
2
- import { FileFlag } from '../file.js';
3
- import { BigIntStats } from '../stats.js';
2
+ import { ActionType, FileFlag } from '../file.js';
3
+ import { BigIntStats, FileType } from '../stats.js';
4
4
  import { normalizePath, cred, getFdForFile, normalizeMode, normalizeOptions, fdMap, fd2file, normalizeTime, resolveFS, fixError, mounts, } from './shared.js';
5
5
  import { decode, encode } from '../utils.js';
6
6
  import { Dirent } from './dir.js';
7
- import { join } from './path.js';
7
+ import { dirname, join } from './path.js';
8
8
  function doOp(...[name, resolveSymlinks, path, ...args]) {
9
9
  path = normalizePath(path);
10
10
  const { fs, path: resolvedPath } = resolveFS(resolveSymlinks && existsSync(path) ? realpathSync(path) : path);
@@ -74,10 +74,13 @@ lstatSync;
74
74
  * @param len
75
75
  */
76
76
  export function truncateSync(path, len = 0) {
77
- if (len < 0) {
78
- throw new ApiError(ErrorCode.EINVAL);
77
+ const fd = openSync(path, 'r+');
78
+ try {
79
+ ftruncateSync(fd, len);
80
+ }
81
+ finally {
82
+ closeSync(fd);
79
83
  }
80
- return doOp('truncateSync', true, path, len, cred);
81
84
  }
82
85
  truncateSync;
83
86
  /**
@@ -88,51 +91,146 @@ export function unlinkSync(path) {
88
91
  return doOp('unlinkSync', false, path, cred);
89
92
  }
90
93
  unlinkSync;
94
+ function _openSync(_path, _flag, _mode, resolveSymlinks) {
95
+ const path = normalizePath(_path), mode = normalizeMode(_mode, 0o644), flag = FileFlag.FromString(_flag);
96
+ // Check if the path exists, and is a file.
97
+ let stats;
98
+ try {
99
+ stats = doOp('statSync', resolveSymlinks, path, cred);
100
+ }
101
+ catch (e) {
102
+ // File does not exist.
103
+ switch (flag.pathNotExistsAction()) {
104
+ case ActionType.CREATE:
105
+ // Ensure parent exists.
106
+ const parentStats = doOp('statSync', resolveSymlinks, dirname(path), cred);
107
+ if (!parentStats.isDirectory()) {
108
+ throw ApiError.ENOTDIR(dirname(path));
109
+ }
110
+ return doOp('createFileSync', resolveSymlinks, path, flag, mode, cred);
111
+ case ActionType.THROW:
112
+ throw ApiError.ENOENT(path);
113
+ default:
114
+ throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
115
+ }
116
+ }
117
+ if (!stats.hasAccess(mode, cred)) {
118
+ throw ApiError.EACCES(path);
119
+ }
120
+ // File exists.
121
+ switch (flag.pathExistsAction()) {
122
+ case ActionType.THROW:
123
+ throw ApiError.EEXIST(path);
124
+ case ActionType.TRUNCATE:
125
+ // Delete file.
126
+ doOp('unlinkSync', resolveSymlinks, path, cred);
127
+ /*
128
+ Create file. Use the same mode as the old file.
129
+ Node itself modifies the ctime when this occurs, so this action
130
+ will preserve that behavior if the underlying file system
131
+ supports those properties.
132
+ */
133
+ return doOp('createFileSync', resolveSymlinks, path, flag, stats.mode, cred);
134
+ case ActionType.NOP:
135
+ return doOp('openFileSync', resolveSymlinks, path, flag, cred);
136
+ default:
137
+ throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
138
+ }
139
+ }
91
140
  /**
92
141
  * Synchronous file open.
93
142
  * @see http://www.manpagez.com/man/2/open/
94
- * @param path
95
- * @param flags
96
- * @param mode defaults to `0644`
97
- * @returns file descriptor
143
+ * @param flags Handles the complexity of the various file
144
+ * modes. See its API for more details.
145
+ * @param mode Mode to use to open the file. Can be ignored if the
146
+ * filesystem doesn't support permissions.
98
147
  */
99
- export function openSync(path, flag, mode = 0o644) {
100
- const file = doOp('openSync', true, path, FileFlag.getFileFlag(flag), normalizeMode(mode, 0o644), cred);
101
- return getFdForFile(file);
148
+ export function openSync(path, flag, mode) {
149
+ return getFdForFile(_openSync(path, flag, mode, true));
102
150
  }
103
151
  openSync;
152
+ /**
153
+ * Opens a file or symlink
154
+ * @internal
155
+ */
156
+ export function lopenSync(path, flag, mode) {
157
+ return getFdForFile(_openSync(path, flag, mode, false));
158
+ }
159
+ /**
160
+ * Synchronously reads the entire contents of a file.
161
+ */
162
+ function _readFileSync(fname, flag, resolveSymlinks) {
163
+ // Get file.
164
+ const file = _openSync(fname, flag, 0o644, resolveSymlinks);
165
+ try {
166
+ const stat = file.statSync();
167
+ // Allocate buffer.
168
+ const data = new Uint8Array(stat.size);
169
+ file.readSync(data, 0, stat.size, 0);
170
+ file.closeSync();
171
+ return data;
172
+ }
173
+ finally {
174
+ file.closeSync();
175
+ }
176
+ }
104
177
  export function readFileSync(filename, arg2 = {}) {
105
- const options = normalizeOptions(arg2, null, 'r', null);
106
- const flag = FileFlag.getFileFlag(options.flag);
178
+ const options = normalizeOptions(arg2, null, 'r', 0o644);
179
+ const flag = FileFlag.FromString(options.flag);
107
180
  if (!flag.isReadable()) {
108
181
  throw new ApiError(ErrorCode.EINVAL, 'Flag passed to readFile must allow for reading.');
109
182
  }
110
- const data = doOp('readFileSync', true, filename, flag, cred);
111
- switch (options.encoding) {
112
- case 'utf8':
113
- case 'utf-8':
114
- return decode(data);
115
- default:
116
- return data;
117
- }
183
+ const data = _readFileSync(filename, options.flag, true);
184
+ return options.encoding ? decode(data, options.encoding) : data;
118
185
  }
119
186
  readFileSync;
120
- export function writeFileSync(filename, data, arg3) {
121
- const options = normalizeOptions(arg3, 'utf8', 'w', 0o644);
122
- const flag = FileFlag.getFileFlag(options.flag);
187
+ /**
188
+ * Synchronously writes data to a file, replacing the file
189
+ * if it already exists.
190
+ *
191
+ * The encoding option is ignored if data is a buffer.
192
+ */
193
+ function _writeFileSync(fname, data, flag, mode, resolveSymlinks) {
194
+ const file = _openSync(fname, flag, mode, resolveSymlinks);
195
+ try {
196
+ file.writeSync(data, 0, data.length, 0);
197
+ }
198
+ finally {
199
+ file.closeSync();
200
+ }
201
+ }
202
+ export function writeFileSync(filename, data, _options) {
203
+ const options = normalizeOptions(_options, 'utf8', 'w', 0o644);
204
+ const flag = FileFlag.FromString(options.flag);
123
205
  if (!flag.isWriteable()) {
124
206
  throw new ApiError(ErrorCode.EINVAL, 'Flag passed to writeFile must allow for writing.');
125
207
  }
126
208
  if (typeof data != 'string' && !options.encoding) {
127
209
  throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
128
210
  }
129
- const encodedData = typeof data == 'string' ? encode(data) : data;
130
- return doOp('writeFileSync', true, filename, encodedData, flag, options.mode, cred);
211
+ const encodedData = typeof data == 'string' ? encode(data, options.encoding) : data;
212
+ if (encodedData === undefined) {
213
+ throw new ApiError(ErrorCode.EINVAL, 'Data not specified');
214
+ }
215
+ _writeFileSync(filename, encodedData, options.flag, options.mode, true);
131
216
  }
132
217
  writeFileSync;
218
+ /**
219
+ * Synchronously append data to a file, creating the file if
220
+ * it not yet exists.
221
+ */
222
+ function _appendFileSync(fname, data, flag, mode, resolveSymlinks) {
223
+ const file = _openSync(fname, flag, mode, resolveSymlinks);
224
+ try {
225
+ file.writeSync(data, 0, data.length, null);
226
+ }
227
+ finally {
228
+ file.closeSync();
229
+ }
230
+ }
133
231
  export function appendFileSync(filename, data, arg3) {
134
232
  const options = normalizeOptions(arg3, 'utf8', 'a', 0o644);
135
- const flag = FileFlag.getFileFlag(options.flag);
233
+ const flag = FileFlag.FromString(options.flag);
136
234
  if (!flag.isAppendable()) {
137
235
  throw new ApiError(ErrorCode.EINVAL, 'Flag passed to appendFile must allow for appending.');
138
236
  }
@@ -140,7 +238,7 @@ export function appendFileSync(filename, data, arg3) {
140
238
  throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
141
239
  }
142
240
  const encodedData = typeof data == 'string' ? encode(data) : data;
143
- return doOp('appendFileSync', true, filename, encodedData, flag, options.mode, cred);
241
+ _appendFileSync(filename, encodedData, options.flag, options.mode, true);
144
242
  }
145
243
  appendFileSync;
146
244
  export function fstatSync(fd, options) {
@@ -163,11 +261,10 @@ closeSync;
163
261
  * @param len
164
262
  */
165
263
  export function ftruncateSync(fd, len = 0) {
166
- const file = fd2file(fd);
167
264
  if (len < 0) {
168
265
  throw new ApiError(ErrorCode.EINVAL);
169
266
  }
170
- file.truncateSync(len);
267
+ fd2file(fd).truncateSync(len);
171
268
  }
172
269
  ftruncateSync;
173
270
  /**
@@ -186,26 +283,26 @@ export function fdatasyncSync(fd) {
186
283
  fd2file(fd).datasyncSync();
187
284
  }
188
285
  fdatasyncSync;
189
- export function writeSync(fd, arg2, arg3, arg4, arg5) {
286
+ export function writeSync(fd, data, posOrOff, lenOrEnc, pos) {
190
287
  let buffer, offset = 0, length, position;
191
- if (typeof arg2 === 'string') {
288
+ if (typeof data === 'string') {
192
289
  // Signature 1: (fd, string, [position?, [encoding?]])
193
- position = typeof arg3 === 'number' ? arg3 : null;
194
- const encoding = (typeof arg4 === 'string' ? arg4 : 'utf8');
290
+ position = typeof posOrOff === 'number' ? posOrOff : null;
291
+ const encoding = (typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8');
195
292
  offset = 0;
196
- buffer = encode(arg2);
293
+ buffer = encode(data, encoding);
197
294
  length = buffer.length;
198
295
  }
199
296
  else {
200
297
  // Signature 2: (fd, buffer, offset, length, position?)
201
- buffer = arg2;
202
- offset = arg3;
203
- length = arg4;
204
- position = typeof arg5 === 'number' ? arg5 : null;
298
+ buffer = data;
299
+ offset = posOrOff;
300
+ length = lenOrEnc;
301
+ position = typeof pos === 'number' ? pos : null;
205
302
  }
206
303
  const file = fd2file(fd);
207
304
  if (position === undefined || position === null) {
208
- position = file.getPos();
305
+ position = file.position;
209
306
  }
210
307
  return file.writeSync(buffer, offset, length, position);
211
308
  }
@@ -217,7 +314,7 @@ export function readSync(fd, buffer, opts, length, position) {
217
314
  ({ offset, length, position } = opts);
218
315
  }
219
316
  if (isNaN(+position)) {
220
- position = file.getPos();
317
+ position = file.position;
221
318
  }
222
319
  return file.readSync(buffer, offset, length, position);
223
320
  }
@@ -238,7 +335,10 @@ fchownSync;
238
335
  * @param mode
239
336
  */
240
337
  export function fchmodSync(fd, mode) {
241
- const numMode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
338
+ const numMode = normalizeMode(mode, -1);
339
+ if (numMode < 0) {
340
+ throw new ApiError(ErrorCode.EINVAL, `Invalid mode.`);
341
+ }
242
342
  fd2file(fd).chmodSync(numMode);
243
343
  }
244
344
  fchmodSync;
@@ -253,7 +353,6 @@ export function futimesSync(fd, atime, mtime) {
253
353
  fd2file(fd).utimesSync(normalizeTime(atime), normalizeTime(mtime));
254
354
  }
255
355
  futimesSync;
256
- // DIRECTORY-ONLY METHODS
257
356
  /**
258
357
  * Synchronous `rmdir`.
259
358
  * @param path
@@ -296,31 +395,39 @@ readdirSync;
296
395
  // SYMLINK METHODS
297
396
  /**
298
397
  * Synchronous `link`.
299
- * @param srcpath
300
- * @param dstpath
398
+ * @param existing
399
+ * @param newpath
301
400
  */
302
- export function linkSync(srcpath, dstpath) {
303
- dstpath = normalizePath(dstpath);
304
- return doOp('linkSync', false, srcpath, dstpath, cred);
401
+ export function linkSync(existing, newpath) {
402
+ newpath = normalizePath(newpath);
403
+ return doOp('linkSync', false, existing, newpath, cred);
305
404
  }
306
405
  linkSync;
307
406
  /**
308
407
  * Synchronous `symlink`.
309
- * @param srcpath
310
- * @param dstpath
408
+ * @param target target path
409
+ * @param path link path
311
410
  * @param type can be either `'dir'` or `'file'` (default is `'file'`)
312
411
  */
313
- export function symlinkSync(srcpath, dstpath, type) {
412
+ export function symlinkSync(target, path, type = 'file') {
314
413
  if (!['file', 'dir', 'junction'].includes(type)) {
315
414
  throw new ApiError(ErrorCode.EINVAL, 'Invalid type: ' + type);
316
415
  }
317
- dstpath = normalizePath(dstpath);
318
- return doOp('symlinkSync', false, srcpath, dstpath, type, cred);
416
+ if (existsSync(path)) {
417
+ throw ApiError.EEXIST(path);
418
+ }
419
+ writeFileSync(path, target);
420
+ const file = _openSync(path, 'r+', 0o644, false);
421
+ file._setTypeSync(FileType.SYMLINK);
319
422
  }
320
423
  symlinkSync;
321
424
  export function readlinkSync(path, options) {
322
- const value = doOp('readlinkSync', false, path, cred);
323
- return encode(value, typeof options == 'object' ? options.encoding : options);
425
+ const value = _readFileSync(path, 'r', false);
426
+ const encoding = typeof options == 'object' ? options.encoding : options;
427
+ if (encoding == 'buffer') {
428
+ return value;
429
+ }
430
+ return decode(value, encoding);
324
431
  }
325
432
  readlinkSync;
326
433
  // PROPERTY OPERATIONS
@@ -331,7 +438,9 @@ readlinkSync;
331
438
  * @param gid
332
439
  */
333
440
  export function chownSync(path, uid, gid) {
334
- doOp('chownSync', true, path, uid, gid, cred);
441
+ const fd = openSync(path, 'r+');
442
+ fchownSync(fd, uid, gid);
443
+ closeSync(fd);
335
444
  }
336
445
  chownSync;
337
446
  /**
@@ -341,7 +450,9 @@ chownSync;
341
450
  * @param gid
342
451
  */
343
452
  export function lchownSync(path, uid, gid) {
344
- doOp('chownSync', false, path, uid, gid, cred);
453
+ const fd = lopenSync(path, 'r+');
454
+ fchownSync(fd, uid, gid);
455
+ closeSync(fd);
345
456
  }
346
457
  lchownSync;
347
458
  /**
@@ -350,11 +461,9 @@ lchownSync;
350
461
  * @param mode
351
462
  */
352
463
  export function chmodSync(path, mode) {
353
- const numMode = normalizeMode(mode, -1);
354
- if (numMode < 0) {
355
- throw new ApiError(ErrorCode.EINVAL, `Invalid mode.`);
356
- }
357
- doOp('chmodSync', true, path, numMode, cred);
464
+ const fd = openSync(path, 'r+');
465
+ fchmodSync(fd, mode);
466
+ closeSync(fd);
358
467
  }
359
468
  chmodSync;
360
469
  /**
@@ -363,11 +472,9 @@ chmodSync;
363
472
  * @param mode
364
473
  */
365
474
  export function lchmodSync(path, mode) {
366
- const numMode = normalizeMode(mode, -1);
367
- if (numMode < 1) {
368
- throw new ApiError(ErrorCode.EINVAL, `Invalid mode.`);
369
- }
370
- doOp('chmodSync', false, path, numMode, cred);
475
+ const fd = lopenSync(path, 'r+');
476
+ fchmodSync(fd, mode);
477
+ closeSync(fd);
371
478
  }
372
479
  lchmodSync;
373
480
  /**
@@ -377,7 +484,9 @@ lchmodSync;
377
484
  * @param mtime
378
485
  */
379
486
  export function utimesSync(path, atime, mtime) {
380
- doOp('utimesSync', true, path, normalizeTime(atime), normalizeTime(mtime), cred);
487
+ const fd = openSync(path, 'r+');
488
+ futimesSync(fd, atime, mtime);
489
+ closeSync(fd);
381
490
  }
382
491
  utimesSync;
383
492
  /**
@@ -387,7 +496,9 @@ utimesSync;
387
496
  * @param mtime
388
497
  */
389
498
  export function lutimesSync(path, atime, mtime) {
390
- doOp('utimesSync', false, path, normalizeTime(atime), normalizeTime(mtime), cred);
499
+ const fd = lopenSync(path, 'r+');
500
+ futimesSync(fd, atime, mtime);
501
+ closeSync(fd);
391
502
  }
392
503
  lutimesSync;
393
504
  export function realpathSync(path, options) {
@@ -398,7 +509,7 @@ export function realpathSync(path, options) {
398
509
  if (!stats.isSymbolicLink()) {
399
510
  return path;
400
511
  }
401
- const dst = normalizePath(mountPoint + fs.readlinkSync(resolvedPath, cred));
512
+ const dst = normalizePath(mountPoint + decode(_readFileSync(resolvedPath, 'r+', false)));
402
513
  return realpathSync(dst);
403
514
  }
404
515
  catch (e) {
@@ -412,7 +523,10 @@ realpathSync;
412
523
  * @param mode
413
524
  */
414
525
  export function accessSync(path, mode = 0o600) {
415
- return doOp('accessSync', true, path, mode, cred);
526
+ const stats = statSync(path);
527
+ if (!stats.hasAccess(mode, cred)) {
528
+ throw new ApiError(ErrorCode.EACCES);
529
+ }
416
530
  }
417
531
  accessSync;
418
532
  export function rmSync(path) {