samefile: Cache FileInformation for the target (#409)

And don't follow symlinks.
This commit is contained in:
Tavian Barnes
2024-06-28 03:53:52 -04:00
committed by GitHub
parent f145469cfd
commit fd54f9f72a
3 changed files with 21 additions and 18 deletions
+3 -9
View File
@@ -540,16 +540,10 @@ fn build_matcher_tree(
if i >= args.len() - 1 {
return Err(From::from(format!("missing argument to {}", args[i])));
}
let path = Path::new(args[i + 1]).to_path_buf();
// check if path is not found
if !path.exists() {
return Err(From::from(format!(
"{}: No such file or directory",
args[i + 1]
)));
}
i += 1;
Some(SameFileMatcher::new(path).into_box())
let path = args[i];
let matcher = SameFileMatcher::new(path).map_err(|e| format!("{path}: {e}"))?;
Some(matcher.into_box())
}
"-user" => {
if i >= args.len() - 1 {
+16 -7
View File
@@ -3,23 +3,29 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use std::path::PathBuf;
use super::Matcher;
use std::error::Error;
use std::path::Path;
use uucore::fs::FileInformation;
pub struct SameFileMatcher {
path: PathBuf,
info: FileInformation,
}
impl SameFileMatcher {
pub fn new(path: PathBuf) -> SameFileMatcher {
SameFileMatcher { path }
pub fn new(path: impl AsRef<Path>) -> Result<Self, Box<dyn Error>> {
let info = FileInformation::from_path(path, false)?;
Ok(Self { info })
}
}
impl Matcher for SameFileMatcher {
fn matches(&self, file_info: &walkdir::DirEntry, _matcher_io: &mut super::MatcherIO) -> bool {
uucore::fs::paths_refer_to_same_file(file_info.path(), &self.path, true)
if let Ok(info) = FileInformation::from_path(file_info.path(), false) {
info == self.info
} else {
false
}
}
}
@@ -38,11 +44,14 @@ mod tests {
// But you can't delete a file that doesn't exist,
// so ignore the error returned here.
let _ = fs::remove_file("test_data/links/hard_link");
assert!(SameFileMatcher::new("test_data/links/hard_link").is_err());
fs::hard_link("test_data/links/abbbc", "test_data/links/hard_link").unwrap();
let file = get_dir_entry_for("test_data/links", "abbbc");
let hard_link_file = get_dir_entry_for("test_data/links", "hard_link");
let matcher = SameFileMatcher::new(file.into_path());
let matcher = SameFileMatcher::new(file.into_path()).unwrap();
let deps = FakeDependencies::new();
assert!(matcher.matches(&hard_link_file, &mut deps.new_matcher_io()));
+2 -2
View File
@@ -878,6 +878,6 @@ fn find_samefile() {
.args([".", "-samefile", "./test_data/links/not-exist-file"])
.assert()
.failure()
.stdout(predicate::str::contains(""))
.stderr(predicate::str::contains("No such file or directory"));
.stdout(predicate::str::is_empty())
.stderr(predicate::str::contains("not-exist-file"));
}