@@ -329,15 +329,16 @@ struct TreeNode {
329
329
dir : HybridDir ,
330
330
filename : Rc < [ libc:: c_char ] > ,
331
331
metadata : Metadata ,
332
+ path_depth : usize ,
332
333
}
333
334
334
335
/// An entry in the directory tree.
335
336
#[ derive( Debug , Clone ) ]
336
337
pub struct Entry < ' a > {
337
338
dir_file_descriptor : & ' a FileDescriptor ,
338
339
path_stack : & ' a [ Rc < [ libc:: c_char ] > ] ,
339
- filename : & ' a Rc < [ libc:: c_char ] > ,
340
- metadata : Option < & ' a Metadata > ,
340
+ filename : Rc < [ libc:: c_char ] > ,
341
+ metadata : Option < Metadata > ,
341
342
is_symlink : Option < bool > ,
342
343
read_link : Option < Rc < [ libc:: c_char ] > > ,
343
344
}
@@ -346,8 +347,8 @@ impl<'a> Entry<'a> {
346
347
fn new (
347
348
dir_file_descriptor : & ' a FileDescriptor ,
348
349
path_stack : & ' a [ Rc < [ libc:: c_char ] > ] ,
349
- filename : & ' a Rc < [ libc:: c_char ] > ,
350
- metadata : Option < & ' a Metadata > ,
350
+ filename : Rc < [ libc:: c_char ] > ,
351
+ metadata : Option < Metadata > ,
351
352
) -> Self {
352
353
Self {
353
354
dir_file_descriptor,
@@ -375,7 +376,7 @@ impl<'a> Entry<'a> {
375
376
///
376
377
/// This is either the metadata of the file itself or the metadata of the file it points to.
377
378
pub fn metadata ( & self ) -> Option < & Metadata > {
378
- self . metadata
379
+ self . metadata . as_ref ( )
379
380
}
380
381
381
382
/// Check if this entry is a symlink.
@@ -394,7 +395,7 @@ impl<'a> Entry<'a> {
394
395
///
395
396
/// This is either relative to the current working directory or an absolute path.
396
397
pub fn path ( & self ) -> DisplayablePath {
397
- DisplayablePath ( build_path ( self . path_stack , self . filename ) )
398
+ DisplayablePath ( build_path ( self . path_stack , & self . filename ) )
398
399
}
399
400
400
401
/// Check if this `Entry` is an empty directory.
@@ -473,28 +474,22 @@ impl Deref for DisplayablePath {
473
474
}
474
475
}
475
476
476
- enum NodeOrMetadata {
477
- TreeNode ( TreeNode ) ,
478
- Metadata ( Metadata ) ,
479
- }
480
-
481
- enum ProcessFileResult {
482
- ProcessedDirectory ( NodeOrMetadata ) ,
477
+ enum ProcessFileResult < ' a > {
478
+ ProcessedDirectory ( Entry < ' a > ) ,
483
479
ProcessedFile ,
484
480
NotProcessed ,
485
481
Skipped ,
486
482
}
487
483
488
- fn process_file < F , H > (
489
- path_stack : & [ Rc < [ libc:: c_char ] > ] ,
490
- dir_fd : & FileDescriptor ,
484
+ fn process_file < ' a , F , H > (
485
+ path_stack : & ' a [ Rc < [ libc:: c_char ] > ] ,
486
+ dir_fd : & ' a FileDescriptor ,
491
487
entry_filename : Rc < [ libc:: c_char ] > ,
492
488
follow_symlinks : bool ,
489
+ is_dot_or_double_dot : bool ,
493
490
file_handler : & mut F ,
494
491
err_reporter : & mut H ,
495
- is_dot_or_double_dot : bool ,
496
- conserve_fds : bool ,
497
- ) -> ProcessFileResult
492
+ ) -> ProcessFileResult < ' a >
498
493
where
499
494
F : FnMut ( Entry < ' _ > ) -> Result < bool , ( ) > ,
500
495
H : FnMut ( Entry < ' _ > , Error ) ,
@@ -504,7 +499,7 @@ where
504
499
Ok ( md) => md,
505
500
Err ( e) => {
506
501
err_reporter (
507
- Entry :: new ( dir_fd, & path_stack, & entry_filename, None ) ,
502
+ Entry :: new ( dir_fd, & path_stack, entry_filename, None ) ,
508
503
Error :: new ( e, ErrorKind :: Stat ) ,
509
504
) ;
510
505
return ProcessFileResult :: NotProcessed ;
@@ -519,7 +514,7 @@ where
519
514
Ok ( p) => p,
520
515
Err ( e) => {
521
516
err_reporter (
522
- Entry :: new ( dir_fd, path_stack, & entry_filename, None ) ,
517
+ Entry :: new ( dir_fd, path_stack, entry_filename, None ) ,
523
518
Error :: new ( e, ErrorKind :: ReadLink ) ,
524
519
) ;
525
520
return ProcessFileResult :: NotProcessed ;
@@ -534,7 +529,7 @@ where
534
529
( Some ( read_link) , entry_symlink_metadata)
535
530
} else {
536
531
err_reporter (
537
- Entry :: new ( dir_fd, path_stack, & entry_filename, None ) ,
532
+ Entry :: new ( dir_fd, path_stack, entry_filename, None ) ,
538
533
Error :: new ( e, ErrorKind :: Stat ) ,
539
534
) ;
540
535
return ProcessFileResult :: NotProcessed ;
@@ -545,7 +540,7 @@ where
545
540
( None , entry_symlink_metadata)
546
541
} ;
547
542
548
- let mut entry = Entry :: new ( dir_fd, path_stack, & entry_filename, Some ( & entry_metadata) ) ;
543
+ let mut entry = Entry :: new ( dir_fd, path_stack, entry_filename, Some ( entry_metadata) ) ;
549
544
entry. is_symlink = Some ( is_symlink) ;
550
545
entry. read_link = entry_readlink;
551
546
@@ -558,28 +553,30 @@ where
558
553
559
554
match file_handler_result {
560
555
Ok ( true ) => {
561
- if entry_metadata. file_type ( ) == FileType :: Directory {
556
+ let entry_metadata = entry. metadata . as_ref ( ) . unwrap ( ) ;
557
+ if entry_metadata. is_dir ( ) {
562
558
// Is the directory searchable?
563
559
if entry_metadata. is_executable ( ) {
564
- if conserve_fds {
565
- ProcessFileResult :: ProcessedDirectory ( NodeOrMetadata :: Metadata (
566
- entry_metadata,
567
- ) )
568
- } else {
569
- match OwnedDir :: open_at ( dir_fd, entry_filename. as_ptr ( ) ) {
570
- Ok ( new_dir) => ProcessFileResult :: ProcessedDirectory (
571
- NodeOrMetadata :: TreeNode ( TreeNode {
572
- dir : HybridDir :: Owned ( new_dir) ,
573
- filename : entry_filename,
574
- metadata : entry_metadata,
575
- } ) ,
576
- ) ,
577
- Err ( error) => {
578
- err_reporter ( entry, error) ;
579
- ProcessFileResult :: NotProcessed
580
- }
581
- }
582
- }
560
+ ProcessFileResult :: ProcessedDirectory ( entry)
561
+ // if conserve_fds {
562
+ // ProcessFileResult::ProcessedDirectory(NodeOrMetadata::Metadata(
563
+ // entry_metadata,
564
+ // ))
565
+ // } else {
566
+ // match OwnedDir::open_at(dir_fd, entry_filename.as_ptr()) {
567
+ // Ok(new_dir) => ProcessFileResult::ProcessedDirectory(
568
+ // NodeOrMetadata::TreeNode(TreeNode {
569
+ // dir: HybridDir::Owned(new_dir),
570
+ // filename: entry_filename,
571
+ // metadata: entry_metadata,
572
+ // }),
573
+ // ),
574
+ // Err(error) => {
575
+ // err_reporter(entry, error);
576
+ // ProcessFileResult::NotProcessed
577
+ // }
578
+ // }
579
+ // }
583
580
} else {
584
581
// "Permission denied" error. `io::ErrorKind::PermissionDenied` uses
585
582
// lowercase for "permission" in the error message so don't use that here.
@@ -651,7 +648,7 @@ where
651
648
Err ( e) => {
652
649
if let Some ( path_stack) = & path_stack {
653
650
err_reporter (
654
- Entry :: new ( & starting_dir, path_stack, & filename, None ) ,
651
+ Entry :: new ( & starting_dir, path_stack, filename, None ) ,
655
652
Error :: new ( e, ErrorKind :: Open ) ,
656
653
) ;
657
654
}
@@ -670,7 +667,9 @@ where
670
667
// TODO: Document
671
668
#[ derive( Debug , Clone , Default ) ] // Defaults to all `false`
672
669
pub struct TraverseDirectoryOpts {
670
+ /// Whether to dereference `path` if it's a symlink.
673
671
pub follow_symlinks_on_args : bool ,
672
+ /// Dereference symlinks encountered (also including `path`).
674
673
pub follow_symlinks : bool ,
675
674
pub include_dot_and_double_dot : bool ,
676
675
pub list_contents_first : bool ,
@@ -695,9 +694,7 @@ pub struct TraverseDirectoryOpts {
695
694
///
696
695
/// * `err_reporter` - Callback for reporting the errors encountered during the directory traversal.
697
696
///
698
- /// * `follow_symlinks_on_args` - Whether to dereference `path` if it's a symlink.
699
- ///
700
- /// * `follow_symlinks` - Dereference symlinks encountered (also including `path`).
697
+ /// * `opts` - TODO
701
698
///
702
699
/// # Return
703
700
///
@@ -749,17 +746,29 @@ where
749
746
match process_file (
750
747
& path_stack,
751
748
& starting_dir,
752
- dir_filename,
749
+ dir_filename. clone ( ) ,
753
750
follow_symlinks_on_args || follow_symlinks,
751
+ false ,
754
752
& mut file_handler,
755
753
& mut err_reporter,
756
- false ,
757
- false ,
758
754
) {
759
- ProcessFileResult :: ProcessedDirectory ( node) => match node {
760
- NodeOrMetadata :: TreeNode ( node) => stack. push ( node) ,
761
- NodeOrMetadata :: Metadata ( _) => unreachable ! ( ) ,
762
- } ,
755
+ ProcessFileResult :: ProcessedDirectory ( entry) => {
756
+ match OwnedDir :: open_at ( & starting_dir, dir_filename. as_ptr ( ) ) {
757
+ Ok ( new_dir) => {
758
+ let node = TreeNode {
759
+ dir : HybridDir :: Owned ( new_dir) ,
760
+ filename : dir_filename,
761
+ metadata : entry. metadata . unwrap ( ) ,
762
+ path_depth : path_stack. len ( ) ,
763
+ } ;
764
+ stack. push ( node) ;
765
+ }
766
+ Err ( error) => {
767
+ err_reporter ( entry, error) ;
768
+ return false ;
769
+ }
770
+ }
771
+ }
763
772
ProcessFileResult :: ProcessedFile => {
764
773
// `path` was not a directory
765
774
return false ;
@@ -802,10 +811,16 @@ where
802
811
HybridDir :: Deferred ( dir) => & dir. open_file_descriptor ( ) ,
803
812
} ;
804
813
814
+ // Resize `path_stack` to the appropriate depth.
815
+ debug_assert ! ( path_stack. len( ) >= current. path_depth) ;
816
+ path_stack. truncate ( current. path_depth ) ;
817
+
805
818
// Push the directory's filename. The contents' filename will be concatenated to the
806
819
// directory's filename.
807
820
path_stack. push ( current. filename . clone ( ) ) ;
808
821
822
+ let path_depth = path_stack. len ( ) ;
823
+
809
824
{
810
825
let mut dir_iter = dir. iter ( ) ;
811
826
@@ -830,8 +845,8 @@ where
830
845
// Need to report the filename of the directory itself so exclude
831
846
// the last one
832
847
& path_stack[ ..( path_stack. len ( ) - 2 ) ] ,
833
- & current. filename ,
834
- Some ( & current. metadata ) ,
848
+ current. filename . clone ( ) ,
849
+ Some ( current. metadata . clone ( ) ) ,
835
850
) ,
836
851
Error :: new ( e, ErrorKind :: ReadDir ) ,
837
852
) ;
@@ -866,15 +881,13 @@ where
866
881
dir_fd,
867
882
entry_filename. clone ( ) ,
868
883
follow_symlinks,
884
+ is_dot_or_double_dot,
869
885
& mut file_handler,
870
886
& mut err_reporter,
871
- is_dot_or_double_dot,
872
- conserve_fds,
873
887
) {
874
- ProcessFileResult :: ProcessedDirectory ( node_or_metadata) => {
875
- let node = match node_or_metadata {
876
- NodeOrMetadata :: TreeNode ( node) => node,
877
- NodeOrMetadata :: Metadata ( metadata) => match dir {
888
+ ProcessFileResult :: ProcessedDirectory ( entry) => {
889
+ let node = if conserve_fds {
890
+ match dir {
878
891
HybridDir :: Owned ( current_dir) => {
879
892
let path = build_path ( & path_stack, & entry_filename) ;
880
893
let slow_dir = DeferredDir :: new (
@@ -887,7 +900,8 @@ where
887
900
TreeNode {
888
901
dir : HybridDir :: Deferred ( slow_dir) ,
889
902
filename : entry_filename,
890
- metadata,
903
+ metadata : entry. metadata . unwrap ( ) ,
904
+ path_depth,
891
905
}
892
906
}
893
907
HybridDir :: Deferred ( current_dir) => {
@@ -898,10 +912,25 @@ where
898
912
TreeNode {
899
913
dir : HybridDir :: Deferred ( slow_dir) ,
900
914
filename : entry_filename,
901
- metadata,
915
+ metadata : entry. metadata . unwrap ( ) ,
916
+ path_depth,
902
917
}
903
918
}
904
- } ,
919
+ }
920
+ } else {
921
+ match OwnedDir :: open_at ( dir_fd, entry_filename. as_ptr ( ) ) {
922
+ Ok ( new_dir) => TreeNode {
923
+ dir : HybridDir :: Owned ( new_dir) ,
924
+ filename : entry_filename,
925
+ metadata : entry. metadata . unwrap ( ) ,
926
+ path_depth,
927
+ } ,
928
+ Err ( error) => {
929
+ err_reporter ( entry, error) ;
930
+ success = false ;
931
+ continue ;
932
+ }
933
+ }
905
934
} ;
906
935
907
936
if list_contents_first {
@@ -951,15 +980,14 @@ where
951
980
if let Err ( _) = postprocess_dir ( Entry :: new (
952
981
prev_dir,
953
982
& path_stack,
954
- & current. filename ,
955
- Some ( & current. metadata ) ,
983
+ current. filename . clone ( ) ,
984
+ Some ( current. metadata . clone ( ) ) ,
956
985
) ) {
957
986
success = false ;
958
987
// Don't `continue` here, falldown below
959
988
}
960
989
961
- // Go up a level in the tree
962
- path_stack. pop ( ) ;
990
+ // Process the next node
963
991
stack. pop ( ) . unwrap ( ) ;
964
992
}
965
993
0 commit comments