@@ -47,6 +47,89 @@ 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+ fn remove_dir_with_special_cases ( path : & Path , options : & Options , error_occurred : bool ) -> bool {
102+ match fs:: remove_dir ( path) {
103+ #[ cfg( not( target_os = "linux" ) ) ]
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+ #[ cfg( target_os = "linux" ) ]
112+ Err ( _) if !error_occurred && path. read_dir ( ) . is_err ( ) => {
113+ // For compatibility with GNU test case on Linux
114+ // Check if directory is readable by attempting to read it
115+ show_permission_denied_error ( path) ;
116+ true
117+ }
118+ Err ( e) if !error_occurred => show_removal_error ( e, path) ,
119+ Err ( _) => {
120+ // If we already had errors while
121+ // trying to remove the children, then there is no need to
122+ // show another error message as we return from each level
123+ // of the recursion.
124+ error_occurred
125+ }
126+ Ok ( _) => {
127+ verbose_removed_directory ( path, options) ;
128+ false
129+ }
130+ }
131+ }
132+
50133#[ derive( Eq , PartialEq , Clone , Copy ) ]
51134/// Enum, determining when the `rm` will prompt the user about the file deletion
52135pub enum InteractiveMode {
@@ -472,22 +555,13 @@ fn unsafe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
472555 // If it's empty, this should succeed. If not, we'll get a different error.
473556 match fs:: remove_dir ( path) {
474557 Ok ( _) => {
475- if options. verbose {
476- println ! (
477- "{}" ,
478- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
479- ) ;
480- }
558+ verbose_removed_directory ( path, options) ;
481559 return false ; // Success
482560 }
483561 Err ( _remove_err) => {
484562 // Could not remove the directory. Always show the original permission denied error
485563 // since this indicates a fundamental access issue, even with force flag
486- let e = e. map_err_context (
487- || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ,
488- ) ;
489- show_error ! ( "{}" , e) ;
490- error = true ;
564+ return show_removal_error ( e, path) ;
491565 }
492566 }
493567 }
@@ -541,19 +615,9 @@ fn unsafe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
541615 }
542616 true
543617 }
544- Err ( e) => {
545- let e =
546- e. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
547- show_error ! ( "{e}" ) ;
548- true
549- }
618+ Err ( e) => show_removal_error ( e, path) ,
550619 Ok ( _) => {
551- if options. verbose {
552- println ! (
553- "{}" ,
554- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
555- ) ;
556- }
620+ verbose_removed_directory ( path, options) ;
557621 false
558622 }
559623 }
@@ -583,31 +647,7 @@ fn safe_remove_dir_recursive(path: &Path, options: &Options) -> bool {
583647 }
584648
585649 // Use regular fs::remove_dir for the root since we can't unlinkat ourselves
586- match fs:: remove_dir ( path) {
587- Ok ( _) => {
588- if options. verbose {
589- println ! (
590- "{}" ,
591- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
592- ) ;
593- }
594- false
595- }
596- Err ( e) if !error => {
597- let e = e. map_err_context (
598- || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ,
599- ) ;
600- show_error ! ( "{e}" ) ;
601- true
602- }
603- Err ( _) => {
604- // If there has already been at least one error when
605- // trying to remove the children, then there is no need to
606- // show another error message as we return from each level
607- // of the recursion.
608- error
609- }
610- }
650+ remove_dir_with_special_cases ( path, options, error)
611651 }
612652}
613653
@@ -690,11 +730,8 @@ fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options
690730 ) ;
691731 show_error ! ( "{e}" ) ;
692732 error = true ;
693- } else if options. verbose {
694- println ! (
695- "{}" ,
696- translate!( "rm-verbose-removed-directory" , "file" => normalize( & entry_path) . quote( ) )
697- ) ;
733+ } else {
734+ verbose_removed_directory ( & entry_path, options) ;
698735 }
699736 }
700737 } else {
@@ -706,11 +743,8 @@ fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options
706743 ) ;
707744 show_error ! ( "{e}" ) ;
708745 error = true ;
709- } else if options. verbose {
710- println ! (
711- "{}" ,
712- translate!( "rm-verbose-removed" , "file" => normalize( & entry_path) . quote( ) )
713- ) ;
746+ } else {
747+ verbose_removed_file ( & entry_path, options) ;
714748 }
715749 }
716750 }
@@ -800,7 +834,7 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
800834 // For compatibility with GNU test case
801835 // `tests/rm/unread2.sh`, show "Permission denied" in this
802836 // case instead of "Directory not empty".
803- show_error ! ( "cannot remove {}: Permission denied" , path. quote ( ) ) ;
837+ show_permission_denied_error ( path) ;
804838 error = true ;
805839 }
806840 Err ( e) if !error => {
@@ -816,11 +850,7 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
816850 // show another error message as we return from each level
817851 // of the recursion.
818852 }
819- Ok ( _) if options. verbose => println ! (
820- "{}" ,
821- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
822- ) ,
823- Ok ( _) => { }
853+ Ok ( _) => verbose_removed_directory ( path, options) ,
824854 }
825855
826856 error
@@ -910,23 +940,7 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
910940 }
911941
912942 // Fallback method for non-Linux or when safe traversal is unavailable
913- match fs:: remove_dir ( path) {
914- Ok ( _) => {
915- if options. verbose {
916- println ! (
917- "{}" ,
918- translate!( "rm-verbose-removed-directory" , "file" => normalize( path) . quote( ) )
919- ) ;
920- }
921- false
922- }
923- Err ( e) => {
924- let e =
925- e. map_err_context ( || translate ! ( "rm-error-cannot-remove" , "file" => path. quote( ) ) ) ;
926- show_error ! ( "{e}" ) ;
927- true
928- }
929- }
943+ remove_dir_with_feedback ( path, options)
930944}
931945
932946fn remove_file ( path : & Path , options : & Options ) -> bool {
@@ -940,12 +954,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
940954 Ok ( dir_fd) => {
941955 match dir_fd. unlink_at ( file_name, false ) {
942956 Ok ( _) => {
943- if options. verbose {
944- println ! (
945- "{}" ,
946- translate!( "rm-verbose-removed" , "file" => normalize( path) . quote( ) )
947- ) ;
948- }
957+ verbose_removed_file ( path, options) ;
949958 return false ;
950959 }
951960 Err ( e) => {
@@ -958,7 +967,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
958967 )
959968 ) ;
960969 } else {
961- show_error ! ( "cannot remove {}: {e}" , path. quote ( ) ) ;
970+ return show_generic_removal_error ( e , path) ;
962971 }
963972 return true ;
964973 }
@@ -975,12 +984,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
975984 // Fallback method for non-Linux or when safe traversal is unavailable
976985 match fs:: remove_file ( path) {
977986 Ok ( _) => {
978- if options. verbose {
979- println ! (
980- "{}" ,
981- translate!( "rm-verbose-removed" , "file" => normalize( path) . quote( ) )
982- ) ;
983- }
987+ verbose_removed_file ( path, options) ;
984988 }
985989 Err ( e) => {
986990 if e. kind ( ) == std:: io:: ErrorKind :: PermissionDenied {
@@ -990,7 +994,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
990994 RmError :: CannotRemovePermissionDenied ( path. as_os_str( ) . to_os_string( ) )
991995 ) ;
992996 } else {
993- show_error ! ( "cannot remove {}: {e}" , path. quote ( ) ) ;
997+ return show_generic_removal_error ( e , path) ;
994998 }
995999 return true ;
9961000 }
0 commit comments