@zenfs/core 1.9.3 → 1.9.5

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.
@@ -57,7 +57,6 @@ import { flagToMode, isAppendable, isExclusive, isReadable, isTruncating, isWrit
57
57
  import '../polyfills.js';
58
58
  import { BigIntStats } from '../stats.js';
59
59
  import { decodeUTF8, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
60
- import * as cache from './cache.js';
61
60
  import { config } from './config.js';
62
61
  import * as constants from './constants.js';
63
62
  import { Dir, Dirent } from './dir.js';
@@ -90,9 +89,8 @@ export class FileHandle {
90
89
  */
91
90
  async chmod(mode) {
92
91
  const numMode = normalizeMode(mode, -1);
93
- if (numMode < 0) {
92
+ if (numMode < 0)
94
93
  throw new ErrnoError(Errno.EINVAL, 'Invalid mode.');
95
- }
96
94
  await this.file.chmod(numMode);
97
95
  this._emitChange();
98
96
  }
@@ -459,7 +457,7 @@ export async function unlink(path) {
459
457
  path = normalizePath(path);
460
458
  const { fs, path: resolved } = resolveMount(path, this);
461
459
  try {
462
- if (config.checkAccess && !(await (cache.stats.getAsync(path) || fs.stat(resolved))).hasAccess(constants.W_OK, this)) {
460
+ if (config.checkAccess && !(await fs.stat(resolved)).hasAccess(constants.W_OK, this)) {
463
461
  throw ErrnoError.With('EACCES', resolved, 'unlink');
464
462
  }
465
463
  await fs.unlink(resolved);
@@ -484,37 +482,35 @@ async function applySetId(file, uid, gid) {
484
482
  * Opens a file. This helper handles the complexity of file flags.
485
483
  * @internal
486
484
  */
487
- async function _open(path, opt) {
485
+ async function _open($, path, opt) {
488
486
  var _a;
489
487
  path = normalizePath(path);
490
488
  const mode = normalizeMode(opt.mode, 0o644), flag = parseFlag(opt.flag);
491
- path = opt.preserveSymlinks ? path : await realpath.call(this, path);
492
- const { fs, path: resolved } = resolveMount(path, this);
493
- const stats = await fs.stat(resolved).catch(() => null);
489
+ const { fullPath, fs, path: resolved, stats } = await _resolve($, path.toString(), opt.preserveSymlinks);
494
490
  if (!stats) {
495
491
  if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') {
496
- throw ErrnoError.With('ENOENT', path, '_open');
492
+ throw ErrnoError.With('ENOENT', fullPath, '_open');
497
493
  }
498
494
  // Create the file
499
495
  const parentStats = await fs.stat(dirname(resolved));
500
- if (config.checkAccess && !parentStats.hasAccess(constants.W_OK, this)) {
501
- throw ErrnoError.With('EACCES', dirname(path), '_open');
496
+ if (config.checkAccess && !parentStats.hasAccess(constants.W_OK, $)) {
497
+ throw ErrnoError.With('EACCES', dirname(fullPath), '_open');
502
498
  }
503
499
  if (!parentStats.isDirectory()) {
504
- throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
500
+ throw ErrnoError.With('ENOTDIR', dirname(fullPath), '_open');
505
501
  }
506
- const { euid: uid, egid: gid } = (_a = this === null || this === void 0 ? void 0 : this.credentials) !== null && _a !== void 0 ? _a : credentials;
502
+ const { euid: uid, egid: gid } = (_a = $ === null || $ === void 0 ? void 0 : $.credentials) !== null && _a !== void 0 ? _a : credentials;
507
503
  const file = await fs.createFile(resolved, flag, mode, { uid, gid });
508
504
  await applySetId(file, uid, gid);
509
- return new FileHandle(file, this);
505
+ return new FileHandle(file, $);
510
506
  }
511
- if (config.checkAccess && !stats.hasAccess(flagToMode(flag), this)) {
512
- throw ErrnoError.With('EACCES', path, '_open');
507
+ if (config.checkAccess && !stats.hasAccess(flagToMode(flag), $)) {
508
+ throw ErrnoError.With('EACCES', fullPath, '_open');
513
509
  }
514
510
  if (isExclusive(flag)) {
515
- throw ErrnoError.With('EEXIST', path, '_open');
511
+ throw ErrnoError.With('EEXIST', fullPath, '_open');
516
512
  }
517
- const handle = new FileHandle(await fs.openFile(resolved, flag), this);
513
+ const handle = new FileHandle(await fs.openFile(resolved, flag), $);
518
514
  /*
519
515
  In a previous implementation, we deleted the file and
520
516
  re-created it. However, this created a race condition if another
@@ -533,7 +529,7 @@ async function _open(path, opt) {
533
529
  * @param mode Mode to use to open the file. Can be ignored if the filesystem doesn't support permissions.
534
530
  */
535
531
  export async function open(path, flag = 'r', mode = 0o644) {
536
- return await _open.call(this, path, { flag, mode });
532
+ return await _open(this, path, { flag, mode });
537
533
  }
538
534
  open;
539
535
  export async function readFile(path, _options) {
@@ -625,7 +621,7 @@ export async function rmdir(path) {
625
621
  path = await realpath.call(this, path);
626
622
  const { fs, path: resolved } = resolveMount(path, this);
627
623
  try {
628
- const stats = await (cache.stats.getAsync(path) || fs.stat(resolved));
624
+ const stats = await fs.stat(resolved);
629
625
  if (!stats) {
630
626
  throw ErrnoError.With('ENOENT', path, 'rmdir');
631
627
  }
@@ -688,9 +684,7 @@ export async function readdir(path, options) {
688
684
  throw fixError(e, { [resolved]: path });
689
685
  };
690
686
  const { fs, path: resolved } = resolveMount(path, this);
691
- const _stats = cache.stats.getAsync(path) || fs.stat(resolved).catch(handleError);
692
- cache.stats.setAsync(path, _stats);
693
- const stats = await _stats;
687
+ const stats = await fs.stat(resolved).catch(handleError);
694
688
  if (!stats) {
695
689
  throw ErrnoError.With('ENOENT', path, 'readdir');
696
690
  }
@@ -705,9 +699,7 @@ export async function readdir(path, options) {
705
699
  const addEntry = async (entry) => {
706
700
  let entryStats;
707
701
  if ((options === null || options === void 0 ? void 0 : options.recursive) || (options === null || options === void 0 ? void 0 : options.withFileTypes)) {
708
- const _entryStats = cache.stats.getAsync(join(path, entry)) || fs.stat(join(resolved, entry)).catch(handleError);
709
- cache.stats.setAsync(join(path, entry), _entryStats);
710
- entryStats = await _entryStats;
702
+ entryStats = await fs.stat(join(resolved, entry)).catch(handleError);
711
703
  }
712
704
  if (options === null || options === void 0 ? void 0 : options.withFileTypes) {
713
705
  values.push(new Dirent(entry, entryStats));
@@ -720,7 +712,7 @@ export async function readdir(path, options) {
720
712
  }
721
713
  if (!(options === null || options === void 0 ? void 0 : options.recursive) || !(entryStats === null || entryStats === void 0 ? void 0 : entryStats.isDirectory()))
722
714
  return;
723
- for (const subEntry of await readdir.call(this, join(path, entry), { ...options, _isIndirect: true })) {
715
+ for (const subEntry of await readdir.call(this, join(path, entry), options)) {
724
716
  if (subEntry instanceof Dirent) {
725
717
  subEntry.path = join(entry, subEntry.path);
726
718
  values.push(subEntry);
@@ -735,9 +727,6 @@ export async function readdir(path, options) {
735
727
  }
736
728
  };
737
729
  await Promise.all(entries.map(addEntry));
738
- if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
739
- cache.stats.clear();
740
- }
741
730
  return values;
742
731
  }
743
732
  readdir;
@@ -778,11 +767,11 @@ export async function symlink(target, path, type = 'file') {
778
767
  if (!['file', 'dir', 'junction'].includes(type)) {
779
768
  throw new ErrnoError(Errno.EINVAL, 'Invalid symlink type: ' + type);
780
769
  }
781
- if (await exists.call(this, path)) {
782
- throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
783
- }
784
- const handle = __addDisposableResource(env_5, await _open.call(this, path, { flag: 'w+', mode: 0o644, preserveSymlinks: true }), true);
785
- await handle.writeFile(target.toString());
770
+ path = normalizePath(path);
771
+ if (await exists.call(this, path))
772
+ throw ErrnoError.With('EEXIST', path, 'symlink');
773
+ const handle = __addDisposableResource(env_5, await _open(this, path, { flag: 'w+', mode: 0o644, preserveSymlinks: true }), true);
774
+ await handle.writeFile(normalizePath(target, true));
786
775
  await handle.file.chmod(constants.S_IFLNK);
787
776
  }
788
777
  catch (e_5) {
@@ -799,7 +788,7 @@ symlink;
799
788
  export async function readlink(path, options) {
800
789
  const env_6 = { stack: [], error: void 0, hasError: false };
801
790
  try {
802
- const handle = __addDisposableResource(env_6, await _open.call(this, normalizePath(path), { flag: 'r', mode: 0o644, preserveSymlinks: true }), true);
791
+ const handle = __addDisposableResource(env_6, await _open(this, normalizePath(path), { flag: 'r', mode: 0o644, preserveSymlinks: true }), true);
803
792
  const value = await handle.readFile();
804
793
  const encoding = typeof options == 'object' ? options === null || options === void 0 ? void 0 : options.encoding : options;
805
794
  // always defaults to utf-8 to avoid wrangler (cloudflare) worker "unknown encoding" exception
@@ -836,7 +825,7 @@ chown;
836
825
  export async function lchown(path, uid, gid) {
837
826
  const env_8 = { stack: [], error: void 0, hasError: false };
838
827
  try {
839
- const handle = __addDisposableResource(env_8, await _open.call(this, path, {
828
+ const handle = __addDisposableResource(env_8, await _open(this, path, {
840
829
  flag: 'r+',
841
830
  mode: 0o644,
842
831
  preserveSymlinks: true,
@@ -875,7 +864,7 @@ chmod;
875
864
  export async function lchmod(path, mode) {
876
865
  const env_10 = { stack: [], error: void 0, hasError: false };
877
866
  try {
878
- const handle = __addDisposableResource(env_10, await _open.call(this, path, {
867
+ const handle = __addDisposableResource(env_10, await _open(this, path, {
879
868
  flag: 'r+',
880
869
  mode: 0o644,
881
870
  preserveSymlinks: true,
@@ -920,7 +909,7 @@ utimes;
920
909
  export async function lutimes(path, atime, mtime) {
921
910
  const env_12 = { stack: [], error: void 0, hasError: false };
922
911
  try {
923
- const handle = __addDisposableResource(env_12, await _open.call(this, path, {
912
+ const handle = __addDisposableResource(env_12, await _open(this, path, {
924
913
  flag: 'r+',
925
914
  mode: 0o644,
926
915
  preserveSymlinks: true,
@@ -939,52 +928,63 @@ export async function lutimes(path, atime, mtime) {
939
928
  }
940
929
  }
941
930
  lutimes;
942
- export async function realpath(path, options) {
943
- path = normalizePath(path);
944
- const ctx_path = ((this === null || this === void 0 ? void 0 : this.root) || '') + path;
945
- if (cache.paths.hasAsync(ctx_path))
946
- return cache.paths.getAsync(ctx_path);
931
+ /**
932
+ * Resolves the mount and real path for a path.
933
+ * Additionally, any stats fetched will be returned for de-duplication
934
+ * @internal @hidden
935
+ */
936
+ async function _resolve($, path, preserveSymlinks) {
937
+ if (preserveSymlinks) {
938
+ const resolved = resolveMount(path, $);
939
+ const stats = await resolved.fs.stat(resolved.path).catch(() => undefined);
940
+ return { ...resolved, fullPath: path, stats };
941
+ }
947
942
  /* Try to resolve it directly. If this works,
948
943
  that means we don't need to perform any resolution for parent directories. */
949
944
  try {
950
- const { fs, path: resolvedPath } = resolveMount(path, this);
945
+ const resolved = resolveMount(path, $);
951
946
  // Stat it to make sure it exists
952
- const stats = await fs.stat(resolvedPath);
953
- let real = path.toString();
954
- if (stats.isSymbolicLink()) {
955
- const target = resolve(dirname(resolvedPath), (await readlink.call(this, resolvedPath, options)).toString());
956
- real = cache.paths.get(((this === null || this === void 0 ? void 0 : this.root) || '') + target) || (await realpath.call(this, target));
957
- cache.paths.set(ctx_path, real);
947
+ const stats = await resolved.fs.stat(resolved.path);
948
+ if (!stats.isSymbolicLink()) {
949
+ return { ...resolved, fullPath: path, stats };
958
950
  }
959
- cache.paths.set(path.toString(), real);
960
- return real;
951
+ const target = resolve(dirname(path), (await readlink.call($, path)).toString());
952
+ return await _resolve($, target);
961
953
  }
962
954
  catch {
963
955
  // Go the long way
964
956
  }
965
957
  const { base, dir } = parse(path);
966
- const realDir = dir == '/' ? '/' : await (cache.paths.getAsync(((this === null || this === void 0 ? void 0 : this.root) || '') + dir) || realpath.call(this, dir));
967
- const lpath = join(realDir, base);
968
- const { fs, path: resolvedPath } = resolveMount(lpath, this);
958
+ const realDir = dir == '/' ? '/' : await realpath.call($, dir);
959
+ const maybePath = join(realDir, base);
960
+ const resolved = resolveMount(maybePath, $);
969
961
  try {
970
- const _stats = cache.stats.getAsync(lpath) || fs.stat(resolvedPath);
971
- cache.stats.setAsync(lpath, _stats);
972
- if (!(await _stats).isSymbolicLink()) {
973
- cache.paths.set(path, lpath);
974
- return lpath;
962
+ const stats = await resolved.fs.stat(resolved.path);
963
+ if (!stats.isSymbolicLink()) {
964
+ return { ...resolved, fullPath: maybePath, stats };
975
965
  }
976
- const target = resolve(realDir, (await readlink.call(this, lpath)).toString());
977
- const real = cache.paths.getAsync(((this === null || this === void 0 ? void 0 : this.root) || '') + target) || realpath.call(this, target);
978
- cache.paths.setAsync(ctx_path, real);
979
- return await real;
966
+ const target = resolve(realDir, (await readlink.call($, maybePath)).toString());
967
+ return await _resolve($, target);
980
968
  }
981
969
  catch (e) {
982
970
  if (e.code == 'ENOENT') {
983
- return path;
971
+ return { ...resolved, fullPath: path };
984
972
  }
985
- throw fixError(e, { [resolvedPath]: lpath });
973
+ throw fixError(e, { [resolved.path]: maybePath });
986
974
  }
987
975
  }
976
+ export async function realpath(path, options) {
977
+ var _a;
978
+ const encoding = typeof options == 'string' ? options : ((_a = options === null || options === void 0 ? void 0 : options.encoding) !== null && _a !== void 0 ? _a : 'utf8');
979
+ path = normalizePath(path);
980
+ const { fullPath } = await _resolve(this, path);
981
+ if (encoding == 'utf8' || encoding == 'utf-8')
982
+ return fullPath;
983
+ const buf = Buffer.from(fullPath, 'utf-8');
984
+ if (encoding == 'buffer')
985
+ return buf;
986
+ return buf.toString(encoding);
987
+ }
988
988
  realpath;
989
989
  export function watch(filename, options = {}) {
990
990
  const watcher = new FSWatcher(this, filename.toString(), typeof options !== 'string' ? options : { encoding: options });
@@ -1038,23 +1038,18 @@ access;
1038
1038
  */
1039
1039
  export async function rm(path, options) {
1040
1040
  path = normalizePath(path);
1041
- const stats = await (cache.stats.getAsync(path) ||
1042
- lstat.call(this, path).catch((error) => {
1043
- if (error.code == 'ENOENT' && (options === null || options === void 0 ? void 0 : options.force))
1044
- return undefined;
1045
- throw error;
1046
- }));
1047
- if (!stats) {
1041
+ const stats = await lstat.call(this, path).catch((error) => {
1042
+ if (error.code == 'ENOENT' && (options === null || options === void 0 ? void 0 : options.force))
1043
+ return undefined;
1044
+ throw error;
1045
+ });
1046
+ if (!stats)
1048
1047
  return;
1049
- }
1050
- cache.stats.set(path, stats);
1051
1048
  switch (stats.mode & constants.S_IFMT) {
1052
1049
  case constants.S_IFDIR:
1053
1050
  if (options === null || options === void 0 ? void 0 : options.recursive) {
1054
- for (const entry of await readdir.call(this, path, {
1055
- _isIndirect: true,
1056
- })) {
1057
- await rm.call(this, join(path, entry), { ...options, _isIndirect: true });
1051
+ for (const entry of (await readdir.call(this, path))) {
1052
+ await rm.call(this, join(path, entry), options);
1058
1053
  }
1059
1054
  }
1060
1055
  await rmdir.call(this, path);
@@ -1068,12 +1063,8 @@ export async function rm(path, options) {
1068
1063
  case constants.S_IFIFO:
1069
1064
  case constants.S_IFSOCK:
1070
1065
  default:
1071
- cache.stats.clear();
1072
1066
  throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
1073
1067
  }
1074
- if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
1075
- cache.stats.clear();
1076
- }
1077
1068
  }
1078
1069
  rm;
1079
1070
  export async function mkdtemp(prefix, options) {
@@ -1,6 +1,7 @@
1
1
  import type * as fs from 'node:fs';
2
2
  import type { File } from '../internal/file.js';
3
3
  import type { FileSystem } from '../internal/filesystem.js';
4
+ import type { Stats } from '../stats.js';
4
5
  import { type BoundContext, type V_Context } from '../context.js';
5
6
  import { ErrnoError } from '../internal/error.js';
6
7
  import { type AbsolutePath } from './path.js';
@@ -46,6 +47,15 @@ export interface ResolvedMount {
46
47
  mountPoint: string;
47
48
  root: string;
48
49
  }
50
+ /**
51
+ * @internal @hidden
52
+ */
53
+ export interface ResolvedPath extends ResolvedMount {
54
+ /** The real, absolute path */
55
+ fullPath: string;
56
+ /** Stats */
57
+ stats?: Stats;
58
+ }
49
59
  /**
50
60
  * Gets the internal `FileSystem` for the path, then returns it along with the path relative to the FS' root
51
61
  * @internal @hidden
@@ -4,7 +4,6 @@ import { bindContext } from '../context.js';
4
4
  import { Errno, ErrnoError } from '../internal/error.js';
5
5
  import { alert, debug, err, info, log_deprecated, notice, warn } from '../internal/log.js';
6
6
  import { normalizePath } from '../utils.js';
7
- import { paths as pathCache } from './cache.js';
8
7
  import { size_max } from './constants.js';
9
8
  import { join, resolve } from './path.js';
10
9
  // descriptors
@@ -54,7 +53,6 @@ export function mount(mountPoint, fs) {
54
53
  mounts.set(mountPoint, fs);
55
54
  info(`Mounted ${fs.name} on ${mountPoint}`);
56
55
  debug(`${fs.name} attributes: ${[...fs.attributes].map(([k, v]) => (v !== undefined && v !== null ? k + '=' + v : v)).join(', ')}`);
57
- pathCache.clear();
58
56
  }
59
57
  /**
60
58
  * Unmounts the file system at `mountPoint`.
@@ -69,7 +67,6 @@ export function umount(mountPoint) {
69
67
  return;
70
68
  }
71
69
  mounts.delete(mountPoint);
72
- pathCache.clear();
73
70
  notice('Unmounted ' + mountPoint);
74
71
  }
75
72
  /**
@@ -84,9 +81,8 @@ export function resolveMount(path, ctx) {
84
81
  // We know path is normalized, so it would be a substring of the mount point.
85
82
  if (_isParentOf(mountPoint, path)) {
86
83
  path = path.slice(mountPoint.length > 1 ? mountPoint.length : 0); // Resolve the path relative to the mount point
87
- if (path === '') {
84
+ if (path === '')
88
85
  path = root;
89
- }
90
86
  return { fs, path, mountPoint, root };
91
87
  }
92
88
  }
@@ -1,7 +1,7 @@
1
1
  import type * as fs from 'node:fs';
2
2
  import type { V_Context } from '../context.js';
3
3
  import type { Stats } from '../stats.js';
4
- import type { FileContents, InternalOptions, NullEnc, ReaddirOptions, ReaddirOptsI, ReaddirOptsU } from './types.js';
4
+ import type { FileContents, NullEnc, ReaddirOptions, ReaddirOptsI, ReaddirOptsU } from './types.js';
5
5
  import { Buffer } from 'buffer';
6
6
  import { BigIntStats } from '../stats.js';
7
7
  import { Dir, Dirent } from './dir.js';
@@ -155,7 +155,7 @@ export declare function accessSync(this: V_Context, path: fs.PathLike, mode?: nu
155
155
  * Synchronous `rm`. Removes files or directories (recursively).
156
156
  * @param path The path to the file or directory to remove.
157
157
  */
158
- export declare function rmSync(this: V_Context, path: fs.PathLike, options?: fs.RmOptions & InternalOptions): void;
158
+ export declare function rmSync(this: V_Context, path: fs.PathLike, options?: fs.RmOptions): void;
159
159
  /**
160
160
  * Synchronous `mkdtemp`. Creates a unique temporary directory.
161
161
  * @param prefix The directory prefix.
package/dist/vfs/sync.js CHANGED
@@ -56,7 +56,6 @@ import { Errno, ErrnoError } from '../internal/error.js';
56
56
  import { flagToMode, isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../internal/file.js';
57
57
  import { BigIntStats } from '../stats.js';
58
58
  import { decodeUTF8, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
59
- import * as cache from './cache.js';
60
59
  import { config } from './config.js';
61
60
  import * as constants from './constants.js';
62
61
  import { Dir, Dirent } from './dir.js';
@@ -154,7 +153,7 @@ export function unlinkSync(path) {
154
153
  path = normalizePath(path);
155
154
  const { fs, path: resolved } = resolveMount(path, this);
156
155
  try {
157
- if (config.checkAccess && !(cache.stats.get(path) || fs.statSync(resolved)).hasAccess(constants.W_OK, this)) {
156
+ if (config.checkAccess && !fs.statSync(resolved).hasAccess(constants.W_OK, this)) {
158
157
  throw ErrnoError.With('EACCES', resolved, 'unlink');
159
158
  }
160
159
  fs.unlinkSync(resolved);
@@ -236,11 +235,12 @@ openSync;
236
235
  export function lopenSync(path, flag, mode) {
237
236
  return file2fd(_openSync.call(this, path, { flag, mode, preserveSymlinks: true }));
238
237
  }
239
- function _readFileSync(fname, flag, preserveSymlinks) {
238
+ function _readFileSync(path, flag, preserveSymlinks) {
240
239
  const env_2 = { stack: [], error: void 0, hasError: false };
241
240
  try {
241
+ path = normalizePath(path);
242
242
  // Get file.
243
- const file = __addDisposableResource(env_2, _openSync.call(this, fname, { flag, mode: 0o644, preserveSymlinks }), false);
243
+ const file = __addDisposableResource(env_2, _openSync.call(this, path, { flag, mode: 0o644, preserveSymlinks }), false);
244
244
  const stat = file.statSync();
245
245
  // Allocate buffer.
246
246
  const data = new Uint8Array(stat.size);
@@ -261,7 +261,7 @@ export function readFileSync(path, _options = {}) {
261
261
  if (!isReadable(flag)) {
262
262
  throw new ErrnoError(Errno.EINVAL, 'Flag passed to readFile must allow for reading.');
263
263
  }
264
- const data = Buffer.from(_readFileSync.call(this, typeof path == 'number' ? fd2file(path).path : path.toString(), options.flag, false));
264
+ const data = Buffer.from(_readFileSync.call(this, typeof path == 'number' ? fd2file(path).path : path, options.flag, false));
265
265
  return options.encoding ? data.toString(options.encoding) : data;
266
266
  }
267
267
  readFileSync;
@@ -426,7 +426,7 @@ export function rmdirSync(path) {
426
426
  path = normalizePath(path);
427
427
  const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
428
428
  try {
429
- const stats = cache.stats.get(path) || fs.statSync(resolved);
429
+ const stats = fs.statSync(resolved);
430
430
  if (!stats.isDirectory()) {
431
431
  throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
432
432
  }
@@ -484,8 +484,7 @@ export function readdirSync(path, options) {
484
484
  const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
485
485
  let entries;
486
486
  try {
487
- const stats = cache.stats.get(path) || fs.statSync(resolved);
488
- cache.stats.set(path, stats);
487
+ const stats = fs.statSync(resolved);
489
488
  if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
490
489
  throw ErrnoError.With('EACCES', resolved, 'readdir');
491
490
  }
@@ -500,8 +499,7 @@ export function readdirSync(path, options) {
500
499
  // Iterate over entries and handle recursive case if needed
501
500
  const values = [];
502
501
  for (const entry of entries) {
503
- const entryStat = cache.stats.get(join(path, entry)) || fs.statSync(join(resolved, entry));
504
- cache.stats.set(join(path, entry), entryStat);
502
+ const entryStat = fs.statSync(join(resolved, entry));
505
503
  if (options === null || options === void 0 ? void 0 : options.withFileTypes) {
506
504
  values.push(new Dirent(entry, entryStat));
507
505
  }
@@ -513,7 +511,7 @@ export function readdirSync(path, options) {
513
511
  }
514
512
  if (!entryStat.isDirectory() || !(options === null || options === void 0 ? void 0 : options.recursive))
515
513
  continue;
516
- for (const subEntry of readdirSync.call(this, join(path, entry), { ...options, _isIndirect: true })) {
514
+ for (const subEntry of readdirSync.call(this, join(path, entry), options)) {
517
515
  if (subEntry instanceof Dirent) {
518
516
  subEntry.path = join(entry, subEntry.path);
519
517
  values.push(subEntry);
@@ -526,9 +524,6 @@ export function readdirSync(path, options) {
526
524
  }
527
525
  }
528
526
  }
529
- if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
530
- cache.stats.clear();
531
- }
532
527
  return values;
533
528
  }
534
529
  readdirSync;
@@ -570,13 +565,13 @@ export function symlinkSync(target, path, type = 'file') {
570
565
  if (existsSync.call(this, path)) {
571
566
  throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
572
567
  }
573
- writeFileSync.call(this, path, target.toString());
568
+ writeFileSync.call(this, path, normalizePath(target, true));
574
569
  const file = _openSync.call(this, path, { flag: 'r+', mode: 0o644, preserveSymlinks: true });
575
570
  file.chmodSync(constants.S_IFLNK);
576
571
  }
577
572
  symlinkSync;
578
573
  export function readlinkSync(path, options) {
579
- const value = Buffer.from(_readFileSync.call(this, path.toString(), 'r', true));
574
+ const value = Buffer.from(_readFileSync.call(this, path, 'r', true));
580
575
  const encoding = typeof options == 'object' ? options === null || options === void 0 ? void 0 : options.encoding : options;
581
576
  if (encoding == 'buffer') {
582
577
  return value;
@@ -627,52 +622,63 @@ export function lutimesSync(path, atime, mtime) {
627
622
  closeSync(fd);
628
623
  }
629
624
  lutimesSync;
630
- export function realpathSync(path, options) {
631
- path = normalizePath(path);
632
- const ctx_path = ((this === null || this === void 0 ? void 0 : this.root) || '') + path;
633
- if (cache.paths.has(ctx_path))
634
- return cache.paths.get(ctx_path);
625
+ /**
626
+ * Resolves the mount and real path for a path.
627
+ * Additionally, any stats fetched will be returned for de-duplication
628
+ * @internal @hidden
629
+ */
630
+ function _resolveSync($, path, preserveSymlinks) {
631
+ if (preserveSymlinks) {
632
+ const resolved = resolveMount(path, $);
633
+ const stats = resolved.fs.statSync(resolved.path);
634
+ return { ...resolved, fullPath: path, stats };
635
+ }
635
636
  /* Try to resolve it directly. If this works,
636
637
  that means we don't need to perform any resolution for parent directories. */
637
638
  try {
638
- const { fs, path: resolvedPath } = resolveMount(path, this);
639
+ const resolved = resolveMount(path, $);
639
640
  // Stat it to make sure it exists
640
- const stats = fs.statSync(resolvedPath);
641
- let real = path;
642
- if (stats.isSymbolicLink()) {
643
- const target = resolve(dirname(resolvedPath), readlinkSync.call(this, resolvedPath, options).toString());
644
- real = cache.paths.get(((this === null || this === void 0 ? void 0 : this.root) || '') + target) || realpathSync.call(this, target);
645
- cache.paths.set(ctx_path, real);
641
+ const stats = resolved.fs.statSync(resolved.path);
642
+ if (!stats.isSymbolicLink()) {
643
+ return { ...resolved, fullPath: path, stats };
646
644
  }
647
- cache.paths.set(path, real);
648
- return real;
645
+ const target = resolve(dirname(path), readlinkSync.call($, path).toString());
646
+ return _resolveSync($, target);
649
647
  }
650
648
  catch {
651
649
  // Go the long way
652
650
  }
653
651
  const { base, dir } = parse(path);
654
- const realDir = dir == '/' ? '/' : cache.paths.get(((this === null || this === void 0 ? void 0 : this.root) || '') + dir) || realpathSync.call(this, dir);
655
- const lpath = join(realDir, base);
656
- const { fs, path: resolvedPath } = resolveMount(lpath, this);
652
+ const realDir = dir == '/' ? '/' : realpathSync.call($, dir);
653
+ const maybePath = join(realDir, base);
654
+ const resolved = resolveMount(maybePath, $);
657
655
  try {
658
- const stats = cache.stats.get(lpath) || fs.statSync(resolvedPath);
659
- cache.stats.set(lpath, stats);
656
+ const stats = resolved.fs.statSync(resolved.path);
660
657
  if (!stats.isSymbolicLink()) {
661
- cache.paths.set(path, lpath);
662
- return lpath;
658
+ return { ...resolved, fullPath: maybePath, stats };
663
659
  }
664
- const target = resolve(realDir, readlinkSync.call(this, lpath, options).toString());
665
- const real = cache.paths.get(((this === null || this === void 0 ? void 0 : this.root) || '') + target) || realpathSync.call(this, target);
666
- cache.paths.set(ctx_path, real);
667
- return real;
660
+ const target = resolve(realDir, readlinkSync.call($, maybePath).toString());
661
+ return _resolveSync($, target);
668
662
  }
669
663
  catch (e) {
670
664
  if (e.code == 'ENOENT') {
671
- return path;
665
+ return { ...resolved, fullPath: path };
672
666
  }
673
- throw fixError(e, { [resolvedPath]: lpath });
667
+ throw fixError(e, { [resolved.path]: maybePath });
674
668
  }
675
669
  }
670
+ export function realpathSync(path, options) {
671
+ var _a;
672
+ const encoding = typeof options == 'string' ? options : ((_a = options === null || options === void 0 ? void 0 : options.encoding) !== null && _a !== void 0 ? _a : 'utf8');
673
+ path = normalizePath(path);
674
+ const { fullPath } = _resolveSync(this, path);
675
+ if (encoding == 'utf8' || encoding == 'utf-8')
676
+ return fullPath;
677
+ const buf = Buffer.from(fullPath, 'utf-8');
678
+ if (encoding == 'buffer')
679
+ return buf;
680
+ return buf.toString(encoding);
681
+ }
676
682
  realpathSync;
677
683
  export function accessSync(path, mode = 0o600) {
678
684
  if (!config.checkAccess)
@@ -690,21 +696,19 @@ export function rmSync(path, options) {
690
696
  path = normalizePath(path);
691
697
  let stats;
692
698
  try {
693
- stats = cache.stats.get(path) || lstatSync.bind(this)(path);
699
+ stats = lstatSync.bind(this)(path);
694
700
  }
695
701
  catch (error) {
696
702
  if (error.code != 'ENOENT' || !(options === null || options === void 0 ? void 0 : options.force))
697
703
  throw error;
698
704
  }
699
- if (!stats) {
705
+ if (!stats)
700
706
  return;
701
- }
702
- cache.stats.set(path, stats);
703
707
  switch (stats.mode & constants.S_IFMT) {
704
708
  case constants.S_IFDIR:
705
709
  if (options === null || options === void 0 ? void 0 : options.recursive) {
706
- for (const entry of readdirSync.call(this, path, { _isIndirect: true })) {
707
- rmSync.call(this, join(path, entry), { ...options, _isIndirect: true });
710
+ for (const entry of readdirSync.call(this, path)) {
711
+ rmSync.call(this, join(path, entry), options);
708
712
  }
709
713
  }
710
714
  rmdirSync.call(this, path);
@@ -718,12 +722,8 @@ export function rmSync(path, options) {
718
722
  case constants.S_IFIFO:
719
723
  case constants.S_IFSOCK:
720
724
  default:
721
- cache.stats.clear();
722
725
  throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
723
726
  }
724
- if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
725
- cache.stats.clear();
726
- }
727
727
  }
728
728
  rmSync;
729
729
  export function mkdtempSync(prefix, options) {
@@ -1,17 +1,5 @@
1
1
  import type * as fs from 'node:fs';
2
2
  export type FileContents = ArrayBufferView | string;
3
- /**
4
- * Options used for caching, among other things.
5
- * @internal @hidden *UNSTABLE*
6
- */
7
- export interface InternalOptions {
8
- /**
9
- * If true, then this readdir was called from another function.
10
- * In this case, don't clear the cache when done.
11
- * @internal *UNSTABLE*
12
- */
13
- _isIndirect?: boolean;
14
- }
15
3
  /**
16
4
  * @internal @hidden Used for the internal `_open` functions
17
5
  */
@@ -27,7 +15,7 @@ export interface OpenOptions {
27
15
  */
28
16
  allowDirectory?: boolean;
29
17
  }
30
- export interface ReaddirOptions extends InternalOptions {
18
+ export interface ReaddirOptions {
31
19
  withFileTypes?: boolean;
32
20
  recursive?: boolean;
33
21
  }