From ddff7f0e50c1184c5cfa1a54c7bd2b6848ed85d6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 28 Apr 2023 02:19:00 +0100 Subject: [PATCH] remove_dir_all: delete directory with fewer perms 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. --- library/std/src/sys/windows/fs.rs | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 956db577d53..8ed62cdddcd 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1132,27 +1132,30 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io &dir, &name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY, - )?; - dirlist.push(child_dir); - } else { - 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(); + ); + // On success, add the handle to the queue. + // If opening the directory fails we treat it the same as a file + if let Ok(child_dir) = child_dir { + dirlist.push(child_dir); + continue; } } + 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 !more_data {