@@ -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