@@ -2029,6 +2029,7 @@ mod remove_dir_impl {
20292029 use crate :: path:: { Path , PathBuf } ;
20302030 use crate :: sys:: common:: small_c_string:: run_path_with_cstr;
20312031 use crate :: sys:: { cvt, cvt_r} ;
2032+ use crate :: sys_common:: ignore_notfound;
20322033
20332034 pub fn openat_nofollow_dironly ( parent_fd : Option < RawFd > , p : & CStr ) -> io:: Result < OwnedFd > {
20342035 let fd = cvt_r ( || unsafe {
@@ -2082,6 +2083,16 @@ mod remove_dir_impl {
20822083 }
20832084 }
20842085
2086+ fn is_enoent ( result : & io:: Result < ( ) > ) -> bool {
2087+ if let Err ( err) = result
2088+ && matches ! ( err. raw_os_error( ) , Some ( libc:: ENOENT ) )
2089+ {
2090+ true
2091+ } else {
2092+ false
2093+ }
2094+ }
2095+
20852096 fn remove_dir_all_recursive ( parent_fd : Option < RawFd > , path : & CStr ) -> io:: Result < ( ) > {
20862097 // try opening as directory
20872098 let fd = match openat_nofollow_dironly ( parent_fd, & path) {
@@ -2105,27 +2116,35 @@ mod remove_dir_impl {
21052116 for child in dir {
21062117 let child = child?;
21072118 let child_name = child. name_cstr ( ) ;
2108- match is_dir ( & child) {
2109- Some ( true ) => {
2110- remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2111- }
2112- Some ( false ) => {
2113- cvt ( unsafe { unlinkat ( fd, child_name. as_ptr ( ) , 0 ) } ) ?;
2114- }
2115- None => {
2116- // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
2117- // if the process has the appropriate privileges. This however can causing orphaned
2118- // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
2119- // into it first instead of trying to unlink() it.
2120- remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2119+ // we need an inner try block, because if one of these
2120+ // directories has already been deleted, then we need to
2121+ // continue the loop, not return ok.
2122+ let result: io:: Result < ( ) > = try {
2123+ match is_dir ( & child) {
2124+ Some ( true ) => {
2125+ remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2126+ }
2127+ Some ( false ) => {
2128+ cvt ( unsafe { unlinkat ( fd, child_name. as_ptr ( ) , 0 ) } ) ?;
2129+ }
2130+ None => {
2131+ // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
2132+ // if the process has the appropriate privileges. This however can causing orphaned
2133+ // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
2134+ // into it first instead of trying to unlink() it.
2135+ remove_dir_all_recursive ( Some ( fd) , child_name) ?;
2136+ }
21212137 }
2138+ } ;
2139+ if result. is_err ( ) && !is_enoent ( & result) {
2140+ return result;
21222141 }
21232142 }
21242143
21252144 // unlink the directory after removing its contents
2126- cvt ( unsafe {
2145+ ignore_notfound ( cvt ( unsafe {
21272146 unlinkat ( parent_fd. unwrap_or ( libc:: AT_FDCWD ) , path. as_ptr ( ) , libc:: AT_REMOVEDIR )
2128- } ) ?;
2147+ } ) ) ?;
21292148 Ok ( ( ) )
21302149 }
21312150
0 commit comments