From 373278952ff96fd01287c6ac89f1bf4b74c6490d Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Mon, 5 Dec 2016 19:53:43 -0500 Subject: [PATCH] Fix bug reading root symlink. When given a root like `foo` where `foo` is a symlink, it should always be followed. This behavior is consistent with `foo/`, which will also be followed. See also: https://github.com/BurntSushi/ripgrep/issues/256 --- src/lib.rs | 17 +++-------------- src/tests.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d74867c..221ae7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,7 +198,8 @@ impl WalkDir { /// Create a builder for a recursive directory iterator starting at the /// file path `root`. If `root` is a directory, then it is the first item /// yielded by the iterator. If `root` is a file, then it is the first - /// and only item yielded by the iterator. + /// and only item yielded by the iterator. If `root` is a symlink, then it + /// is always followed. pub fn new>(root: P) -> Self { WalkDir { opts: WalkDirOptions { @@ -495,7 +496,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option> { if let Some(start) = self.start.take() { - let dent = itry!(DirEntry::from_path(0, start)); + let dent = itry!(DirEntry::from_link(0, start)); if let Some(result) = self.handle_entry(dent) { return Some(result); } @@ -745,18 +746,6 @@ impl DirEntry { depth: depth, }) } - - fn from_path(depth: usize, pb: PathBuf) -> Result { - let md = try!(fs::symlink_metadata(&pb).map_err(|err| { - Error::from_path(depth, pb.clone(), err) - })); - Ok(DirEntry { - path: pb, - ty: md.file_type(), - follow_link: false, - depth: depth, - }) - } } impl Clone for DirEntry { diff --git a/src/tests.rs b/src/tests.rs index 5b43f27..e3f1c4e 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -416,6 +416,33 @@ fn walk_dir_sym_2() { assert_tree_eq!(exp, got); } +#[test] +#[cfg(unix)] +fn walk_dir_root_sym() { + let exp = td("foo", vec![ + td("bar", vec![tf("a"), tf("b")]), + tl("bar", "alink"), + ]); + let tmp = tmpdir(); + let tmp_path = tmp.path(); + let tmp_len = tmp_path.to_str().unwrap().len(); + exp.create_in(tmp_path).unwrap(); + + let it = WalkDir::new(tmp_path.join("foo/alink")).into_iter(); + let mut got = it + .map(|d| d.unwrap().path().to_str().unwrap()[tmp_len+1..].into()) + .collect::>(); + got.sort(); + assert_eq!(got, vec!["foo/alink", "foo/alink/a", "foo/alink/b"]); + + let it = WalkDir::new(tmp_path.join("foo/alink/")).into_iter(); + let mut got = it + .map(|d| d.unwrap().path().to_str().unwrap()[tmp_len+1..].into()) + .collect::>(); + got.sort(); + assert_eq!(got, vec!["foo/alink/", "foo/alink/a", "foo/alink/b"]); +} + #[test] #[cfg(unix)] fn walk_dir_sym_detect_no_follow_no_loop() {