about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Denton <chris@chrisdenton.dev>2023-04-28 02:19:00 +0100
committerChris Denton <chris@chrisdenton.dev>2023-04-28 02:30:45 +0100
commitddff7f0e50c1184c5cfa1a54c7bd2b6848ed85d6 (patch)
treedb3e2c3656b64b4d4b6d6d1fdd6eddcba00e2b84
parent1a6ae3d692cfb52b21d0f45ba50b659486e53d6c (diff)
downloadrust-ddff7f0e50c1184c5cfa1a54c7bd2b6848ed85d6.tar.gz
rust-ddff7f0e50c1184c5cfa1a54c7bd2b6848ed85d6.zip
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.
-rw-r--r--library/std/src/sys/windows/fs.rs41
1 files 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,26 +1132,29 @@ 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.