@zenfs/core 1.3.6 → 1.4.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 (88) hide show
  1. package/dist/backends/memory.d.ts +4 -4
  2. package/dist/backends/memory.js +4 -4
  3. package/dist/backends/overlay.d.ts +5 -2
  4. package/dist/backends/overlay.js +7 -10
  5. package/dist/backends/port/fs.js +1 -4
  6. package/dist/config.js +4 -8
  7. package/dist/context.d.ts +32 -0
  8. package/dist/context.js +23 -0
  9. package/dist/credentials.d.ts +5 -5
  10. package/dist/credentials.js +10 -6
  11. package/dist/emulation/async.d.ts +90 -89
  12. package/dist/emulation/async.js +76 -75
  13. package/dist/emulation/dir.d.ts +3 -1
  14. package/dist/emulation/dir.js +6 -7
  15. package/dist/emulation/index.d.ts +1 -1
  16. package/dist/emulation/index.js +1 -1
  17. package/dist/emulation/promises.d.ts +50 -48
  18. package/dist/emulation/promises.js +78 -77
  19. package/dist/emulation/shared.d.ts +35 -8
  20. package/dist/emulation/shared.js +37 -11
  21. package/dist/emulation/sync.d.ts +63 -62
  22. package/dist/emulation/sync.js +72 -73
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/stats.d.ts +2 -1
  26. package/dist/stats.js +5 -4
  27. package/package.json +3 -5
  28. package/scripts/test.js +78 -17
  29. package/tests/assignment.ts +1 -1
  30. package/tests/common/context.test.ts +19 -0
  31. package/tests/{devices.test.ts → common/devices.test.ts} +3 -3
  32. package/tests/{handle.test.ts → common/handle.test.ts} +1 -1
  33. package/tests/common/mounts.test.ts +36 -0
  34. package/tests/{mutex.test.ts → common/mutex.test.ts} +3 -3
  35. package/tests/common/path.test.ts +34 -0
  36. package/tests/common.ts +4 -3
  37. package/tests/fs/dir.test.ts +11 -11
  38. package/tests/fs/directory.test.ts +17 -17
  39. package/tests/fs/errors.test.ts +29 -39
  40. package/tests/fs/watch.test.ts +2 -2
  41. package/tests/setup/context.ts +9 -0
  42. package/tests/setup/cow+fetch.ts +1 -1
  43. package/tests/setup/memory.ts +1 -1
  44. package/tests/{setup/common.ts → setup.ts} +6 -5
  45. package/src/backends/backend.ts +0 -161
  46. package/src/backends/fetch.ts +0 -180
  47. package/src/backends/file_index.ts +0 -206
  48. package/src/backends/memory.ts +0 -45
  49. package/src/backends/overlay.ts +0 -560
  50. package/src/backends/port/fs.ts +0 -329
  51. package/src/backends/port/readme.md +0 -54
  52. package/src/backends/port/rpc.ts +0 -167
  53. package/src/backends/readme.md +0 -3
  54. package/src/backends/store/fs.ts +0 -667
  55. package/src/backends/store/readme.md +0 -9
  56. package/src/backends/store/simple.ts +0 -154
  57. package/src/backends/store/store.ts +0 -189
  58. package/src/config.ts +0 -227
  59. package/src/credentials.ts +0 -49
  60. package/src/devices.ts +0 -521
  61. package/src/emulation/async.ts +0 -834
  62. package/src/emulation/cache.ts +0 -86
  63. package/src/emulation/config.ts +0 -21
  64. package/src/emulation/constants.ts +0 -182
  65. package/src/emulation/dir.ts +0 -138
  66. package/src/emulation/index.ts +0 -8
  67. package/src/emulation/path.ts +0 -440
  68. package/src/emulation/promises.ts +0 -1140
  69. package/src/emulation/shared.ts +0 -172
  70. package/src/emulation/streams.ts +0 -34
  71. package/src/emulation/sync.ts +0 -863
  72. package/src/emulation/watchers.ts +0 -194
  73. package/src/error.ts +0 -307
  74. package/src/file.ts +0 -631
  75. package/src/filesystem.ts +0 -174
  76. package/src/index.ts +0 -35
  77. package/src/inode.ts +0 -128
  78. package/src/mixins/async.ts +0 -230
  79. package/src/mixins/index.ts +0 -5
  80. package/src/mixins/mutexed.ts +0 -257
  81. package/src/mixins/readonly.ts +0 -96
  82. package/src/mixins/shared.ts +0 -25
  83. package/src/mixins/sync.ts +0 -58
  84. package/src/polyfills.ts +0 -21
  85. package/src/stats.ts +0 -405
  86. package/src/utils.ts +0 -276
  87. package/tests/mounts.test.ts +0 -18
  88. package/tests/path.test.ts +0 -34
@@ -60,9 +60,9 @@ import { emitChange } from './watchers.js';
60
60
  export function renameSync(oldPath, newPath) {
61
61
  oldPath = normalizePath(oldPath);
62
62
  newPath = normalizePath(newPath);
63
- const oldMount = resolveMount(oldPath);
64
- const newMount = resolveMount(newPath);
65
- if (config.checkAccess && !statSync(dirname(oldPath)).hasAccess(constants.W_OK)) {
63
+ const oldMount = resolveMount(oldPath, this);
64
+ const newMount = resolveMount(newPath, this);
65
+ if (config.checkAccess && !statSync.call(this, dirname(oldPath)).hasAccess(constants.W_OK, this)) {
66
66
  throw ErrnoError.With('EACCES', oldPath, 'rename');
67
67
  }
68
68
  try {
@@ -72,8 +72,8 @@ export function renameSync(oldPath, newPath) {
72
72
  emitChange('change', newPath.toString());
73
73
  return;
74
74
  }
75
- writeFileSync(newPath, readFileSync(oldPath));
76
- unlinkSync(oldPath);
75
+ writeFileSync.call(this, newPath, readFileSync(oldPath));
76
+ unlinkSync.call(this, oldPath);
77
77
  emitChange('rename', oldPath.toString());
78
78
  }
79
79
  catch (e) {
@@ -87,7 +87,7 @@ renameSync;
87
87
  export function existsSync(path) {
88
88
  path = normalizePath(path);
89
89
  try {
90
- const { fs, path: resolvedPath } = resolveMount(realpathSync(path));
90
+ const { fs, path: resolvedPath } = resolveMount(realpathSync.call(this, path), this);
91
91
  return fs.existsSync(resolvedPath);
92
92
  }
93
93
  catch (e) {
@@ -100,10 +100,10 @@ export function existsSync(path) {
100
100
  existsSync;
101
101
  export function statSync(path, options) {
102
102
  path = normalizePath(path);
103
- const { fs, path: resolved } = resolveMount(realpathSync(path));
103
+ const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
104
104
  try {
105
105
  const stats = fs.statSync(resolved);
106
- if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
106
+ if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
107
107
  throw ErrnoError.With('EACCES', resolved, 'stat');
108
108
  }
109
109
  return options?.bigint ? new BigIntStats(stats) : stats;
@@ -115,7 +115,7 @@ export function statSync(path, options) {
115
115
  statSync;
116
116
  export function lstatSync(path, options) {
117
117
  path = normalizePath(path);
118
- const { fs, path: resolved } = resolveMount(path);
118
+ const { fs, path: resolved } = resolveMount(path, this);
119
119
  try {
120
120
  const stats = fs.statSync(resolved);
121
121
  return options?.bigint ? new BigIntStats(stats) : stats;
@@ -128,7 +128,7 @@ lstatSync;
128
128
  export function truncateSync(path, len = 0) {
129
129
  const env_1 = { stack: [], error: void 0, hasError: false };
130
130
  try {
131
- const file = __addDisposableResource(env_1, _openSync(path, 'r+'), false);
131
+ const file = __addDisposableResource(env_1, _openSync.call(this, path, 'r+'), false);
132
132
  len || (len = 0);
133
133
  if (len < 0) {
134
134
  throw new ErrnoError(Errno.EINVAL);
@@ -146,9 +146,9 @@ export function truncateSync(path, len = 0) {
146
146
  truncateSync;
147
147
  export function unlinkSync(path) {
148
148
  path = normalizePath(path);
149
- const { fs, path: resolved } = resolveMount(path);
149
+ const { fs, path: resolved } = resolveMount(path, this);
150
150
  try {
151
- if (config.checkAccess && !(cache.stats.get(path) || fs.statSync(resolved)).hasAccess(constants.W_OK)) {
151
+ if (config.checkAccess && !(cache.stats.get(path) || fs.statSync(resolved)).hasAccess(constants.W_OK, this)) {
152
152
  throw ErrnoError.With('EACCES', resolved, 'unlink');
153
153
  }
154
154
  fs.unlinkSync(resolved);
@@ -162,8 +162,8 @@ unlinkSync;
162
162
  function _openSync(path, _flag, _mode, resolveSymlinks = true) {
163
163
  path = normalizePath(path);
164
164
  const mode = normalizeMode(_mode, 0o644), flag = parseFlag(_flag);
165
- path = resolveSymlinks ? realpathSync(path) : path;
166
- const { fs, path: resolved } = resolveMount(path);
165
+ path = resolveSymlinks ? realpathSync.call(this, path) : path;
166
+ const { fs, path: resolved } = resolveMount(path, this);
167
167
  let stats;
168
168
  try {
169
169
  stats = fs.statSync(resolved);
@@ -177,7 +177,7 @@ function _openSync(path, _flag, _mode, resolveSymlinks = true) {
177
177
  }
178
178
  // Create the file
179
179
  const parentStats = fs.statSync(dirname(resolved));
180
- if (config.checkAccess && !parentStats.hasAccess(constants.W_OK)) {
180
+ if (config.checkAccess && !parentStats.hasAccess(constants.W_OK, this)) {
181
181
  throw ErrnoError.With('EACCES', dirname(path), '_open');
182
182
  }
183
183
  if (!parentStats.isDirectory()) {
@@ -185,7 +185,7 @@ function _openSync(path, _flag, _mode, resolveSymlinks = true) {
185
185
  }
186
186
  return fs.createFileSync(resolved, flag, mode);
187
187
  }
188
- if (config.checkAccess && (!stats.hasAccess(mode) || !stats.hasAccess(flagToMode(flag)))) {
188
+ if (config.checkAccess && (!stats.hasAccess(mode, this) || !stats.hasAccess(flagToMode(flag), this))) {
189
189
  throw ErrnoError.With('EACCES', path, '_open');
190
190
  }
191
191
  if (isExclusive(flag)) {
@@ -202,7 +202,7 @@ function _openSync(path, _flag, _mode, resolveSymlinks = true) {
202
202
  * @see http://www.manpagez.com/man/2/open/
203
203
  */
204
204
  export function openSync(path, flag, mode = constants.F_OK) {
205
- return file2fd(_openSync(path, flag, mode, true));
205
+ return file2fd(_openSync.call(this, path, flag, mode, true));
206
206
  }
207
207
  openSync;
208
208
  /**
@@ -210,13 +210,13 @@ openSync;
210
210
  * @internal
211
211
  */
212
212
  export function lopenSync(path, flag, mode) {
213
- return file2fd(_openSync(path, flag, mode, false));
213
+ return file2fd(_openSync.call(this, path, flag, mode, false));
214
214
  }
215
215
  function _readFileSync(fname, flag, resolveSymlinks) {
216
216
  const env_2 = { stack: [], error: void 0, hasError: false };
217
217
  try {
218
218
  // Get file.
219
- const file = __addDisposableResource(env_2, _openSync(fname, flag, 0o644, resolveSymlinks), false);
219
+ const file = __addDisposableResource(env_2, _openSync.call(this, fname, flag, 0o644, resolveSymlinks), false);
220
220
  const stat = file.statSync();
221
221
  // Allocate buffer.
222
222
  const data = new Uint8Array(stat.size);
@@ -237,7 +237,7 @@ export function readFileSync(path, _options = {}) {
237
237
  if (!isReadable(flag)) {
238
238
  throw new ErrnoError(Errno.EINVAL, 'Flag passed to readFile must allow for reading.');
239
239
  }
240
- const data = Buffer.from(_readFileSync(typeof path == 'number' ? fd2file(path).path : path.toString(), options.flag, true));
240
+ const data = Buffer.from(_readFileSync.call(this, typeof path == 'number' ? fd2file(path).path : path.toString(), options.flag, true));
241
241
  return options.encoding ? data.toString(options.encoding) : data;
242
242
  }
243
243
  readFileSync;
@@ -256,7 +256,7 @@ export function writeFileSync(path, data, _options = {}) {
256
256
  if (!encodedData) {
257
257
  throw new ErrnoError(Errno.EINVAL, 'Data not specified');
258
258
  }
259
- const file = __addDisposableResource(env_3, _openSync(typeof path == 'number' ? fd2file(path).path : path.toString(), flag, options.mode, true), false);
259
+ const file = __addDisposableResource(env_3, _openSync.call(this, typeof path == 'number' ? fd2file(path).path : path.toString(), flag, options.mode, true), false);
260
260
  file.writeSync(encodedData, 0, encodedData.byteLength, 0);
261
261
  emitChange('change', path.toString());
262
262
  }
@@ -287,7 +287,7 @@ export function appendFileSync(filename, data, _options = {}) {
287
287
  throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
288
288
  }
289
289
  const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
290
- const file = __addDisposableResource(env_4, _openSync(typeof filename == 'number' ? fd2file(filename).path : filename.toString(), flag, options.mode, true), false);
290
+ const file = __addDisposableResource(env_4, _openSync.call(this, typeof filename == 'number' ? fd2file(filename).path : filename.toString(), flag, options.mode, true), false);
291
291
  file.writeSync(encodedData, 0, encodedData.byteLength);
292
292
  }
293
293
  catch (e_4) {
@@ -392,13 +392,13 @@ export function futimesSync(fd, atime, mtime) {
392
392
  futimesSync;
393
393
  export function rmdirSync(path) {
394
394
  path = normalizePath(path);
395
- const { fs, path: resolved } = resolveMount(realpathSync(path));
395
+ const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
396
396
  try {
397
397
  const stats = cache.stats.get(path) || fs.statSync(resolved);
398
398
  if (!stats.isDirectory()) {
399
399
  throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
400
400
  }
401
- if (config.checkAccess && !stats.hasAccess(constants.W_OK)) {
401
+ if (config.checkAccess && !stats.hasAccess(constants.W_OK, this)) {
402
402
  throw ErrnoError.With('EACCES', resolved, 'rmdir');
403
403
  }
404
404
  fs.rmdirSync(resolved);
@@ -412,12 +412,12 @@ rmdirSync;
412
412
  export function mkdirSync(path, options) {
413
413
  options = typeof options === 'object' ? options : { mode: options };
414
414
  const mode = normalizeMode(options?.mode, 0o777);
415
- path = realpathSync(path);
416
- const { fs, path: resolved } = resolveMount(path);
415
+ path = realpathSync.call(this, path);
416
+ const { fs, path: resolved, root } = resolveMount(path, this);
417
417
  const errorPaths = { [resolved]: path };
418
418
  try {
419
419
  if (!options?.recursive) {
420
- if (config.checkAccess && !fs.statSync(dirname(resolved)).hasAccess(constants.W_OK)) {
420
+ if (config.checkAccess && !fs.statSync(dirname(resolved)).hasAccess(constants.W_OK, this)) {
421
421
  throw ErrnoError.With('EACCES', dirname(resolved), 'mkdir');
422
422
  }
423
423
  return fs.mkdirSync(resolved, mode);
@@ -428,13 +428,13 @@ export function mkdirSync(path, options) {
428
428
  errorPaths[dir] = original;
429
429
  }
430
430
  for (const dir of dirs) {
431
- if (config.checkAccess && !fs.statSync(dirname(dir)).hasAccess(constants.W_OK)) {
431
+ if (config.checkAccess && !fs.statSync(dirname(dir)).hasAccess(constants.W_OK, this)) {
432
432
  throw ErrnoError.With('EACCES', dirname(dir), 'mkdir');
433
433
  }
434
434
  fs.mkdirSync(dir, mode);
435
435
  emitChange('rename', dir);
436
436
  }
437
- return dirs[0];
437
+ return root.length == 1 ? dirs[0] : dirs[0]?.slice(root.length);
438
438
  }
439
439
  catch (e) {
440
440
  throw fixError(e, errorPaths);
@@ -444,12 +444,12 @@ mkdirSync;
444
444
  export function readdirSync(path, options) {
445
445
  options = typeof options === 'object' ? options : { encoding: options };
446
446
  path = normalizePath(path);
447
- const { fs, path: resolved } = resolveMount(realpathSync(path));
447
+ const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
448
448
  let entries;
449
449
  try {
450
450
  const stats = cache.stats.get(path) || fs.statSync(resolved);
451
451
  cache.stats.set(path, stats);
452
- if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
452
+ if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
453
453
  throw ErrnoError.With('EACCES', resolved, 'readdir');
454
454
  }
455
455
  if (!stats.isDirectory()) {
@@ -476,7 +476,7 @@ export function readdirSync(path, options) {
476
476
  }
477
477
  if (!entryStat.isDirectory() || !options?.recursive)
478
478
  continue;
479
- for (const subEntry of readdirSync(join(path, entry), { ...options, _isIndirect: true })) {
479
+ for (const subEntry of readdirSync.call(this, join(path, entry), { ...options, _isIndirect: true })) {
480
480
  if (subEntry instanceof Dirent) {
481
481
  subEntry.path = join(entry, subEntry.path);
482
482
  values.push(subEntry);
@@ -495,23 +495,22 @@ export function readdirSync(path, options) {
495
495
  return values;
496
496
  }
497
497
  readdirSync;
498
- // SYMLINK METHODS
499
498
  export function linkSync(targetPath, linkPath) {
500
499
  targetPath = normalizePath(targetPath);
501
- if (config.checkAccess && !statSync(dirname(targetPath)).hasAccess(constants.R_OK)) {
500
+ if (config.checkAccess && !statSync(dirname(targetPath)).hasAccess(constants.R_OK, this)) {
502
501
  throw ErrnoError.With('EACCES', dirname(targetPath), 'link');
503
502
  }
504
503
  linkPath = normalizePath(linkPath);
505
- if (config.checkAccess && !statSync(dirname(linkPath)).hasAccess(constants.W_OK)) {
504
+ if (config.checkAccess && !statSync(dirname(linkPath)).hasAccess(constants.W_OK, this)) {
506
505
  throw ErrnoError.With('EACCES', dirname(linkPath), 'link');
507
506
  }
508
- const { fs, path } = resolveMount(targetPath);
509
- const link = resolveMount(linkPath);
507
+ const { fs, path } = resolveMount(targetPath, this);
508
+ const link = resolveMount(linkPath, this);
510
509
  if (fs != link.fs) {
511
510
  throw ErrnoError.With('EXDEV', linkPath, 'link');
512
511
  }
513
512
  try {
514
- if (config.checkAccess && !fs.statSync(path).hasAccess(constants.R_OK)) {
513
+ if (config.checkAccess && !fs.statSync(path).hasAccess(constants.R_OK, this)) {
515
514
  throw ErrnoError.With('EACCES', path, 'link');
516
515
  }
517
516
  return fs.linkSync(path, linkPath);
@@ -531,16 +530,16 @@ export function symlinkSync(target, path, type = 'file') {
531
530
  if (!['file', 'dir', 'junction'].includes(type)) {
532
531
  throw new ErrnoError(Errno.EINVAL, 'Invalid type: ' + type);
533
532
  }
534
- if (existsSync(path)) {
533
+ if (existsSync.call(this, path)) {
535
534
  throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
536
535
  }
537
- writeFileSync(path, target.toString());
538
- const file = _openSync(path, 'r+', 0o644, false);
536
+ writeFileSync.call(this, path, target.toString());
537
+ const file = _openSync.call(this, path, 'r+', 0o644, false);
539
538
  file.chmodSync(constants.S_IFLNK);
540
539
  }
541
540
  symlinkSync;
542
541
  export function readlinkSync(path, options) {
543
- const value = Buffer.from(_readFileSync(path.toString(), 'r', false));
542
+ const value = Buffer.from(_readFileSync.call(this, path.toString(), 'r', false));
544
543
  const encoding = typeof options == 'object' ? options?.encoding : options;
545
544
  if (encoding == 'buffer') {
546
545
  return value;
@@ -548,27 +547,26 @@ export function readlinkSync(path, options) {
548
547
  return value.toString(encoding);
549
548
  }
550
549
  readlinkSync;
551
- // PROPERTY OPERATIONS
552
550
  export function chownSync(path, uid, gid) {
553
- const fd = openSync(path, 'r+');
551
+ const fd = openSync.call(this, path, 'r+');
554
552
  fchownSync(fd, uid, gid);
555
553
  closeSync(fd);
556
554
  }
557
555
  chownSync;
558
556
  export function lchownSync(path, uid, gid) {
559
- const fd = lopenSync(path, 'r+');
557
+ const fd = lopenSync.call(this, path, 'r+');
560
558
  fchownSync(fd, uid, gid);
561
559
  closeSync(fd);
562
560
  }
563
561
  lchownSync;
564
562
  export function chmodSync(path, mode) {
565
- const fd = openSync(path, 'r+');
563
+ const fd = openSync.call(this, path, 'r+');
566
564
  fchmodSync(fd, mode);
567
565
  closeSync(fd);
568
566
  }
569
567
  chmodSync;
570
568
  export function lchmodSync(path, mode) {
571
- const fd = lopenSync(path, 'r+');
569
+ const fd = lopenSync.call(this, path, 'r+');
572
570
  fchmodSync(fd, mode);
573
571
  closeSync(fd);
574
572
  }
@@ -577,7 +575,7 @@ lchmodSync;
577
575
  * Change file timestamps of the file referenced by the supplied path.
578
576
  */
579
577
  export function utimesSync(path, atime, mtime) {
580
- const fd = openSync(path, 'r+');
578
+ const fd = openSync.call(this, path, 'r+');
581
579
  futimesSync(fd, atime, mtime);
582
580
  closeSync(fd);
583
581
  }
@@ -586,19 +584,20 @@ utimesSync;
586
584
  * Change file timestamps of the file referenced by the supplied path.
587
585
  */
588
586
  export function lutimesSync(path, atime, mtime) {
589
- const fd = lopenSync(path, 'r+');
587
+ const fd = lopenSync.call(this, path, 'r+');
590
588
  futimesSync(fd, atime, mtime);
591
589
  closeSync(fd);
592
590
  }
593
591
  lutimesSync;
594
592
  export function realpathSync(path, options) {
595
593
  path = normalizePath(path);
596
- if (cache.paths.has(path))
597
- return cache.paths.get(path);
594
+ const ctx_path = (this?.root || '') + path;
595
+ if (cache.paths.has(ctx_path))
596
+ return cache.paths.get(ctx_path);
598
597
  const { base, dir } = parse(path);
599
- const realDir = dir == '/' ? '/' : cache.paths.get(dir) || realpathSync(dir);
598
+ const realDir = dir == '/' ? '/' : cache.paths.get((this?.root || '') + dir) || realpathSync.call(this, dir);
600
599
  const lpath = join(realDir, base);
601
- const { fs, path: resolvedPath } = resolveMount(lpath);
600
+ const { fs, path: resolvedPath } = resolveMount(lpath, this);
602
601
  try {
603
602
  const stats = cache.stats.get(lpath) || fs.statSync(resolvedPath);
604
603
  cache.stats.set(lpath, stats);
@@ -606,9 +605,9 @@ export function realpathSync(path, options) {
606
605
  cache.paths.set(path, lpath);
607
606
  return lpath;
608
607
  }
609
- const target = resolve(realDir, readlinkSync(lpath, options).toString());
610
- const real = cache.paths.get(target) || realpathSync(target);
611
- cache.paths.set(path, real);
608
+ const target = resolve(realDir, readlinkSync.call(this, lpath, options).toString());
609
+ const real = cache.paths.get((this?.root || '') + target) || realpathSync.call(this, target);
610
+ cache.paths.set(ctx_path, real);
612
611
  return real;
613
612
  }
614
613
  catch (e) {
@@ -622,7 +621,7 @@ realpathSync;
622
621
  export function accessSync(path, mode = 0o600) {
623
622
  if (!config.checkAccess)
624
623
  return;
625
- if (!statSync(path).hasAccess(mode)) {
624
+ if (!statSync.call(this, path).hasAccess(mode, this)) {
626
625
  throw new ErrnoError(Errno.EACCES);
627
626
  }
628
627
  }
@@ -635,7 +634,7 @@ export function rmSync(path, options) {
635
634
  path = normalizePath(path);
636
635
  let stats;
637
636
  try {
638
- stats = cache.stats.get(path) || statSync(path);
637
+ stats = cache.stats.get(path) || lstatSync.bind(this)(path);
639
638
  }
640
639
  catch (error) {
641
640
  if (error.code != 'ENOENT' || !options?.force)
@@ -648,17 +647,17 @@ export function rmSync(path, options) {
648
647
  switch (stats.mode & constants.S_IFMT) {
649
648
  case constants.S_IFDIR:
650
649
  if (options?.recursive) {
651
- for (const entry of readdirSync(path, { _isIndirect: true })) {
652
- rmSync(join(path, entry), { ...options, _isIndirect: true });
650
+ for (const entry of readdirSync.call(this, path, { _isIndirect: true })) {
651
+ rmSync.call(this, join(path, entry), { ...options, _isIndirect: true });
653
652
  }
654
653
  }
655
- rmdirSync(path);
654
+ rmdirSync.call(this, path);
656
655
  break;
657
656
  case constants.S_IFREG:
658
657
  case constants.S_IFLNK:
659
658
  case constants.S_IFBLK:
660
659
  case constants.S_IFCHR:
661
- unlinkSync(path);
660
+ unlinkSync.call(this, path);
662
661
  break;
663
662
  case constants.S_IFIFO:
664
663
  case constants.S_IFSOCK:
@@ -675,7 +674,7 @@ export function mkdtempSync(prefix, options) {
675
674
  const encoding = typeof options === 'object' ? options?.encoding : options || 'utf8';
676
675
  const fsName = `${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`;
677
676
  const resolvedPath = '/tmp/' + fsName;
678
- mkdirSync(resolvedPath);
677
+ mkdirSync.call(this, resolvedPath);
679
678
  return encoding == 'buffer' ? Buffer.from(resolvedPath) : resolvedPath;
680
679
  }
681
680
  mkdtempSync;
@@ -690,7 +689,7 @@ export function copyFileSync(source, destination, flags) {
690
689
  if (flags && flags & constants.COPYFILE_EXCL && existsSync(destination)) {
691
690
  throw new ErrnoError(Errno.EEXIST, 'Destination file already exists.', destination, 'copyFile');
692
691
  }
693
- writeFileSync(destination, readFileSync(source));
692
+ writeFileSync.call(this, destination, readFileSync(source));
694
693
  emitChange('rename', destination.toString());
695
694
  }
696
695
  copyFileSync;
@@ -735,7 +734,7 @@ writevSync;
735
734
  */
736
735
  export function opendirSync(path, options) {
737
736
  path = normalizePath(path);
738
- return new Dir(path);
737
+ return new Dir(path, this);
739
738
  }
740
739
  opendirSync;
741
740
  /**
@@ -753,8 +752,8 @@ opendirSync;
753
752
  export function cpSync(source, destination, opts) {
754
753
  source = normalizePath(source);
755
754
  destination = normalizePath(destination);
756
- const srcStats = lstatSync(source); // Use lstat to follow symlinks if not dereferencing
757
- if (opts?.errorOnExist && existsSync(destination)) {
755
+ const srcStats = lstatSync.call(this, source); // Use lstat to follow symlinks if not dereferencing
756
+ if (opts?.errorOnExist && existsSync.call(this, destination)) {
758
757
  throw new ErrnoError(Errno.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
759
758
  }
760
759
  switch (srcStats.mode & constants.S_IFMT) {
@@ -762,17 +761,17 @@ export function cpSync(source, destination, opts) {
762
761
  if (!opts?.recursive) {
763
762
  throw new ErrnoError(Errno.EISDIR, source + ' is a directory (not copied)', source, 'cp');
764
763
  }
765
- mkdirSync(destination, { recursive: true }); // Ensure the destination directory exists
766
- for (const dirent of readdirSync(source, { withFileTypes: true })) {
764
+ mkdirSync.call(this, destination, { recursive: true }); // Ensure the destination directory exists
765
+ for (const dirent of readdirSync.call(this, source, { withFileTypes: true })) {
767
766
  if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
768
767
  continue; // Skip if the filter returns false
769
768
  }
770
- cpSync(join(source, dirent.name), join(destination, dirent.name), opts);
769
+ cpSync.call(this, join(source, dirent.name), join(destination, dirent.name), opts);
771
770
  }
772
771
  break;
773
772
  case constants.S_IFREG:
774
773
  case constants.S_IFLNK:
775
- copyFileSync(source, destination);
774
+ copyFileSync.call(this, source, destination);
776
775
  break;
777
776
  case constants.S_IFBLK:
778
777
  case constants.S_IFCHR:
@@ -783,12 +782,12 @@ export function cpSync(source, destination, opts) {
783
782
  }
784
783
  // Optionally preserve timestamps
785
784
  if (opts?.preserveTimestamps) {
786
- utimesSync(destination, srcStats.atime, srcStats.mtime);
785
+ utimesSync.call(this, destination, srcStats.atime, srcStats.mtime);
787
786
  }
788
787
  }
789
788
  cpSync;
790
789
  export function statfsSync(path, options) {
791
790
  path = normalizePath(path);
792
- const { fs } = resolveMount(path);
791
+ const { fs } = resolveMount(path, this);
793
792
  return _statfs(fs, options?.bigint);
794
793
  }
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from './backends/store/simple.js';
9
9
  export * from './backends/store/store.js';
10
10
  export * from './backends/backend.js';
11
11
  export * from './config.js';
12
+ export * from './context.js';
12
13
  export * from './credentials.js';
13
14
  export * from './devices.js';
14
15
  export { default as devices } from './devices.js';
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ export * from './backends/store/simple.js';
9
9
  export * from './backends/store/store.js';
10
10
  export * from './backends/backend.js';
11
11
  export * from './config.js';
12
+ export * from './context.js';
12
13
  export * from './credentials.js';
13
14
  export * from './devices.js';
14
15
  export { default as devices } from './devices.js';
package/dist/stats.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type * as Node from 'node:fs';
2
+ import type { V_Context } from './context.js';
2
3
  import { S_IFDIR, S_IFLNK, S_IFREG } from './emulation/constants.js';
3
4
  /**
4
5
  * Indicates the type of a file. Applied to 'mode'.
@@ -138,7 +139,7 @@ export declare abstract class StatsCommon<T extends number | bigint> implements
138
139
  * @returns True if the request has access, false if the request does not
139
140
  * @internal
140
141
  */
141
- hasAccess(mode: number): boolean;
142
+ hasAccess(mode: number, context?: V_Context): boolean;
142
143
  /**
143
144
  * Change the mode of the file.
144
145
  * We use this helper function to prevent messing up the type of the file.
package/dist/stats.js CHANGED
@@ -108,12 +108,13 @@ export class StatsCommon {
108
108
  * @returns True if the request has access, false if the request does not
109
109
  * @internal
110
110
  */
111
- hasAccess(mode) {
112
- if (this.isSymbolicLink() || credentials.euid === 0 || credentials.egid === 0)
111
+ hasAccess(mode, context) {
112
+ const creds = context?.credentials || credentials;
113
+ if (this.isSymbolicLink() || creds.euid === 0 || creds.egid === 0)
113
114
  return true;
114
115
  let perm = 0;
115
116
  // Owner permissions
116
- if (credentials.uid === this.uid) {
117
+ if (creds.uid === this.uid) {
117
118
  if (this.mode & S_IRUSR)
118
119
  perm |= R_OK;
119
120
  if (this.mode & S_IWUSR)
@@ -122,7 +123,7 @@ export class StatsCommon {
122
123
  perm |= X_OK;
123
124
  }
124
125
  // Group permissions
125
- if (credentials.gid === this.gid || credentials.groups.includes(Number(this.gid))) {
126
+ if (creds.gid === this.gid || creds.groups.includes(Number(this.gid))) {
126
127
  if (this.mode & S_IRGRP)
127
128
  perm |= R_OK;
128
129
  if (this.mode & S_IWGRP)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -18,7 +18,6 @@
18
18
  "zenfs-test": "scripts/test.js"
19
19
  },
20
20
  "files": [
21
- "src",
22
21
  "dist",
23
22
  "tests",
24
23
  "license.md",
@@ -49,14 +48,12 @@
49
48
  "./mixins": "./dist/mixins/index.js",
50
49
  "./path": "./dist/emulation/path.js",
51
50
  "./eslint": "./eslint.shared.js",
52
- "./tests/*": "./tests/*",
53
- "./src/*": "./src/*"
51
+ "./tests/*": "./tests/*"
54
52
  },
55
53
  "scripts": {
56
54
  "format": "prettier --write .",
57
55
  "format:check": "prettier --check .",
58
56
  "lint": "eslint src tests",
59
- "test:common": "tsx --test --experimental-test-coverage 'tests/**/!(fs)/*.test.ts' 'tests/*.test.ts'",
60
57
  "test": "tsx --test --experimental-test-coverage",
61
58
  "pretest": "npm run build",
62
59
  "build": "tsc -p tsconfig.json",
@@ -83,6 +80,7 @@
83
80
  "devDependencies": {
84
81
  "@eslint/js": "^9.8.0",
85
82
  "@types/eslint__js": "^8.42.3",
83
+ "c8": "^10.1.2",
86
84
  "eslint": "^9.8.0",
87
85
  "globals": "^15.9.0",
88
86
  "lint-staged": "^15.2.7",