@@ -2002,6 +2002,7 @@ mod remove_dir_impl {
2002
2002
use crate :: path:: { Path , PathBuf } ;
2003
2003
use crate :: sys:: common:: small_c_string:: run_path_with_cstr;
2004
2004
use crate :: sys:: { cvt, cvt_r} ;
2005
+ use crate :: sys_common:: ignore_notfound;
2005
2006
2006
2007
pub fn openat_nofollow_dironly ( parent_fd : Option < RawFd > , p : & CStr ) -> io:: Result < OwnedFd > {
2007
2008
let fd = cvt_r ( || unsafe {
@@ -2055,6 +2056,16 @@ mod remove_dir_impl {
2055
2056
}
2056
2057
}
2057
2058
2059
+ fn is_enoent ( result : & io:: Result < ( ) > ) -> bool {
2060
+ if let Err ( err) = result
2061
+ && matches ! ( err. raw_os_error( ) , Some ( libc:: ENOENT ) )
2062
+ {
2063
+ true
2064
+ } else {
2065
+ false
2066
+ }
2067
+ }
2068
+
2058
2069
fn remove_dir_all_recursive ( parent_fd : Option < RawFd > , path : & CStr ) -> io:: Result < ( ) > {
2059
2070
// try opening as directory
2060
2071
let fd = match openat_nofollow_dironly ( parent_fd, & path) {
@@ -2078,27 +2089,35 @@ mod remove_dir_impl {
2078
2089
for child in dir {
2079
2090
let child = child?;
2080
2091
let child_name = child. name_cstr ( ) ;
2081
- match is_dir ( & child) {
2082
- Some ( true ) => {
2083
- remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2084
- }
2085
- Some ( false ) => {
2086
- cvt ( unsafe { unlinkat ( fd, child_name. as_ptr ( ) , 0 ) } ) ?;
2087
- }
2088
- None => {
2089
- // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
2090
- // if the process has the appropriate privileges. This however can causing orphaned
2091
- // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
2092
- // into it first instead of trying to unlink() it.
2093
- remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2092
+ // we need an inner try block, because if one of these
2093
+ // directories has already been deleted, then we need to
2094
+ // continue the loop, not return ok.
2095
+ let result: io:: Result < ( ) > = try {
2096
+ match is_dir ( & child) {
2097
+ Some ( true ) => {
2098
+ remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2099
+ }
2100
+ Some ( false ) => {
2101
+ cvt ( unsafe { unlinkat ( fd, child_name. as_ptr ( ) , 0 ) } ) ?;
2102
+ }
2103
+ None => {
2104
+ // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
2105
+ // if the process has the appropriate privileges. This however can causing orphaned
2106
+ // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
2107
+ // into it first instead of trying to unlink() it.
2108
+ remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2109
+ }
2094
2110
}
2111
+ } ;
2112
+ if result. is_err ( ) && !is_enoent ( & result) {
2113
+ return result;
2095
2114
}
2096
2115
}
2097
2116
2098
2117
// unlink the directory after removing its contents
2099
- cvt ( unsafe {
2118
+ ignore_notfound ( cvt ( unsafe {
2100
2119
unlinkat ( parent_fd. unwrap_or ( libc:: AT_FDCWD ) , path. as_ptr ( ) , libc:: AT_REMOVEDIR )
2101
- } ) ?;
2120
+ } ) ) ?;
2102
2121
Ok ( ( ) )
2103
2122
}
2104
2123
0 commit comments