diff --git a/Cargo.lock b/Cargo.lock index 6dcf882..dede4b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.18" @@ -166,6 +168,7 @@ dependencies = [ "lazy_static", "libc", "lscolors", + "normpath", "num_cpus", "regex", "regex-syntax", @@ -330,6 +333,15 @@ dependencies = [ "libc", ] +[[package]] +name = "normpath" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e6e8f70e9fbbe3752d330d769e3424f24b9458ce266df93a3b456902fd696a" +dependencies = [ + "winapi", +] + [[package]] name = "num_cpus" version = "1.13.0" diff --git a/Cargo.toml b/Cargo.toml index 7c93224..a4d479d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ lscolors = "0.7" globset = "0.4" anyhow = "1.0" dirs-next = "2.0" +normpath = "0.3" [dependencies.clap] version = "2.31.2" diff --git a/src/filesystem.rs b/src/filesystem.rs index 19fc0e6..6680ae5 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -7,6 +7,8 @@ use std::io; use std::os::unix::fs::{FileTypeExt, PermissionsExt}; use std::path::{Path, PathBuf}; +use normpath::PathExt; + use crate::walk; pub fn path_absolute_form(path: &Path) -> io::Result { @@ -33,10 +35,10 @@ pub fn absolute_path(path: &Path) -> io::Result { Ok(path_buf) } -// Path::is_dir() is not guaranteed to be intuitively correct for "." and ".." -// See: https://github.com/rust-lang/rust/issues/45302 -pub fn is_dir(path: &Path) -> bool { - path.is_dir() && (path.file_name().is_some() || path.canonicalize().is_ok()) +pub fn is_existing_directory(path: &Path) -> bool { + // Note: we do not use `.exists()` here, as `.` always exists, even if + // the CWD has been deleted. + path.is_dir() && (path.file_name().is_some() || path.normalize().is_ok()) } #[cfg(any(unix, target_os = "redox"))] diff --git a/src/main.rs b/src/main.rs index 8a315a0..5221d95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ fn run() -> Result { // Set the current working directory of the process if let Some(base_directory) = matches.value_of_os("base-directory") { let base_directory = Path::new(base_directory); - if !filesystem::is_dir(base_directory) { + if !filesystem::is_existing_directory(base_directory) { return Err(anyhow!( "The '--base-directory' path '{}' is not a directory.", base_directory.to_string_lossy() @@ -70,7 +70,7 @@ fn run() -> Result { } let current_directory = Path::new("."); - if !filesystem::is_dir(current_directory) { + if !filesystem::is_existing_directory(current_directory) { return Err(anyhow!( "Could not retrieve current directory (has it been deleted?)." )); @@ -95,7 +95,7 @@ fn run() -> Result { let mut directories = vec![]; for path in paths { let path_buffer = PathBuf::from(path); - if filesystem::is_dir(&path_buffer) { + if filesystem::is_existing_directory(&path_buffer) { directories.push(path_buffer); } else { print_error(format!( @@ -130,7 +130,7 @@ fn run() -> Result { // Detect if the user accidentally supplied a path instead of a search pattern if !matches.is_present("full-path") && pattern.contains(std::path::MAIN_SEPARATOR) - && filesystem::is_dir(Path::new(pattern)) + && Path::new(pattern).is_dir() { return Err(anyhow!( "The search pattern '{pattern}' contains a path-separation character ('{sep}') \