@@ -73,7 +73,9 @@ use std::cmp;
7373use std:: error:: Error ;
7474use std:: fmt;
7575use std:: fs;
76+ use std:: fs:: DirEntry ;
7677use std:: io;
78+ use std:: ops:: Deref ;
7779use std:: path:: { self , Component , Path , PathBuf } ;
7880use std:: str:: FromStr ;
7981
@@ -96,8 +98,8 @@ pub struct Paths {
9698 dir_patterns : Vec < Pattern > ,
9799 require_dir : bool ,
98100 options : MatchOptions ,
99- todo : Vec < Result < ( PathBuf , usize ) , GlobError > > ,
100- scope : Option < PathBuf > ,
101+ todo : Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
102+ scope : Option < PathWrapper > ,
101103}
102104
103105/// Return an iterator that produces all the `Path`s that match the given
@@ -242,6 +244,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
242244 }
243245
244246 let scope = root. map_or_else ( || PathBuf :: from ( "." ) , to_scope) ;
247+ let scope = PathWrapper :: from_path ( scope) ;
245248
246249 let mut dir_patterns = Vec :: new ( ) ;
247250 let components =
@@ -323,8 +326,52 @@ impl fmt::Display for GlobError {
323326 }
324327}
325328
326- fn is_dir ( p : & Path ) -> bool {
327- fs:: metadata ( p) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false )
329+ #[ derive( Debug ) ]
330+ struct PathWrapper {
331+ path : PathBuf ,
332+ is_directory : bool ,
333+ }
334+
335+ impl PathWrapper {
336+ fn from_dir_entry ( path : PathBuf , e : DirEntry ) -> Self {
337+ let is_directory = e
338+ . file_type ( )
339+ . ok ( )
340+ . and_then ( |file_type| {
341+ // We need to use fs::metadata to resolve the actual path
342+ // if it's a symlink.
343+ if file_type. is_symlink ( ) {
344+ None
345+ } else {
346+ Some ( file_type. is_dir ( ) )
347+ }
348+ } )
349+ . or_else ( || fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . ok ( ) )
350+ . unwrap_or ( false ) ;
351+ Self { path, is_directory }
352+ }
353+ fn from_path ( path : PathBuf ) -> Self {
354+ let is_directory = fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false ) ;
355+ Self { path, is_directory }
356+ }
357+
358+ fn into_path ( self ) -> PathBuf {
359+ self . path
360+ }
361+ }
362+
363+ impl Deref for PathWrapper {
364+ type Target = Path ;
365+
366+ fn deref ( & self ) -> & Self :: Target {
367+ self . path . deref ( )
368+ }
369+ }
370+
371+ impl AsRef < Path > for PathWrapper {
372+ fn as_ref ( & self ) -> & Path {
373+ self . path . as_ref ( )
374+ }
328375}
329376
330377/// An alias for a glob iteration result.
@@ -363,10 +410,10 @@ impl Iterator for Paths {
363410 // idx -1: was already checked by fill_todo, maybe path was '.' or
364411 // '..' that we can't match here because of normalization.
365412 if idx == !0 as usize {
366- if self . require_dir && !is_dir ( & path) {
413+ if self . require_dir && !path. is_directory {
367414 continue ;
368415 }
369- return Some ( Ok ( path) ) ;
416+ return Some ( Ok ( path. into_path ( ) ) ) ;
370417 }
371418
372419 if self . dir_patterns [ idx] . is_recursive {
@@ -379,7 +426,7 @@ impl Iterator for Paths {
379426 next += 1 ;
380427 }
381428
382- if is_dir ( & path) {
429+ if path. is_directory {
383430 // the path is a directory, so it's a match
384431
385432 // push this directory's contents
@@ -394,7 +441,7 @@ impl Iterator for Paths {
394441 if next == self . dir_patterns . len ( ) - 1 {
395442 // pattern ends in recursive pattern, so return this
396443 // directory as a result
397- return Some ( Ok ( path) ) ;
444+ return Some ( Ok ( path. into_path ( ) ) ) ;
398445 } else {
399446 // advanced to the next pattern for this path
400447 idx = next + 1 ;
@@ -427,8 +474,8 @@ impl Iterator for Paths {
427474 // *AND* its children so we don't need to check the
428475 // children
429476
430- if !self . require_dir || is_dir ( & path) {
431- return Some ( Ok ( path) ) ;
477+ if !self . require_dir || path. is_directory {
478+ return Some ( Ok ( path. into_path ( ) ) ) ;
432479 }
433480 } else {
434481 fill_todo (
@@ -817,10 +864,10 @@ impl Pattern {
817864// special-casing patterns to match `.` and `..`, and avoiding `readdir()`
818865// calls when there are no metacharacters in the pattern.
819866fn fill_todo (
820- todo : & mut Vec < Result < ( PathBuf , usize ) , GlobError > > ,
867+ todo : & mut Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
821868 patterns : & [ Pattern ] ,
822869 idx : usize ,
823- path : & Path ,
870+ path : & PathWrapper ,
824871 options : MatchOptions ,
825872) {
826873 // convert a pattern that's just many Char(_) to a string
@@ -836,7 +883,7 @@ fn fill_todo(
836883 Some ( s)
837884 }
838885
839- let add = |todo : & mut Vec < _ > , next_path : PathBuf | {
886+ let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
840887 if idx + 1 == patterns. len ( ) {
841888 // We know it's good, so don't make the iterator match this path
842889 // against the pattern again. In particular, it can't match
@@ -848,8 +895,8 @@ fn fill_todo(
848895 } ;
849896
850897 let pattern = & patterns[ idx] ;
851- let is_dir = is_dir ( path) ;
852- let curdir = path == Path :: new ( "." ) ;
898+ let is_dir = path. is_directory ;
899+ let curdir = path. as_ref ( ) == Path :: new ( "." ) ;
853900 match pattern_as_str ( pattern) {
854901 Some ( s) => {
855902 // This pattern component doesn't have any metacharacters, so we
@@ -863,6 +910,7 @@ fn fill_todo(
863910 } else {
864911 path. join ( & s)
865912 } ;
913+ let next_path = PathWrapper :: from_path ( next_path) ;
866914 if ( special && is_dir)
867915 || ( !special
868916 && ( fs:: metadata ( & next_path) . is_ok ( )
@@ -875,19 +923,21 @@ fn fill_todo(
875923 let dirs = fs:: read_dir ( path) . and_then ( |d| {
876924 d. map ( |e| {
877925 e. map ( |e| {
878- if curdir {
926+ let path = if curdir {
879927 PathBuf :: from ( e. path ( ) . file_name ( ) . unwrap ( ) )
880928 } else {
881929 e. path ( )
882- }
930+ } ;
931+ PathWrapper :: from_dir_entry ( path, e)
883932 } )
884933 } )
885934 . collect :: < Result < Vec < _ > , _ > > ( )
886935 } ) ;
887936 match dirs {
888937 Ok ( mut children) => {
889938 if options. require_literal_leading_dot {
890- children. retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
939+ children
940+ . retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
891941 }
892942 children. sort_by ( |p1, p2| p2. file_name ( ) . cmp ( & p1. file_name ( ) ) ) ;
893943 todo. extend ( children. into_iter ( ) . map ( |x| Ok ( ( x, idx) ) ) ) ;
@@ -900,7 +950,7 @@ fn fill_todo(
900950 if !pattern. tokens . is_empty ( ) && pattern. tokens [ 0 ] == Char ( '.' ) {
901951 for & special in & [ "." , ".." ] {
902952 if pattern. matches_with ( special, options) {
903- add ( todo, path. join ( special) ) ;
953+ add ( todo, PathWrapper :: from_path ( path. join ( special) ) ) ;
904954 }
905955 }
906956 }
0 commit comments