@@ -394,7 +394,7 @@ fn is_readable_metadata(metadata: &Metadata) -> bool {
394394}
395395
396396/// Whether the given file or directory is readable.
397- #[ cfg( unix) ]
397+ #[ cfg( all ( unix, not ( target_os = "linux" ) ) ) ]
398398fn is_readable ( path : & Path ) -> bool {
399399 match fs:: metadata ( path) {
400400 Err ( _) => false ,
@@ -590,19 +590,14 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
590590 return false ;
591591 }
592592
593- // Use secure traversal on Linux for long paths
593+ // Use secure traversal on Linux to prevent TOCTOU attacks
594594 #[ cfg( target_os = "linux" ) ]
595- {
596- if let Some ( s) = path. to_str ( ) {
597- if s. len ( ) > 1000 {
598- return safe_remove_dir_recursive ( path, options) ;
599- }
600- }
601- }
595+ return safe_remove_dir_recursive ( path, options) ;
602596
603- // Fallback for non-Linux or shorter paths
597+ // Fallback for non-Linux systems
604598 #[ cfg( not( target_os = "linux" ) ) ]
605599 {
600+ // Handle very long paths with remove_dir_all
606601 if let Some ( s) = path. to_str ( ) {
607602 if s. len ( ) > 1000 {
608603 match fs:: remove_dir_all ( path) {
@@ -617,62 +612,63 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
617612 }
618613 }
619614 }
620- }
621615
622- // Recursive case: this is a directory.
623- let mut error = false ;
624- match fs:: read_dir ( path) {
625- Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: PermissionDenied => {
626- // This is not considered an error.
627- }
628- Err ( _) => error = true ,
629- Ok ( iter) => {
630- for entry in iter {
631- match entry {
632- Err ( _) => error = true ,
633- Ok ( entry) => {
634- let child_error = remove_dir_recursive ( & entry. path ( ) , options) ;
635- error = error || child_error;
616+ // Recursive case: this is a directory.
617+ let mut error = false ;
618+ match fs:: read_dir ( path) {
619+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: PermissionDenied => {
620+ // This is not considered an error.
621+ }
622+ Err ( _) => error = true ,
623+ Ok ( iter) => {
624+ for entry in iter {
625+ match entry {
626+ Err ( _) => error = true ,
627+ Ok ( entry) => {
628+ let child_error = remove_dir_recursive ( & entry. path ( ) , options) ;
629+ error = error || child_error;
630+ }
636631 }
637632 }
638633 }
639634 }
640- }
641-
642- // Ask the user whether to remove the current directory.
643- if options. interactive == InteractiveMode :: Always && !prompt_dir ( path, options) {
644- return false ;
645- }
646635
647- // Try removing the directory itself.
648- match fs:: remove_dir ( path) {
649- Err ( _) if !error && !is_readable ( path) => {
650- // For compatibility with GNU test case
651- // `tests/rm/unread2.sh`, show "Permission denied" in this
652- // case instead of "Directory not empty".
653- show_error ! ( "cannot remove {}: Permission denied" , path. quote( ) ) ;
654- error = true ;
655- }
656- Err ( e) if !error => {
657- let e =
658- e. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
659- show_error ! ( "{e}" ) ;
660- error = true ;
636+ // Ask the user whether to remove the current directory.
637+ if options. interactive == InteractiveMode :: Always && !prompt_dir ( path, options) {
638+ return false ;
661639 }
662- Err ( _) => {
663- // If there has already been at least one error when
664- // trying to remove the children, then there is no need to
665- // show another error message as we return from each level
666- // of the recursion.
640+
641+ // Try removing the directory itself.
642+ match fs:: remove_dir ( path) {
643+ Err ( _) if !error && !is_readable ( path) => {
644+ // For compatibility with GNU test case
645+ // `tests/rm/unread2.sh`, show "Permission denied" in this
646+ // case instead of "Directory not empty".
647+ show_error ! ( "cannot remove {}: Permission denied" , path. quote( ) ) ;
648+ error = true ;
649+ }
650+ Err ( e) if !error => {
651+ let e = e. map_err_context (
652+ || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ,
653+ ) ;
654+ show_error ! ( "{e}" ) ;
655+ error = true ;
656+ }
657+ Err ( _) => {
658+ // If there has already been at least one error when
659+ // trying to remove the children, then there is no need to
660+ // show another error message as we return from each level
661+ // of the recursion.
662+ }
663+ Ok ( _) if options. verbose => println ! (
664+ "{}" ,
665+ translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
666+ ) ,
667+ Ok ( _) => { }
667668 }
668- Ok ( _) if options. verbose => println ! (
669- "{}" ,
670- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
671- ) ,
672- Ok ( _) => { }
673- }
674669
675- error
670+ error
671+ }
676672}
677673
678674fn handle_dir ( path : & Path , options : & Options ) -> bool {
0 commit comments