这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions benches/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,5 +716,33 @@ mod memory_fs {
))
})
}

fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
// Follow symlinks to resolve the canonical path
let mut current = path.to_path_buf();
let mut visited = FxHashSet::default();

while let Some(target) = self.symlinks.get(&current) {
if !visited.insert(current.clone()) {
return Err(io::Error::other("Circular symlink"));
}

current = if target.is_relative() {
current.parent().unwrap().join(target)
} else {
target.clone()
};
}

// Verify the final path exists
if self.files.contains_key(&current) || self.directories.contains(&current) {
Ok(current)
} else {
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Path not found: {}", path.display()),
))
}
}
}
}
13 changes: 10 additions & 3 deletions src/cache/cache_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,16 @@ impl<Fs: FileSystem> Cache<Fs> {
});

result.as_ref().map_err(Clone::clone).and_then(|weak| {
weak.upgrade().map(CachedPath).ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "Path no longer exists").into()
})
weak.upgrade()
.map(CachedPath)
.or_else(|| {
// Cache was cleared while canonicalizing. Fall back to direct FS canonicalize
// without caching the result to ensure we still return the resolved path.
self.fs.canonicalize(path.path()).ok().map(|canonical| self.value(&canonical))
})
.ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "Path no longer exists").into()
})
})
}

Expand Down
30 changes: 30 additions & 0 deletions src/file_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ pub trait FileSystem: Send + Sync {
///
/// See [std::fs::read_link]
fn read_link(&self, path: &Path) -> Result<PathBuf, ResolveError>;

/// Returns the canonical, absolute form of a path with all intermediate components normalized.
///
/// # Errors
///
/// See [std::fs::canonicalize]
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
}

/// Metadata information about a file
Expand Down Expand Up @@ -208,6 +215,14 @@ impl FileSystemOs {
}
}
}

/// # Errors
///
/// See [std::fs::canonicalize]
#[inline]
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
fs::canonicalize(path)
}
}

impl FileSystem for FileSystemOs {
Expand Down Expand Up @@ -281,6 +296,21 @@ impl FileSystem for FileSystemOs {
}
Self::read_link(path)
}

fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
cfg_if! {
if #[cfg(feature = "yarn_pnp")] {
if self.yarn_pnp {
return match VPath::from(path)? {
VPath::Zip(info) => Self::canonicalize(&info.physical_base_path().join(info.zip_path)),
VPath::Virtual(info) => Self::canonicalize(&info.physical_base_path()),
VPath::Native(path) => Self::canonicalize(&path),
}
}
}
}
Self::canonicalize(path)
}
}

#[test]
Expand Down
9 changes: 9 additions & 0 deletions src/tests/memory_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,13 @@ impl FileSystem for MemoryFS {
fn read_link(&self, _path: &Path) -> Result<PathBuf, ResolveError> {
Err(io::Error::new(io::ErrorKind::NotFound, "not a symlink").into())
}

fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
// MemoryFS doesn't support symlinks, so just verify path exists and return it
use vfs::FileSystem;
self.fs
.metadata(path.to_string_lossy().as_ref())
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err))?;
Ok(path.to_path_buf())
}
}