@@ -73,7 +73,9 @@ use std::cmp;
73
73
use std:: error:: Error ;
74
74
use std:: fmt;
75
75
use std:: fs;
76
+ use std:: fs:: DirEntry ;
76
77
use std:: io;
78
+ use std:: ops:: Deref ;
77
79
use std:: path:: { self , Component , Path , PathBuf } ;
78
80
use std:: str:: FromStr ;
79
81
@@ -96,8 +98,8 @@ pub struct Paths {
96
98
dir_patterns : Vec < Pattern > ,
97
99
require_dir : bool ,
98
100
options : MatchOptions ,
99
- todo : Vec < Result < ( PathBuf , usize ) , GlobError > > ,
100
- scope : Option < PathBuf > ,
101
+ todo : Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
102
+ scope : Option < PathWrapper > ,
101
103
}
102
104
103
105
/// 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
242
244
}
243
245
244
246
let scope = root. map_or_else ( || PathBuf :: from ( "." ) , to_scope) ;
247
+ let scope = PathWrapper :: from_path ( scope) ;
245
248
246
249
let mut dir_patterns = Vec :: new ( ) ;
247
250
let components =
@@ -323,8 +326,52 @@ impl fmt::Display for GlobError {
323
326
}
324
327
}
325
328
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
+ }
328
375
}
329
376
330
377
/// An alias for a glob iteration result.
@@ -363,10 +410,10 @@ impl Iterator for Paths {
363
410
// idx -1: was already checked by fill_todo, maybe path was '.' or
364
411
// '..' that we can't match here because of normalization.
365
412
if idx == !0 as usize {
366
- if self . require_dir && !is_dir ( & path) {
413
+ if self . require_dir && !path. is_directory {
367
414
continue ;
368
415
}
369
- return Some ( Ok ( path) ) ;
416
+ return Some ( Ok ( path. into_path ( ) ) ) ;
370
417
}
371
418
372
419
if self . dir_patterns [ idx] . is_recursive {
@@ -379,7 +426,7 @@ impl Iterator for Paths {
379
426
next += 1 ;
380
427
}
381
428
382
- if is_dir ( & path) {
429
+ if path. is_directory {
383
430
// the path is a directory, so it's a match
384
431
385
432
// push this directory's contents
@@ -394,7 +441,7 @@ impl Iterator for Paths {
394
441
if next == self . dir_patterns . len ( ) - 1 {
395
442
// pattern ends in recursive pattern, so return this
396
443
// directory as a result
397
- return Some ( Ok ( path) ) ;
444
+ return Some ( Ok ( path. into_path ( ) ) ) ;
398
445
} else {
399
446
// advanced to the next pattern for this path
400
447
idx = next + 1 ;
@@ -427,8 +474,8 @@ impl Iterator for Paths {
427
474
// *AND* its children so we don't need to check the
428
475
// children
429
476
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 ( ) ) ) ;
432
479
}
433
480
} else {
434
481
fill_todo (
@@ -817,10 +864,10 @@ impl Pattern {
817
864
// special-casing patterns to match `.` and `..`, and avoiding `readdir()`
818
865
// calls when there are no metacharacters in the pattern.
819
866
fn fill_todo (
820
- todo : & mut Vec < Result < ( PathBuf , usize ) , GlobError > > ,
867
+ todo : & mut Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
821
868
patterns : & [ Pattern ] ,
822
869
idx : usize ,
823
- path : & Path ,
870
+ path : & PathWrapper ,
824
871
options : MatchOptions ,
825
872
) {
826
873
// convert a pattern that's just many Char(_) to a string
@@ -836,7 +883,7 @@ fn fill_todo(
836
883
Some ( s)
837
884
}
838
885
839
- let add = |todo : & mut Vec < _ > , next_path : PathBuf | {
886
+ let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
840
887
if idx + 1 == patterns. len ( ) {
841
888
// We know it's good, so don't make the iterator match this path
842
889
// against the pattern again. In particular, it can't match
@@ -848,8 +895,8 @@ fn fill_todo(
848
895
} ;
849
896
850
897
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 ( "." ) ;
853
900
match pattern_as_str ( pattern) {
854
901
Some ( s) => {
855
902
// This pattern component doesn't have any metacharacters, so we
@@ -863,6 +910,7 @@ fn fill_todo(
863
910
} else {
864
911
path. join ( & s)
865
912
} ;
913
+ let next_path = PathWrapper :: from_path ( next_path) ;
866
914
if ( special && is_dir)
867
915
|| ( !special
868
916
&& ( fs:: metadata ( & next_path) . is_ok ( )
@@ -875,19 +923,21 @@ fn fill_todo(
875
923
let dirs = fs:: read_dir ( path) . and_then ( |d| {
876
924
d. map ( |e| {
877
925
e. map ( |e| {
878
- if curdir {
926
+ let path = if curdir {
879
927
PathBuf :: from ( e. path ( ) . file_name ( ) . unwrap ( ) )
880
928
} else {
881
929
e. path ( )
882
- }
930
+ } ;
931
+ PathWrapper :: from_dir_entry ( path, e)
883
932
} )
884
933
} )
885
934
. collect :: < Result < Vec < _ > , _ > > ( )
886
935
} ) ;
887
936
match dirs {
888
937
Ok ( mut children) => {
889
938
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 ( "." ) ) ;
891
941
}
892
942
children. sort_by ( |p1, p2| p2. file_name ( ) . cmp ( & p1. file_name ( ) ) ) ;
893
943
todo. extend ( children. into_iter ( ) . map ( |x| Ok ( ( x, idx) ) ) ) ;
@@ -900,7 +950,7 @@ fn fill_todo(
900
950
if !pattern. tokens . is_empty ( ) && pattern. tokens [ 0 ] == Char ( '.' ) {
901
951
for & special in & [ "." , ".." ] {
902
952
if pattern. matches_with ( special, options) {
903
- add ( todo, path. join ( special) ) ;
953
+ add ( todo, PathWrapper :: from_path ( path. join ( special) ) ) ;
904
954
}
905
955
}
906
956
}
0 commit comments