Rollup merge of #110918 - ChrisDenton:on-error-resume-next, r=cuviper

`remove_dir_all`: try deleting the directory even if `FILE_LIST_DIRECTORY` access is denied

If opening a directory with `FILE_LIST_DIRECTORY` access fails then we should try opening without requesting that access. We may still be able to delete it if it's empty or a link.

Fixes https://github.com/rust-lang/cargo/issues/12042
This commit is contained in:
Matthias Krüger 2023-04-28 07:34:04 +02:00 committed by GitHub
commit 6476b79df7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1132,27 +1132,30 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io
&dir, &dir,
&name, &name,
c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY,
)?; );
dirlist.push(child_dir); // On success, add the handle to the queue.
} else { // If opening the directory fails we treat it the same as a file
for i in 1..=MAX_RETRIES { if let Ok(child_dir) = child_dir {
let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE); dirlist.push(child_dir);
match result { continue;
Ok(f) => delete(&f)?,
// Already deleted, so skip.
Err(e) if e.kind() == io::ErrorKind::NotFound => break,
// Retry a few times if the file is locked or a delete is already in progress.
Err(e)
if i < MAX_RETRIES
&& (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _)
|| e.raw_os_error()
== Some(c::ERROR_SHARING_VIOLATION as _)) => {}
// Otherwise return the error.
Err(e) => return Err(e),
}
thread::yield_now();
} }
} }
for i in 1..=MAX_RETRIES {
let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE);
match result {
Ok(f) => delete(&f)?,
// Already deleted, so skip.
Err(e) if e.kind() == io::ErrorKind::NotFound => break,
// Retry a few times if the file is locked or a delete is already in progress.
Err(e)
if i < MAX_RETRIES
&& (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _)
|| e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _)) => {}
// Otherwise return the error.
Err(e) => return Err(e),
}
thread::yield_now();
}
} }
// If there were no more files then delete the directory. // If there were no more files then delete the directory.
if !more_data { if !more_data {