mirror of
https://github.com/BurntSushi/walkdir.git
synced 2025-09-28 14:10:31 +00:00
api: add follow_root_links() option to WalkDir
With it it's possible to control whether symlinks in the traversal root are followed, while defaulting to 'true' like before, or if they are handled like ordinary links. Ref https://github.com/rust-lang/cargo/pull/11634 Fixes #175
This commit is contained in:
parent
61a185fe49
commit
dcc527d832
27
src/lib.rs
27
src/lib.rs
@ -237,6 +237,7 @@ pub struct WalkDir {
|
||||
|
||||
struct WalkDirOptions {
|
||||
follow_links: bool,
|
||||
follow_root_links: bool,
|
||||
max_open: usize,
|
||||
min_depth: usize,
|
||||
max_depth: usize,
|
||||
@ -265,6 +266,7 @@ impl fmt::Debug for WalkDirOptions {
|
||||
};
|
||||
f.debug_struct("WalkDirOptions")
|
||||
.field("follow_links", &self.follow_links)
|
||||
.field("follow_root_link", &self.follow_root_links)
|
||||
.field("max_open", &self.max_open)
|
||||
.field("min_depth", &self.min_depth)
|
||||
.field("max_depth", &self.max_depth)
|
||||
@ -287,6 +289,7 @@ impl WalkDir {
|
||||
WalkDir {
|
||||
opts: WalkDirOptions {
|
||||
follow_links: false,
|
||||
follow_root_links: true,
|
||||
max_open: 10,
|
||||
min_depth: 0,
|
||||
max_depth: ::std::usize::MAX,
|
||||
@ -344,6 +347,25 @@ impl WalkDir {
|
||||
self
|
||||
}
|
||||
|
||||
/// Follow symbolic links if these are the root of the traversal.
|
||||
/// By default, this is enabled.
|
||||
///
|
||||
/// When `yes` is `true`, symbolic links on root paths are followed
|
||||
/// which is effective if the symbolic link points to a directory.
|
||||
/// If a symbolic link is broken or is involved in a loop, an error is yielded
|
||||
/// as the first entry of the traversal.
|
||||
///
|
||||
/// When enabled, the yielded [`DirEntry`] values represent the target of
|
||||
/// the link while the path corresponds to the link. See the [`DirEntry`]
|
||||
/// type for more details, and all future entries will be contained within
|
||||
/// the resolved directory behind the symbolic link of the root path.
|
||||
///
|
||||
/// [`DirEntry`]: struct.DirEntry.html
|
||||
pub fn follow_root_links(mut self, yes: bool) -> Self {
|
||||
self.opts.follow_root_links = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the maximum number of simultaneously open file descriptors used
|
||||
/// by the iterator.
|
||||
///
|
||||
@ -830,7 +852,10 @@ impl IntoIter {
|
||||
} else {
|
||||
itry!(self.push(&dent));
|
||||
}
|
||||
} else if dent.depth() == 0 && dent.file_type().is_symlink() {
|
||||
} else if dent.depth() == 0
|
||||
&& dent.file_type().is_symlink()
|
||||
&& self.opts.follow_root_links
|
||||
{
|
||||
// As a special case, if we are processing a root entry, then we
|
||||
// always follow it even if it's a symlink and follow_links is
|
||||
// false. We are careful to not let this change the semantics of
|
||||
|
@ -383,7 +383,76 @@ fn sym_root_file_follow() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sym_root_dir_nofollow() {
|
||||
fn broken_sym_root_dir_nofollow_and_root_nofollow() {
|
||||
let dir = Dir::tmp();
|
||||
dir.symlink_dir("broken", "a-link");
|
||||
|
||||
let wd = WalkDir::new(dir.join("a-link"))
|
||||
.follow_links(false)
|
||||
.follow_root_links(false);
|
||||
let r = dir.run_recursive(wd);
|
||||
let ents = r.sorted_ents();
|
||||
assert_eq!(ents.len(), 1);
|
||||
let link = &ents[0];
|
||||
assert_eq!(dir.join("a-link"), link.path());
|
||||
assert!(link.path_is_symlink());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn broken_sym_root_dir_follow_and_root_nofollow() {
|
||||
let dir = Dir::tmp();
|
||||
dir.symlink_dir("broken", "a-link");
|
||||
|
||||
let wd = WalkDir::new(dir.join("a-link"))
|
||||
.follow_links(true)
|
||||
.follow_root_links(false);
|
||||
let r = dir.run_recursive(wd);
|
||||
assert!(r.sorted_ents().is_empty());
|
||||
assert_eq!(
|
||||
r.errs().len(),
|
||||
1,
|
||||
"broken symlink cannot be traversed - they are followed if symlinks are followed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn broken_sym_root_dir_root_is_always_followed() {
|
||||
let dir = Dir::tmp();
|
||||
dir.symlink_dir("broken", "a-link");
|
||||
|
||||
for follow_symlinks in &[true, false] {
|
||||
let wd =
|
||||
WalkDir::new(dir.join("a-link")).follow_links(*follow_symlinks);
|
||||
let r = dir.run_recursive(wd);
|
||||
assert!(r.sorted_ents().is_empty());
|
||||
assert_eq!(
|
||||
r.errs().len(),
|
||||
1,
|
||||
"broken symlink in roots cannot be traversed, they are always followed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sym_root_dir_nofollow_root_nofollow() {
|
||||
let dir = Dir::tmp();
|
||||
dir.mkdirp("a");
|
||||
dir.symlink_dir("a", "a-link");
|
||||
dir.touch("a/zzz");
|
||||
|
||||
let wd = WalkDir::new(dir.join("a-link")).follow_root_links(false);
|
||||
let r = dir.run_recursive(wd);
|
||||
r.assert_no_errors();
|
||||
|
||||
let ents = r.sorted_ents();
|
||||
assert_eq!(1, ents.len());
|
||||
let link = &ents[0];
|
||||
assert_eq!(dir.join("a-link"), link.path());
|
||||
assert_eq!(0, link.depth());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sym_root_dir_nofollow_root_follow() {
|
||||
let dir = Dir::tmp();
|
||||
dir.mkdirp("a");
|
||||
dir.symlink_dir("a", "a-link");
|
||||
|
Loading…
x
Reference in New Issue
Block a user