@@ -47,6 +47,88 @@ enum RmError {
4747
4848impl UError for RmError { }
4949
50+ /// Helper function to print verbose message for removed file
51+ fn verbose_removed_file ( path : & Path , options : & Options ) {
52+ if options. verbose {
53+ println ! (
54+ "{}" ,
55+ translate!( "rm-verbose-removed" , "file" => normalize( path) . quote( ) )
56+ ) ;
57+ }
58+ }
59+
60+ /// Helper function to print verbose message for removed directory
61+ fn verbose_removed_directory ( path : & Path , options : & Options ) {
62+ if options. verbose {
63+ println ! (
64+ "{}" ,
65+ translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
66+ ) ;
67+ }
68+ }
69+
70+ /// Helper function to show error with context and return error status
71+ fn show_removal_error ( error : std:: io:: Error , path : & Path ) -> bool {
72+ let e = error. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
73+ show_error ! ( "{e}" ) ;
74+ true
75+ }
76+
77+ /// Helper function for permission denied errors
78+ fn show_permission_denied_error ( path : & Path ) -> bool {
79+ show_error ! ( "cannot remove {}: Permission denied" , path. quote( ) ) ;
80+ true
81+ }
82+
83+ /// Helper function to show generic removal error
84+ fn show_generic_removal_error ( error : std:: io:: Error , path : & Path ) -> bool {
85+ show_error ! ( "cannot remove {}: {error}" , path. quote( ) ) ;
86+ true
87+ }
88+
89+ /// Helper function to remove a directory and handle results
90+ fn remove_dir_with_feedback ( path : & Path , options : & Options ) -> bool {
91+ match fs:: remove_dir ( path) {
92+ Ok ( _) => {
93+ verbose_removed_directory ( path, options) ;
94+ false
95+ }
96+ Err ( e) => show_removal_error ( e, path) ,
97+ }
98+ }
99+
100+ /// Helper function to remove directory handling special cases
101+ #[ cfg( target_os = "linux" ) ]
102+ fn remove_dir_with_special_cases ( path : & Path , options : & Options , error_occurred : bool ) -> bool {
103+ match fs:: remove_dir ( path) {
104+ Err ( _) if !error_occurred && !is_readable ( path) => {
105+ // For compatibility with GNU test case
106+ // `tests/rm/unread2.sh`, show "Permission denied" in this
107+ // case instead of "Directory not empty".
108+ show_permission_denied_error ( path) ;
109+ true
110+ }
111+ Err ( _) if !error_occurred && path. read_dir ( ) . is_err ( ) => {
112+ // For compatibility with GNU test case on Linux
113+ // Check if directory is readable by attempting to read it
114+ show_permission_denied_error ( path) ;
115+ true
116+ }
117+ Err ( e) if !error_occurred => show_removal_error ( e, path) ,
118+ Err ( _) => {
119+ // If we already had errors while
120+ // trying to remove the children, then there is no need to
121+ // show another error message as we return from each level
122+ // of the recursion.
123+ error_occurred
124+ }
125+ Ok ( _) => {
126+ verbose_removed_directory ( path, options) ;
127+ false
128+ }
129+ }
130+ }
131+
50132#[ derive( Eq , PartialEq , Clone , Copy ) ]
51133/// Enum, determining when the `rm` will prompt the user about the file deletion
52134pub enum InteractiveMode {
@@ -473,22 +555,13 @@ fn unsafe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
473555 // If it's empty, this should succeed. If not, we'll get a different error.
474556 match fs:: remove_dir ( path) {
475557 Ok ( _) => {
476- if options. verbose {
477- println ! (
478- "{}" ,
479- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
480- ) ;
481- }
558+ verbose_removed_directory ( path, options) ;
482559 return false ; // Success
483560 }
484561 Err ( _remove_err) => {
485562 // Could not remove the directory. Always show the original permission denied error
486563 // since this indicates a fundamental access issue, even with force flag
487- let e = e. map_err_context (
488- || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ,
489- ) ;
490- show_error ! ( "{}" , e) ;
491- error = true ;
564+ return show_removal_error ( e, path) ;
492565 }
493566 }
494567 }
@@ -542,19 +615,9 @@ fn unsafe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
542615 }
543616 true
544617 }
545- Err ( e) => {
546- let e =
547- e. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
548- show_error ! ( "{e}" ) ;
549- true
550- }
618+ Err ( e) => show_removal_error ( e, path) ,
551619 Ok ( _) => {
552- if options. verbose {
553- println ! (
554- "{}" ,
555- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
556- ) ;
557- }
620+ verbose_removed_directory ( path, options) ;
558621 false
559622 }
560623 }
@@ -584,31 +647,7 @@ fn safe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
584647 }
585648
586649 // Use regular fs::remove_dir for the root since we can't unlinkat ourselves
587- match fs:: remove_dir ( path) {
588- Ok ( _) => {
589- if options. verbose {
590- println ! (
591- "{}" ,
592- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
593- ) ;
594- }
595- false
596- }
597- Err ( e) if !error => {
598- let e = e. map_err_context (
599- || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ,
600- ) ;
601- show_error ! ( "{e}" ) ;
602- true
603- }
604- Err ( _) => {
605- // If there has already been at least one error when
606- // trying to remove the children, then there is no need to
607- // show another error message as we return from each level
608- // of the recursion.
609- error
610- }
611- }
650+ remove_dir_with_special_cases ( path, options, error)
612651 }
613652}
614653
@@ -691,11 +730,8 @@ fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options
691730 ) ;
692731 show_error ! ( "{e}" ) ;
693732 error = true ;
694- } else if options. verbose {
695- println ! (
696- "{}" ,
697- translate!( "rm-verbose-removed-directory" , "file" => normalize( & entry_path) . quote( ) )
698- ) ;
733+ } else {
734+ verbose_removed_directory ( & entry_path, options) ;
699735 }
700736 }
701737 } else {
@@ -707,11 +743,8 @@ fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options
707743 ) ;
708744 show_error ! ( "{e}" ) ;
709745 error = true ;
710- } else if options. verbose {
711- println ! (
712- "{}" ,
713- translate!( "rm-verbose-removed" , "file" => normalize( & entry_path) . quote( ) )
714- ) ;
746+ } else {
747+ verbose_removed_file ( & entry_path, options) ;
715748 }
716749 }
717750 }
@@ -801,7 +834,7 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
801834 // For compatibility with GNU test case
802835 // `tests/rm/unread2.sh`, show "Permission denied" in this
803836 // case instead of "Directory not empty".
804- show_error ! ( "cannot remove {}: Permission denied" , path. quote ( ) ) ;
837+ show_permission_denied_error ( path) ;
805838 error = true ;
806839 }
807840 Err ( e) if !error => {
@@ -817,11 +850,7 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
817850 // show another error message as we return from each level
818851 // of the recursion.
819852 }
820- Ok ( _) if options. verbose => println ! (
821- "{}" ,
822- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
823- ) ,
824- Ok ( _) => { }
853+ Ok ( _) => verbose_removed_directory ( path, options) ,
825854 }
826855
827856 error
@@ -911,23 +940,7 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
911940 }
912941
913942 // Fallback method for non-Linux or when safe traversal is unavailable
914- match fs:: remove_dir ( path) {
915- Ok ( _) => {
916- if options. verbose {
917- println ! (
918- "{}" ,
919- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
920- ) ;
921- }
922- false
923- }
924- Err ( e) => {
925- let e =
926- e. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
927- show_error ! ( "{e}" ) ;
928- true
929- }
930- }
943+ remove_dir_with_feedback ( path, options)
931944}
932945
933946fn remove_file ( path : & Path , options : & Options ) -> bool {
@@ -941,12 +954,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
941954 Ok ( dir_fd) => {
942955 match dir_fd. unlink_at ( file_name, false ) {
943956 Ok ( _) => {
944- if options. verbose {
945- println ! (
946- "{}" ,
947- translate!( "rm-verbose-removed" , "file" => normalize( path) . quote( ) )
948- ) ;
949- }
957+ verbose_removed_file ( path, options) ;
950958 return false ;
951959 }
952960 Err ( e) => {
@@ -959,7 +967,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
959967 )
960968 ) ;
961969 } else {
962- show_error ! ( "cannot remove {}: {e}" , path. quote ( ) ) ;
970+ return show_generic_removal_error ( e , path) ;
963971 }
964972 return true ;
965973 }
@@ -976,12 +984,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
976984 // Fallback method for non-Linux or when safe traversal is unavailable
977985 match fs:: remove_file ( path) {
978986 Ok ( _) => {
979- if options. verbose {
980- println ! (
981- "{}" ,
982- translate!( "rm-verbose-removed" , "file" => normalize( path) . quote( ) )
983- ) ;
984- }
987+ verbose_removed_file ( path, options) ;
985988 }
986989 Err ( e) => {
987990 if e. kind ( ) == std:: io:: ErrorKind :: PermissionDenied {
@@ -991,7 +994,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
991994 RmError :: CannotRemovePermissionDenied ( path. as_os_str( ) . to_os_string( ) )
992995 ) ;
993996 } else {
994- show_error ! ( "cannot remove {}: {e}" , path. quote ( ) ) ;
997+ return show_generic_removal_error ( e , path) ;
995998 }
996999 return true ;
9971000 }
0 commit comments