From 6f72fce4315cb13f2ceb6903910a52852a12ba0b Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 21 Aug 2018 21:41:48 -0400 Subject: path_is_symlink: fix false positive This commit fixes a bug where the first path always reported itself as as symlink via `path_is_symlink`. Partially fixes https://github.com/BurntSushi/ripgrep/issues/984 --- src/lib.rs | 22 +++++++++++++--------- src/tests.rs | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0180818..58fc2e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -623,7 +623,7 @@ pub struct DirEntry { /// The file type. Necessary for recursive iteration, so store it. ty: FileType, /// Is set when this entry was created from a symbolic link and the user - /// excepts the iterator to follow symbolic links. + /// expects the iterator to follow symbolic links. follow_link: bool, /// The depth at which this entry was generated relative to the root. depth: usize, @@ -650,7 +650,7 @@ impl Iterator for IntoIter { /// an error value. The error will be wrapped in an Option::Some. fn next(&mut self) -> Option> { if let Some(start) = self.start.take() { - let dent = itry!(DirEntry::from_link(0, start)); + let dent = itry!(DirEntry::from_path(0, start, false)); if let Some(result) = self.handle_entry(dent) { return Some(result); } @@ -885,7 +885,11 @@ impl IntoIter { } fn follow(&self, mut dent: DirEntry) -> Result { - dent = DirEntry::from_link(self.depth, dent.path().to_path_buf())?; + dent = DirEntry::from_path( + self.depth, + dent.path().to_path_buf(), + true, + )?; // The only way a symlink can cause a loop is if it points // to a directory. Otherwise, it always points to a leaf // and we can omit any loop checks. @@ -1119,21 +1123,21 @@ impl DirEntry { } #[cfg(windows)] - fn from_link(depth: usize, pb: PathBuf) -> Result { + fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result { let md = fs::metadata(&pb).map_err(|err| { Error::from_path(depth, pb.clone(), err) })?; Ok(DirEntry { path: pb, ty: md.file_type(), - follow_link: true, + follow_link: link, depth: depth, metadata: md, }) } #[cfg(unix)] - fn from_link(depth: usize, pb: PathBuf) -> Result { + fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result { use std::os::unix::fs::MetadataExt; let md = fs::metadata(&pb).map_err(|err| { @@ -1142,21 +1146,21 @@ impl DirEntry { Ok(DirEntry { path: pb, ty: md.file_type(), - follow_link: true, + follow_link: link, depth: depth, ino: md.ino(), }) } #[cfg(not(any(unix, windows)))] - fn from_link(depth: usize, pb: PathBuf) -> Result { + fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result { let md = fs::metadata(&pb).map_err(|err| { Error::from_path(depth, pb.clone(), err) })?; Ok(DirEntry { path: pb, ty: md.file_type(), - follow_link: true, + follow_link: link, depth: depth, }) } diff --git a/src/tests.rs b/src/tests.rs index be2f89b..8847323 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -516,6 +516,21 @@ fn walk_dir_sym_root() { assert_eq!(got, vec!["foo/alink/", "foo/alink/a", "foo/alink/b"]); } +// See: https://github.com/BurntSushi/ripgrep/issues/984 +#[test] +#[cfg(unix)] +fn first_path_not_symlink() { + let exp = td("foo", vec![]); + let (tmp, _got) = dir_setup(&exp); + + let dents = WalkDir::new(tmp.path().join("foo")) + .into_iter() + .collect::, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); +} + #[test] #[cfg(unix)] fn walk_dir_sym_detect_no_follow_no_loop() { -- cgit v1.2.3