Rollup merge of #127623 - lolbinarycat:fix_remove_dir_all, r=Amanieu · patricklam/verify-rust-std@2c06146 (original) (raw)

`@@ -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, p: &CStr) -> io::Result {

`

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

``