Skip to content

Commit

Permalink
perf: use custom canonicalize impl to avoid heavy syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Jul 9, 2024
1 parent a94a984 commit 1a6a707
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 36 deletions.
19 changes: 2 additions & 17 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ pub struct CachedPathImpl {
path: Box<Path>,
parent: Option<CachedPath>,
meta: OnceLock<Option<FileMetadata>>,
symlink: OnceLock<Option<PathBuf>>,
canonicalized: OnceLock<Option<PathBuf>>,
node_modules: OnceLock<Option<CachedPath>>,
package_json: OnceLock<Option<Arc<PackageJson>>>,
Expand All @@ -147,7 +146,6 @@ impl CachedPathImpl {
path,
parent,
meta: OnceLock::new(),
symlink: OnceLock::new(),
canonicalized: OnceLock::new(),
node_modules: OnceLock::new(),
package_json: OnceLock::new(),
Expand Down Expand Up @@ -190,24 +188,11 @@ impl CachedPathImpl {
)
}

fn symlink<Fs: FileSystem>(&self, fs: &Fs) -> io::Result<Option<PathBuf>> {
self.symlink
.get_or_try_init(|| {
if let Ok(symlink_metadata) = fs.symlink_metadata(&self.path) {
if symlink_metadata.is_symlink {
return fs.canonicalize(self.path()).map(Some);
}
}
Ok(None)
})
.cloned()
}

pub fn realpath<Fs: FileSystem>(&self, fs: &Fs) -> io::Result<PathBuf> {
self.canonicalized
.get_or_try_init(|| {
if let Some(link) = self.symlink(fs)? {
return Ok(Some(link));
if fs.symlink_metadata(&self.path).map(|m| m.is_symlink).unwrap_or_default() {
return fs.canonicalize(&self.path).map(Some);
}
if let Some(parent) = self.parent() {
let parent_path = parent.realpath(fs)?;
Expand Down
41 changes: 22 additions & 19 deletions src/file_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,33 +91,36 @@ impl FileSystem for FileSystemOs {
}

fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
#[cfg(not(target_os = "wasi"))]
#[cfg(target_os = "windows")]
{
dunce::canonicalize(path)
}
#[cfg(target_os = "wasi")]
#[cfg(not(target_os = "windows"))]
{
let meta = fs::symlink_metadata(path)?;
if meta.file_type().is_symlink() {
let link = fs::read_link(path)?;
let mut path_buf = path.to_path_buf();
path_buf.pop();
for segment in link.iter() {
match segment.to_str() {
Some("..") => {
path_buf.pop();
}
Some(".") | None => {}
Some(seg) => {
// Need to trim the extra \0 introduces by rust std rust-lang/rust#123727
path_buf.push(seg.trim_end_matches('\0'));
let mut path_buf = path.to_path_buf();
let mut is_symlink = true;
loop {
if is_symlink {
let link = fs::read_link(&path_buf)?;
path_buf.pop();
for segment in &link {
match segment.to_str() {
Some("..") => {
path_buf.pop();
}
Some(".") | None => {}
Some(seg) => {
// Need to trim the extra \0 introduces by rust std rust-lang/rust#123727
path_buf.push(seg.trim_end_matches('\0'));
}
}
}
is_symlink = fs::symlink_metadata(&path_buf)?.is_symlink();
} else {
break;
}
Ok(path_buf)
} else {
Ok(path.to_path_buf())
}
Ok(path_buf)
}
}
}
Expand Down

0 comments on commit 1a6a707

Please sign in to comment.