Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/walkdir.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2018-11-11 17:14:27 +0300
committerAndrew Gallant <jamslam@gmail.com>2018-11-11 17:32:29 +0300
commit83b7a2430216cdc99348f4ec0b02f84a4eeed35f (patch)
tree7704e7ca531997a0902393d9545fb11521ce7384 /src/tests.rs
parent4879ce266a81d95ceea1ff40c1a69387265b9043 (diff)
walkdir: fix root symlink bug
This commit fixes a nasty bug where the root path given to walkdir was always reported as a symlink, even when 'follow_links' was enabled. This appears to be a regression introduced by commit 6f72fce as part of fixing BurntSushi/ripgrep#984. The central problem was that since root paths should always be followed, we were creating a DirEntry whose internal file type was always resolved by following a symlink, but whose 'metadata' method still returned the metadata of the symlink and not the target. This was problematic and inconsistent both with and without 'follow_links' enabled. We also fix the documentation. In particular, we make the docs of 'new' more unambiguous, where it previously could have been interpreted as contradictory to the docs on 'DirEntry'. Specifically, 'WalkDir::new' says: If root is a symlink, then it is always followed. But the docs for 'DirEntry::metadata' say This always calls std::fs::symlink_metadata. If this entry is a symbolic link and follow_links is enabled, then std::fs::metadata is called instead. Similarly, 'DirEntry::file_type' said If this is a symbolic link and follow_links is true, then this returns the type of the target. That is, if 'root' is a symlink and 'follow_links' is NOT enabled, then the previous incorrect behavior resulted in 'DirEntry::file_type' behaving as if 'follow_links' was enabled. If 'follow_links' was enabled, then the previous incorrect behavior resulted in 'DirEntry::metadata' reporting the metadata of the symlink itself. We fix this by correctly constructing the DirEntry in the first place, and then adding special case logic to path traversal that will always attempt to follow the root path if it's a symlink and 'follow_links' was not enabled. We also tweak the docs on 'WalkDir::new' to be more precise. Fixes #115
Diffstat (limited to 'src/tests.rs')
-rw-r--r--src/tests.rs45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/tests.rs b/src/tests.rs
index 1fb7682..ddce795 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -531,6 +531,51 @@ fn first_path_not_symlink() {
assert!(!dents[0].path_is_symlink());
}
+// Like first_path_not_symlink, but checks that the first path is not reported
+// as a symlink even when we are supposed to be following them.
+#[test]
+#[cfg(unix)]
+fn first_path_not_symlink_follow() {
+ let exp = td("foo", vec![]);
+ let (tmp, _got) = dir_setup(&exp);
+
+ let dents = WalkDir::new(tmp.path().join("foo"))
+ .follow_links(true)
+ .into_iter()
+ .collect::<Result<Vec<_>, _>>()
+ .unwrap();
+ assert_eq!(1, dents.len());
+ assert!(!dents[0].path_is_symlink());
+}
+
+// See: https://github.com/BurntSushi/walkdir/issues/115
+#[test]
+#[cfg(unix)]
+fn first_path_is_followed() {
+ let exp = td("foo", vec![
+ td("a", vec![tf("a1"), tf("a2")]),
+ td("b", vec![tlf("../a/a1", "alink")]),
+ ]);
+ let (tmp, _got) = dir_setup(&exp);
+
+ let dents = WalkDir::new(tmp.path().join("foo/b/alink"))
+ .into_iter()
+ .collect::<Result<Vec<_>, _>>()
+ .unwrap();
+ assert_eq!(1, dents.len());
+ assert!(dents[0].file_type().is_symlink());
+ assert!(dents[0].metadata().unwrap().file_type().is_symlink());
+
+ let dents = WalkDir::new(tmp.path().join("foo/b/alink"))
+ .follow_links(true)
+ .into_iter()
+ .collect::<Result<Vec<_>, _>>()
+ .unwrap();
+ assert_eq!(1, dents.len());
+ assert!(!dents[0].file_type().is_symlink());
+ assert!(!dents[0].metadata().unwrap().file_type().is_symlink());
+}
+
#[test]
#[cfg(unix)]
fn walk_dir_sym_detect_no_follow_no_loop() {