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