From 76515bacd9abdcd740736ac0272226112c73ba57 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Wed, 20 Sep 2017 08:51:36 +0200 Subject: [PATCH] Add an option to not follow symlinks Add `follow_links` option in `MatchOptions` struct to signalize when to follow symlinks when the directory is traversed. The default value is `false`. --- src/lib.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b5a31e6..6ef6d3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ //! case_sensitive: false, //! require_literal_separator: false, //! require_literal_leading_dot: false, +//! follow_links: false, //! }; //! for entry in glob_with("local/*a*", &options).unwrap() { //! if let Ok(path) = entry { @@ -299,8 +300,13 @@ impl fmt::Display for GlobError { } } -fn is_dir(p: &Path) -> bool { - fs::metadata(p).map(|m| m.is_dir()).unwrap_or(false) +fn is_dir(p: &Path, follow_links: bool) -> bool { + let metadata = if follow_links { + fs::metadata(p) + } else { + fs::symlink_metadata(p) + }; + metadata.map(|m| m.is_dir()).unwrap_or(false) } /// An alias for a glob iteration result. @@ -343,7 +349,8 @@ impl Iterator for Paths { // idx -1: was already checked by fill_todo, maybe path was '.' or // '..' that we can't match here because of normalization. if idx == !0 as usize { - if self.require_dir && !is_dir(&path) { + if self.require_dir && !is_dir(&path, + self.options.follow_links) { continue; } return Some(Ok(path)); @@ -358,7 +365,7 @@ impl Iterator for Paths { next += 1; } - if is_dir(&path) { + if is_dir(&path, self.options.follow_links) { // the path is a directory, so it's a match // push this directory's contents @@ -401,7 +408,8 @@ impl Iterator for Paths { // *AND* its children so we don't need to check the // children - if !self.require_dir || is_dir(&path) { + if !self.require_dir || is_dir(&path, + self.options.follow_links) { return Some(Ok(path)); } } else { @@ -804,7 +812,7 @@ fn fill_todo(todo: &mut Vec>, }; let pattern = &patterns[idx]; - let is_dir = is_dir(path); + let is_dir = is_dir(path, options.follow_links); let curdir = path == Path::new("."); match pattern_as_str(pattern) { Some(s) => { @@ -957,6 +965,10 @@ pub struct MatchOptions { /// conventionally considered hidden on Unix systems and it might be /// desirable to skip them when listing files. pub require_literal_leading_dot: bool, + + /// Whether ot not paths that are symbolic links are followed + /// during the walk. + pub follow_links: bool, } impl MatchOptions { @@ -970,7 +982,8 @@ impl MatchOptions { /// MatchOptions { /// case_sensitive: true, /// require_literal_separator: false, - /// require_literal_leading_dot: false + /// require_literal_leading_dot: false, + /// follow_links: false, /// } /// ``` pub fn new() -> MatchOptions { @@ -978,6 +991,7 @@ impl MatchOptions { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, } } } @@ -1219,6 +1233,7 @@ mod test { case_sensitive: false, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, }; assert!(pat.matches_with("aBcDeFg", &options)); @@ -1237,11 +1252,13 @@ mod test { case_sensitive: false, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, }; let options_case_sensitive = MatchOptions { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, }; assert!(pat_within.matches_with("a", &options_case_insensitive)); @@ -1260,11 +1277,13 @@ mod test { case_sensitive: true, require_literal_separator: true, require_literal_leading_dot: false, + follow_links: false, }; let options_not_require_literal = MatchOptions { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, }; assert!(Pattern::new("abc/def").unwrap().matches_with("abc/def", &options_require_literal)); @@ -1299,11 +1318,13 @@ mod test { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: true, + follow_links: false, }; let options_not_require_literal_leading_dot = MatchOptions { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: false, + follow_links: false, }; let f = |options| Pattern::new("*.txt").unwrap().matches_with(".hello.txt", options);