@@ -2002,6 +2002,7 @@ mod remove_dir_impl {
20022002    use  crate :: path:: { Path ,  PathBuf } ; 
20032003    use  crate :: sys:: common:: small_c_string:: run_path_with_cstr; 
20042004    use  crate :: sys:: { cvt,  cvt_r} ; 
2005+     use  crate :: sys_common:: ignore_notfound; 
20052006
20062007    pub  fn  openat_nofollow_dironly ( parent_fd :  Option < RawFd > ,  p :  & CStr )  -> io:: Result < OwnedFd >  { 
20072008        let  fd = cvt_r ( || unsafe  { 
@@ -2055,6 +2056,16 @@ mod remove_dir_impl {
20552056        } 
20562057    } 
20572058
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+ 
20582069    fn  remove_dir_all_recursive ( parent_fd :  Option < RawFd > ,  path :  & CStr )  -> io:: Result < ( ) >  { 
20592070        // try opening as directory 
20602071        let  fd = match  openat_nofollow_dironly ( parent_fd,  & path)  { 
@@ -2078,27 +2089,35 @@ mod remove_dir_impl {
20782089        for  child in  dir { 
20792090            let  child = child?; 
20802091            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+                     } 
20942110                } 
2111+             } ; 
2112+             if  result. is_err ( )  && !is_enoent ( & result)  { 
2113+                 return  result; 
20952114            } 
20962115        } 
20972116
20982117        // unlink the directory after removing its contents 
2099-         cvt ( unsafe  { 
2118+         ignore_notfound ( cvt ( unsafe  { 
21002119            unlinkat ( parent_fd. unwrap_or ( libc:: AT_FDCWD ) ,  path. as_ptr ( ) ,  libc:: AT_REMOVEDIR ) 
2101-         } ) ?; 
2120+         } ) ) ?; 
21022121        Ok ( ( ) ) 
21032122    } 
21042123
0 commit comments