@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
@@ -62,7 +62,8 @@ import { ReadStream, WriteStream } from './streams.js';
62
62
  import { FSWatcher, emitChange } from './watchers.js';
63
63
  export * as constants from './constants.js';
64
64
  export class FileHandle {
65
- constructor(fdOrFile) {
65
+ constructor(fdOrFile, context) {
66
+ this.context = context;
66
67
  const isFile = typeof fdOrFile != 'number';
67
68
  this.fd = isFile ? file2fd(fdOrFile) : fdOrFile;
68
69
  this.file = isFile ? fdOrFile : fd2file(fdOrFile);
@@ -219,7 +220,7 @@ export class FileHandle {
219
220
  }
220
221
  async stat(opts) {
221
222
  const stats = await this.file.stat();
222
- if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
223
+ if (config.checkAccess && !stats.hasAccess(constants.R_OK, this.context)) {
223
224
  throw ErrnoError.With('EACCES', this.file.path, 'stat');
224
225
  }
225
226
  return opts?.bigint ? new BigIntStats(stats) : stats;
@@ -351,9 +352,9 @@ export class FileHandle {
351
352
  export async function rename(oldPath, newPath) {
352
353
  oldPath = normalizePath(oldPath);
353
354
  newPath = normalizePath(newPath);
354
- const src = resolveMount(oldPath);
355
- const dst = resolveMount(newPath);
356
- if (config.checkAccess && !(await stat(dirname(oldPath))).hasAccess(constants.W_OK)) {
355
+ const src = resolveMount(oldPath, this);
356
+ const dst = resolveMount(newPath, this);
357
+ if (config.checkAccess && !(await stat.call(this, dirname(oldPath))).hasAccess(constants.W_OK, this)) {
357
358
  throw ErrnoError.With('EACCES', oldPath, 'rename');
358
359
  }
359
360
  try {
@@ -363,8 +364,8 @@ export async function rename(oldPath, newPath) {
363
364
  emitChange('change', newPath.toString());
364
365
  return;
365
366
  }
366
- await writeFile(newPath, await readFile(oldPath));
367
- await unlink(oldPath);
367
+ await writeFile.call(this, newPath, await readFile(oldPath));
368
+ await unlink.call(this, oldPath);
368
369
  emitChange('rename', oldPath.toString());
369
370
  }
370
371
  catch (e) {
@@ -377,7 +378,7 @@ rename;
377
378
  */
378
379
  export async function exists(path) {
379
380
  try {
380
- const { fs, path: resolved } = resolveMount(await realpath(path));
381
+ const { fs, path: resolved } = resolveMount(await realpath.call(this, path), this);
381
382
  return await fs.exists(resolved);
382
383
  }
383
384
  catch (e) {
@@ -389,10 +390,10 @@ export async function exists(path) {
389
390
  }
390
391
  export async function stat(path, options) {
391
392
  path = normalizePath(path);
392
- const { fs, path: resolved } = resolveMount(await realpath(path));
393
+ const { fs, path: resolved } = resolveMount(await realpath.call(this, path), this);
393
394
  try {
394
395
  const stats = await fs.stat(resolved);
395
- if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
396
+ if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
396
397
  throw ErrnoError.With('EACCES', resolved, 'stat');
397
398
  }
398
399
  return options?.bigint ? new BigIntStats(stats) : stats;
@@ -404,7 +405,7 @@ export async function stat(path, options) {
404
405
  stat;
405
406
  export async function lstat(path, options) {
406
407
  path = normalizePath(path);
407
- const { fs, path: resolved } = resolveMount(path);
408
+ const { fs, path: resolved } = resolveMount(path, this);
408
409
  try {
409
410
  const stats = await fs.stat(resolved);
410
411
  return options?.bigint ? new BigIntStats(stats) : stats;
@@ -418,7 +419,7 @@ lstat;
418
419
  export async function truncate(path, len = 0) {
419
420
  const env_1 = { stack: [], error: void 0, hasError: false };
420
421
  try {
421
- const handle = __addDisposableResource(env_1, await open(path, 'r+'), true);
422
+ const handle = __addDisposableResource(env_1, await open.call(this, path, 'r+'), true);
422
423
  await handle.truncate(len);
423
424
  }
424
425
  catch (e_1) {
@@ -434,9 +435,9 @@ export async function truncate(path, len = 0) {
434
435
  truncate;
435
436
  export async function unlink(path) {
436
437
  path = normalizePath(path);
437
- const { fs, path: resolved } = resolveMount(path);
438
+ const { fs, path: resolved } = resolveMount(path, this);
438
439
  try {
439
- if (config.checkAccess && !(await (cache.stats.getAsync(path) || fs.stat(resolved))).hasAccess(constants.W_OK)) {
440
+ if (config.checkAccess && !(await (cache.stats.getAsync(path) || fs.stat(resolved))).hasAccess(constants.W_OK, this)) {
440
441
  throw ErrnoError.With('EACCES', resolved, 'unlink');
441
442
  }
442
443
  await fs.unlink(resolved);
@@ -454,8 +455,8 @@ unlink;
454
455
  async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
455
456
  path = normalizePath(path);
456
457
  const mode = normalizeMode(_mode, 0o644), flag = parseFlag(_flag);
457
- path = resolveSymlinks ? await realpath(path) : path;
458
- const { fs, path: resolved } = resolveMount(path);
458
+ path = resolveSymlinks ? await realpath.call(this, path) : path;
459
+ const { fs, path: resolved } = resolveMount(path, this);
459
460
  const stats = await fs.stat(resolved).catch(() => null);
460
461
  if (!stats) {
461
462
  if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') {
@@ -463,21 +464,21 @@ async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
463
464
  }
464
465
  // Create the file
465
466
  const parentStats = await fs.stat(dirname(resolved));
466
- if (config.checkAccess && !parentStats.hasAccess(constants.W_OK)) {
467
+ if (config.checkAccess && !parentStats.hasAccess(constants.W_OK, this)) {
467
468
  throw ErrnoError.With('EACCES', dirname(path), '_open');
468
469
  }
469
470
  if (!parentStats.isDirectory()) {
470
471
  throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
471
472
  }
472
- return new FileHandle(await fs.createFile(resolved, flag, mode));
473
+ return new FileHandle(await fs.createFile(resolved, flag, mode), this);
473
474
  }
474
- if (config.checkAccess && !stats.hasAccess(flagToMode(flag))) {
475
+ if (config.checkAccess && !stats.hasAccess(flagToMode(flag), this)) {
475
476
  throw ErrnoError.With('EACCES', path, '_open');
476
477
  }
477
478
  if (isExclusive(flag)) {
478
479
  throw ErrnoError.With('EEXIST', path, '_open');
479
480
  }
480
- const handle = new FileHandle(await fs.openFile(resolved, flag));
481
+ const handle = new FileHandle(await fs.openFile(resolved, flag), this);
481
482
  /*
482
483
  In a previous implementation, we deleted the file and
483
484
  re-created it. However, this created a race condition if another
@@ -496,14 +497,14 @@ async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
496
497
  * @param mode Mode to use to open the file. Can be ignored if the filesystem doesn't support permissions.
497
498
  */
498
499
  export async function open(path, flag = 'r', mode = 0o644) {
499
- return await _open(path, flag, mode, true);
500
+ return await _open.call(this, path, flag, mode, true);
500
501
  }
501
502
  open;
502
503
  export async function readFile(path, _options) {
503
504
  const env_2 = { stack: [], error: void 0, hasError: false };
504
505
  try {
505
506
  const options = normalizeOptions(_options, null, 'r', 0o644);
506
- const handle = __addDisposableResource(env_2, typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode), true);
507
+ const handle = __addDisposableResource(env_2, typeof path == 'object' && 'fd' in path ? path : await open.call(this, path, options.flag, options.mode), true);
507
508
  return await handle.readFile(options);
508
509
  }
509
510
  catch (e_2) {
@@ -529,7 +530,7 @@ export async function writeFile(path, data, _options) {
529
530
  const env_3 = { stack: [], error: void 0, hasError: false };
530
531
  try {
531
532
  const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
532
- const handle = __addDisposableResource(env_3, path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode), true);
533
+ const handle = __addDisposableResource(env_3, path instanceof FileHandle ? path : await open.call(this, path.toString(), options.flag, options.mode), true);
533
534
  const _data = typeof data == 'string' ? data : data;
534
535
  if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {
535
536
  throw new ErrnoError(Errno.EINVAL, 'Iterables and streams not supported', handle.file.path, 'writeFile');
@@ -565,7 +566,7 @@ export async function appendFile(path, data, _options) {
565
566
  throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
566
567
  }
567
568
  const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
568
- const handle = __addDisposableResource(env_4, typeof path == 'object' && 'fd' in path ? path : await open(path, options.flag, options.mode), true);
569
+ const handle = __addDisposableResource(env_4, typeof path == 'object' && 'fd' in path ? path : await open.call(this, path, options.flag, options.mode), true);
569
570
  await handle.appendFile(encodedData, options);
570
571
  }
571
572
  catch (e_4) {
@@ -581,8 +582,8 @@ export async function appendFile(path, data, _options) {
581
582
  appendFile;
582
583
  // DIRECTORY-ONLY METHODS
583
584
  export async function rmdir(path) {
584
- path = await realpath(path);
585
- const { fs, path: resolved } = resolveMount(path);
585
+ path = await realpath.call(this, path);
586
+ const { fs, path: resolved } = resolveMount(path, this);
586
587
  try {
587
588
  const stats = await (cache.stats.getAsync(path) || fs.stat(resolved));
588
589
  if (!stats) {
@@ -591,7 +592,7 @@ export async function rmdir(path) {
591
592
  if (!stats.isDirectory()) {
592
593
  throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
593
594
  }
594
- if (config.checkAccess && !stats.hasAccess(constants.W_OK)) {
595
+ if (config.checkAccess && !stats.hasAccess(constants.W_OK, this)) {
595
596
  throw ErrnoError.With('EACCES', resolved, 'rmdir');
596
597
  }
597
598
  await fs.rmdir(resolved);
@@ -605,12 +606,12 @@ rmdir;
605
606
  export async function mkdir(path, options) {
606
607
  options = typeof options === 'object' ? options : { mode: options };
607
608
  const mode = normalizeMode(options?.mode, 0o777);
608
- path = await realpath(path);
609
- const { fs, path: resolved } = resolveMount(path);
609
+ path = await realpath.call(this, path);
610
+ const { fs, path: resolved, root } = resolveMount(path, this);
610
611
  const errorPaths = { [resolved]: path };
611
612
  try {
612
613
  if (!options?.recursive) {
613
- if (config.checkAccess && !(await fs.stat(dirname(resolved))).hasAccess(constants.W_OK)) {
614
+ if (config.checkAccess && !(await fs.stat(dirname(resolved))).hasAccess(constants.W_OK, this)) {
614
615
  throw ErrnoError.With('EACCES', dirname(resolved), 'mkdir');
615
616
  }
616
617
  await fs.mkdir(resolved, mode);
@@ -623,13 +624,13 @@ export async function mkdir(path, options) {
623
624
  errorPaths[dir] = origDir;
624
625
  }
625
626
  for (const dir of dirs) {
626
- if (config.checkAccess && !(await fs.stat(dirname(dir))).hasAccess(constants.W_OK)) {
627
+ if (config.checkAccess && !(await fs.stat(dirname(dir))).hasAccess(constants.W_OK, this)) {
627
628
  throw ErrnoError.With('EACCES', dirname(dir), 'mkdir');
628
629
  }
629
630
  await fs.mkdir(dir, mode);
630
631
  emitChange('rename', dir);
631
632
  }
632
- return dirs[0];
633
+ return root.length == 1 ? dirs[0] : dirs[0]?.slice(root.length);
633
634
  }
634
635
  catch (e) {
635
636
  throw fixError(e, errorPaths);
@@ -638,18 +639,18 @@ export async function mkdir(path, options) {
638
639
  mkdir;
639
640
  export async function readdir(path, options) {
640
641
  options = typeof options === 'object' ? options : { encoding: options };
641
- path = await realpath(path);
642
+ path = await realpath.call(this, path);
642
643
  const handleError = (e) => {
643
644
  throw fixError(e, { [resolved]: path });
644
645
  };
645
- const { fs, path: resolved } = resolveMount(path);
646
+ const { fs, path: resolved } = resolveMount(path, this);
646
647
  const _stats = cache.stats.getAsync(path) || fs.stat(resolved).catch(handleError);
647
648
  cache.stats.setAsync(path, _stats);
648
649
  const stats = await _stats;
649
650
  if (!stats) {
650
651
  throw ErrnoError.With('ENOENT', path, 'readdir');
651
652
  }
652
- if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
653
+ if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
653
654
  throw ErrnoError.With('EACCES', path, 'readdir');
654
655
  }
655
656
  if (!stats.isDirectory()) {
@@ -675,7 +676,7 @@ export async function readdir(path, options) {
675
676
  }
676
677
  if (!options?.recursive || !entryStats?.isDirectory())
677
678
  return;
678
- for (const subEntry of await readdir(join(path, entry), { ...options, _isIndirect: true })) {
679
+ for (const subEntry of await readdir.call(this, join(path, entry), { ...options, _isIndirect: true })) {
679
680
  if (subEntry instanceof Dirent) {
680
681
  subEntry.path = join(entry, subEntry.path);
681
682
  values.push(subEntry);
@@ -699,19 +700,19 @@ readdir;
699
700
  export async function link(targetPath, linkPath) {
700
701
  targetPath = normalizePath(targetPath);
701
702
  linkPath = normalizePath(linkPath);
702
- const { fs, path } = resolveMount(targetPath);
703
- const link = resolveMount(linkPath);
703
+ const { fs, path } = resolveMount(targetPath, this);
704
+ const link = resolveMount(linkPath, this);
704
705
  if (fs != link.fs) {
705
706
  throw ErrnoError.With('EXDEV', linkPath, 'link');
706
707
  }
707
708
  try {
708
- if (config.checkAccess && !(await fs.stat(dirname(targetPath))).hasAccess(constants.R_OK)) {
709
+ if (config.checkAccess && !(await fs.stat(dirname(targetPath))).hasAccess(constants.R_OK, this)) {
709
710
  throw ErrnoError.With('EACCES', dirname(path), 'link');
710
711
  }
711
- if (config.checkAccess && !(await stat(dirname(linkPath))).hasAccess(constants.W_OK)) {
712
+ if (config.checkAccess && !(await stat.call(this, dirname(linkPath))).hasAccess(constants.W_OK, this)) {
712
713
  throw ErrnoError.With('EACCES', dirname(linkPath), 'link');
713
714
  }
714
- if (config.checkAccess && !(await fs.stat(path)).hasAccess(constants.R_OK)) {
715
+ if (config.checkAccess && !(await fs.stat(path)).hasAccess(constants.R_OK, this)) {
715
716
  throw ErrnoError.With('EACCES', path, 'link');
716
717
  }
717
718
  return await fs.link(path, link.path);
@@ -733,10 +734,10 @@ export async function symlink(target, path, type = 'file') {
733
734
  if (!['file', 'dir', 'junction'].includes(type)) {
734
735
  throw new ErrnoError(Errno.EINVAL, 'Invalid symlink type: ' + type);
735
736
  }
736
- if (await exists(path)) {
737
+ if (await exists.call(this, path)) {
737
738
  throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
738
739
  }
739
- const handle = __addDisposableResource(env_5, await _open(path, 'w+', 0o644, false), true);
740
+ const handle = __addDisposableResource(env_5, await _open.call(this, path, 'w+', 0o644, false), true);
740
741
  await handle.writeFile(target.toString());
741
742
  await handle.file.chmod(constants.S_IFLNK);
742
743
  }
@@ -754,7 +755,7 @@ symlink;
754
755
  export async function readlink(path, options) {
755
756
  const env_6 = { stack: [], error: void 0, hasError: false };
756
757
  try {
757
- const handle = __addDisposableResource(env_6, await _open(normalizePath(path), 'r', 0o644, false), true);
758
+ const handle = __addDisposableResource(env_6, await _open.call(this, normalizePath(path), 'r', 0o644, false), true);
758
759
  const value = await handle.readFile();
759
760
  const encoding = typeof options == 'object' ? options?.encoding : options;
760
761
  return encoding == 'buffer' ? value : value.toString(encoding);
@@ -770,11 +771,10 @@ export async function readlink(path, options) {
770
771
  }
771
772
  }
772
773
  readlink;
773
- // PROPERTY OPERATIONS
774
774
  export async function chown(path, uid, gid) {
775
775
  const env_7 = { stack: [], error: void 0, hasError: false };
776
776
  try {
777
- const handle = __addDisposableResource(env_7, await open(path, 'r+'), true);
777
+ const handle = __addDisposableResource(env_7, await open.call(this, path, 'r+'), true);
778
778
  await handle.chown(uid, gid);
779
779
  }
780
780
  catch (e_7) {
@@ -791,7 +791,7 @@ chown;
791
791
  export async function lchown(path, uid, gid) {
792
792
  const env_8 = { stack: [], error: void 0, hasError: false };
793
793
  try {
794
- const handle = __addDisposableResource(env_8, await _open(path, 'r+', 0o644, false), true);
794
+ const handle = __addDisposableResource(env_8, await _open.call(this, path, 'r+', 0o644, false), true);
795
795
  await handle.chown(uid, gid);
796
796
  }
797
797
  catch (e_8) {
@@ -808,7 +808,7 @@ lchown;
808
808
  export async function chmod(path, mode) {
809
809
  const env_9 = { stack: [], error: void 0, hasError: false };
810
810
  try {
811
- const handle = __addDisposableResource(env_9, await open(path, 'r+'), true);
811
+ const handle = __addDisposableResource(env_9, await open.call(this, path, 'r+'), true);
812
812
  await handle.chmod(mode);
813
813
  }
814
814
  catch (e_9) {
@@ -825,7 +825,7 @@ chmod;
825
825
  export async function lchmod(path, mode) {
826
826
  const env_10 = { stack: [], error: void 0, hasError: false };
827
827
  try {
828
- const handle = __addDisposableResource(env_10, await _open(path, 'r+', 0o644, false), true);
828
+ const handle = __addDisposableResource(env_10, await _open.call(this, path, 'r+', 0o644, false), true);
829
829
  await handle.chmod(mode);
830
830
  }
831
831
  catch (e_10) {
@@ -845,7 +845,7 @@ lchmod;
845
845
  export async function utimes(path, atime, mtime) {
846
846
  const env_11 = { stack: [], error: void 0, hasError: false };
847
847
  try {
848
- const handle = __addDisposableResource(env_11, await open(path, 'r+'), true);
848
+ const handle = __addDisposableResource(env_11, await open.call(this, path, 'r+'), true);
849
849
  await handle.utimes(atime, mtime);
850
850
  }
851
851
  catch (e_11) {
@@ -865,7 +865,7 @@ utimes;
865
865
  export async function lutimes(path, atime, mtime) {
866
866
  const env_12 = { stack: [], error: void 0, hasError: false };
867
867
  try {
868
- const handle = __addDisposableResource(env_12, await _open(path, 'r+', 0o644, false), true);
868
+ const handle = __addDisposableResource(env_12, await _open.call(this, path, 'r+', 0o644, false), true);
869
869
  await handle.utimes(new Date(atime), new Date(mtime));
870
870
  }
871
871
  catch (e_12) {
@@ -881,12 +881,13 @@ export async function lutimes(path, atime, mtime) {
881
881
  lutimes;
882
882
  export async function realpath(path, options) {
883
883
  path = normalizePath(path);
884
- if (cache.paths.hasAsync(path))
885
- return cache.paths.getAsync(path);
884
+ const ctx_path = (this?.root || '') + path;
885
+ if (cache.paths.hasAsync(ctx_path))
886
+ return cache.paths.getAsync(ctx_path);
886
887
  const { base, dir } = parse(path);
887
- const realDir = dir == '/' ? '/' : await (cache.paths.getAsync(dir) || realpath(dir));
888
+ const realDir = dir == '/' ? '/' : await (cache.paths.getAsync((this?.root || '') + dir) || realpath.call(this, dir));
888
889
  const lpath = join(realDir, base);
889
- const { fs, path: resolvedPath } = resolveMount(lpath);
890
+ const { fs, path: resolvedPath } = resolveMount(lpath, this);
890
891
  try {
891
892
  const _stats = cache.stats.getAsync(lpath) || fs.stat(resolvedPath);
892
893
  cache.stats.setAsync(lpath, _stats);
@@ -894,9 +895,9 @@ export async function realpath(path, options) {
894
895
  cache.paths.set(path, lpath);
895
896
  return lpath;
896
897
  }
897
- const target = resolve(realDir, await readlink(lpath));
898
- const real = cache.paths.getAsync(target) || realpath(target);
899
- cache.paths.setAsync(path, real);
898
+ const target = resolve(realDir, (await readlink.call(this, lpath)).toString());
899
+ const real = cache.paths.getAsync((this?.root || '') + target) || realpath.call(this, target);
900
+ cache.paths.setAsync(ctx_path, real);
900
901
  return await real;
901
902
  }
902
903
  catch (e) {
@@ -940,8 +941,8 @@ watch;
940
941
  export async function access(path, mode = constants.F_OK) {
941
942
  if (!config.checkAccess)
942
943
  return;
943
- const stats = await stat(path);
944
- if (!stats.hasAccess(mode)) {
944
+ const stats = await stat.call(this, path);
945
+ if (!stats.hasAccess(mode, this)) {
945
946
  throw new ErrnoError(Errno.EACCES);
946
947
  }
947
948
  }
@@ -953,7 +954,7 @@ access;
953
954
  export async function rm(path, options) {
954
955
  path = normalizePath(path);
955
956
  const stats = await (cache.stats.getAsync(path) ||
956
- stat(path).catch((error) => {
957
+ lstat.call(this, path).catch((error) => {
957
958
  if (error.code == 'ENOENT' && options?.force)
958
959
  return undefined;
959
960
  throw error;
@@ -965,17 +966,17 @@ export async function rm(path, options) {
965
966
  switch (stats.mode & constants.S_IFMT) {
966
967
  case constants.S_IFDIR:
967
968
  if (options?.recursive) {
968
- for (const entry of await readdir(path, { _isIndirect: true })) {
969
- await rm(join(path, entry), { ...options, _isIndirect: true });
969
+ for (const entry of await readdir.call(this, path, { _isIndirect: true })) {
970
+ await rm.call(this, join(path, entry), { ...options, _isIndirect: true });
970
971
  }
971
972
  }
972
- await rmdir(path);
973
+ await rmdir.call(this, path);
973
974
  break;
974
975
  case constants.S_IFREG:
975
976
  case constants.S_IFLNK:
976
977
  case constants.S_IFBLK:
977
978
  case constants.S_IFCHR:
978
- await unlink(path);
979
+ await unlink.call(this, path);
979
980
  break;
980
981
  case constants.S_IFIFO:
981
982
  case constants.S_IFSOCK:
@@ -992,7 +993,7 @@ export async function mkdtemp(prefix, options) {
992
993
  const encoding = typeof options === 'object' ? options?.encoding : options || 'utf8';
993
994
  const fsName = `${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`;
994
995
  const resolvedPath = '/tmp/' + fsName;
995
- await mkdir(resolvedPath);
996
+ await mkdir.call(this, resolvedPath);
996
997
  return encoding == 'buffer' ? Buffer.from(resolvedPath) : resolvedPath;
997
998
  }
998
999
  mkdtemp;
@@ -1006,10 +1007,10 @@ mkdtemp;
1006
1007
  export async function copyFile(src, dest, mode) {
1007
1008
  src = normalizePath(src);
1008
1009
  dest = normalizePath(dest);
1009
- if (mode && mode & constants.COPYFILE_EXCL && (await exists(dest))) {
1010
+ if (mode && mode & constants.COPYFILE_EXCL && (await exists.call(this, dest))) {
1010
1011
  throw new ErrnoError(Errno.EEXIST, 'Destination file already exists.', dest, 'copyFile');
1011
1012
  }
1012
- await writeFile(dest, await readFile(src));
1013
+ await writeFile.call(this, dest, await readFile.call(this, src));
1013
1014
  emitChange('rename', dest.toString());
1014
1015
  }
1015
1016
  copyFile;
@@ -1022,7 +1023,7 @@ copyFile;
1022
1023
  */
1023
1024
  export function opendir(path, options) {
1024
1025
  path = normalizePath(path);
1025
- return Promise.resolve(new Dir(path));
1026
+ return Promise.resolve(new Dir(path, this));
1026
1027
  }
1027
1028
  opendir;
1028
1029
  /**
@@ -1040,8 +1041,8 @@ opendir;
1040
1041
  export async function cp(source, destination, opts) {
1041
1042
  source = normalizePath(source);
1042
1043
  destination = normalizePath(destination);
1043
- const srcStats = await lstat(source); // Use lstat to follow symlinks if not dereferencing
1044
- if (opts?.errorOnExist && (await exists(destination))) {
1044
+ const srcStats = await lstat.call(this, source); // Use lstat to follow symlinks if not dereferencing
1045
+ if (opts?.errorOnExist && (await exists.call(this, destination))) {
1045
1046
  throw new ErrnoError(Errno.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
1046
1047
  }
1047
1048
  switch (srcStats.mode & constants.S_IFMT) {
@@ -1049,20 +1050,20 @@ export async function cp(source, destination, opts) {
1049
1050
  if (!opts?.recursive) {
1050
1051
  throw new ErrnoError(Errno.EISDIR, source + ' is a directory (not copied)', source, 'cp');
1051
1052
  }
1052
- const [entries] = await Promise.all([readdir(source, { withFileTypes: true }), mkdir(destination, { recursive: true })] // Ensure the destination directory exists
1053
+ const [entries] = await Promise.all([readdir.call(this, source, { withFileTypes: true }), mkdir.call(this, destination, { recursive: true })] // Ensure the destination directory exists
1053
1054
  );
1054
1055
  const _cp = async (dirent) => {
1055
1056
  if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
1056
1057
  return; // Skip if the filter returns false
1057
1058
  }
1058
- await cp(join(source, dirent.name), join(destination, dirent.name), opts);
1059
+ await cp.call(this, join(source, dirent.name), join(destination, dirent.name), opts);
1059
1060
  };
1060
1061
  await Promise.all(entries.map(_cp));
1061
1062
  break;
1062
1063
  }
1063
1064
  case constants.S_IFREG:
1064
1065
  case constants.S_IFLNK:
1065
- await copyFile(source, destination);
1066
+ await copyFile.call(this, source, destination);
1066
1067
  break;
1067
1068
  case constants.S_IFBLK:
1068
1069
  case constants.S_IFCHR:
@@ -1073,12 +1074,12 @@ export async function cp(source, destination, opts) {
1073
1074
  }
1074
1075
  // Optionally preserve timestamps
1075
1076
  if (opts?.preserveTimestamps) {
1076
- await utimes(destination, srcStats.atime, srcStats.mtime);
1077
+ await utimes.call(this, destination, srcStats.atime, srcStats.mtime);
1077
1078
  }
1078
1079
  }
1079
1080
  cp;
1080
- export function statfs(path, opts) {
1081
+ export async function statfs(path, opts) {
1081
1082
  path = normalizePath(path);
1082
- const { fs } = resolveMount(path);
1083
+ const { fs } = resolveMount(path, this);
1083
1084
  return Promise.resolve(_statfs(fs, opts?.bigint));
1084
1085
  }
@@ -1,11 +1,24 @@
1
1
  import type { BigIntStatsFs, StatsFs } from 'node:fs';
2
+ import { type BoundContext, type V_Context } from '../context.js';
2
3
  import { ErrnoError } from '../error.js';
3
4
  import type { File } from '../file.js';
4
5
  import type { FileSystem } from '../filesystem.js';
5
6
  import { type AbsolutePath } from './path.js';
7
+ /**
8
+ * @internal @hidden
9
+ */
6
10
  export declare const fdMap: Map<number, File>;
11
+ /**
12
+ * @internal @hidden
13
+ */
7
14
  export declare function file2fd(file: File): number;
15
+ /**
16
+ * @internal @hidden
17
+ */
8
18
  export declare function fd2file(fd: number): File;
19
+ /**
20
+ * @internal @hidden
21
+ */
9
22
  export type MountObject = Record<AbsolutePath, FileSystem>;
10
23
  /**
11
24
  * The map of mount points
@@ -14,6 +27,7 @@ export type MountObject = Record<AbsolutePath, FileSystem>;
14
27
  export declare const mounts: Map<string, FileSystem>;
15
28
  /**
16
29
  * Mounts the file system at `mountPoint`.
30
+ * @internal
17
31
  */
18
32
  export declare function mount(mountPoint: string, fs: FileSystem): void;
19
33
  /**
@@ -21,13 +35,19 @@ export declare function mount(mountPoint: string, fs: FileSystem): void;
21
35
  */
22
36
  export declare function umount(mountPoint: string): void;
23
37
  /**
24
- * Gets the internal `FileSystem` for the path, then returns it along with the path relative to the FS' root
38
+ * @internal @hidden
25
39
  */
26
- export declare function resolveMount(path: string): {
40
+ export interface ResolvedMount {
27
41
  fs: FileSystem;
28
42
  path: string;
29
43
  mountPoint: string;
30
- };
44
+ root: string;
45
+ }
46
+ /**
47
+ * Gets the internal `FileSystem` for the path, then returns it along with the path relative to the FS' root
48
+ * @internal @hidden
49
+ */
50
+ export declare function resolveMount(path: string, ctx: V_Context): ResolvedMount;
31
51
  /**
32
52
  * Wait for all file systems to be ready and synced.
33
53
  * May be removed at some point.
@@ -36,25 +56,25 @@ export declare function resolveMount(path: string): {
36
56
  export declare function _synced(): Promise<void>;
37
57
  /**
38
58
  * Reverse maps the paths in text from the mounted FileSystem to the global path
39
- * @hidden
59
+ * @internal @hidden
40
60
  */
41
61
  export declare function fixPaths(text: string, paths: Record<string, string>): string;
42
62
  /**
43
63
  * Fix paths in error stacks
44
- * @hidden
64
+ * @internal @hidden
45
65
  */
46
66
  export declare function fixError<E extends ErrnoError>(e: E, paths: Record<string, string>): E;
47
67
  /**
48
- * @deprecated
68
+ * @internal @deprecated
49
69
  */
50
70
  export declare function mountObject(mounts: MountObject): void;
51
71
  /**
52
- * @hidden
72
+ * @internal @hidden
53
73
  */
54
74
  export declare function _statfs<const T extends boolean>(fs: FileSystem, bigint?: T): T extends true ? BigIntStatsFs : StatsFs;
55
75
  /**
56
76
  * Options used for caching, among other things.
57
- * @internal *UNSTABLE*
77
+ * @internal @hidden *UNSTABLE*
58
78
  */
59
79
  export interface InternalOptions {
60
80
  /**
@@ -68,3 +88,10 @@ export interface ReaddirOptions extends InternalOptions {
68
88
  withFileTypes?: boolean;
69
89
  recursive?: boolean;
70
90
  }
91
+ /**
92
+ * Change the root path
93
+ * @param inPlace if true, this changes the root for the current context instead of creating a new one (if associated with a context).
94
+ * @experimental
95
+ */
96
+ export declare function chroot(this: V_Context, path: string, inPlace?: false): BoundContext;
97
+ export declare function chroot<T extends V_Context>(this: T, path: string, inPlace: true): T;