about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
authorUrgau <3616612+Urgau@users.noreply.github.com>2025-02-09 00:37:26 +0100
committerGitHub <noreply@github.com>2025-02-09 00:37:26 +0100
commit34182470ebbc0c8fd67f09c7902b3bd44f4abbe5 (patch)
tree7d939978e6272a27d5e64358662e8176c5725a45 /library/std/src/sys
parent73bf7947e9ab731bf2764db219cd9cda216a3aed (diff)
parent962ebf0a48436445cf300efc0fa552044f4ca19d (diff)
downloadrust-34182470ebbc0c8fd67f09c7902b3bd44f4abbe5.tar.gz
rust-34182470ebbc0c8fd67f09c7902b3bd44f4abbe5.zip
Rollup merge of #134679 - ChrisDenton:rm-readonly, r=Mark-Simulacrum
Windows: remove readonly files

When calling `remove_file`, we shouldn't fail to delete readonly files. As the test makes clear, this make the Windows behaviour consistent with other platforms. This also makes us internally consistent with `remove_dir_all`.

try-job: x86_64-msvc-ext1
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/pal/windows/fs.rs26
1 files changed, 24 insertions, 2 deletions
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index f8493c21ad4..bdb55643bb1 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -296,6 +296,10 @@ impl OpenOptions {
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
         let path = maybe_verbatim(path)?;
+        Self::open_native(&path, opts)
+    }
+
+    fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result<File> {
         let creation = opts.get_creation_mode()?;
         let handle = unsafe {
             c::CreateFileW(
@@ -1226,8 +1230,26 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 
 pub fn unlink(p: &Path) -> io::Result<()> {
     let p_u16s = maybe_verbatim(p)?;
-    cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?;
-    Ok(())
+    if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 {
+        let err = api::get_last_error();
+        // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove
+        // the file while ignoring the readonly attribute.
+        // This is accomplished by calling the `posix_delete` function on an open file handle.
+        if err == WinError::ACCESS_DENIED {
+            let mut opts = OpenOptions::new();
+            opts.access_mode(c::DELETE);
+            opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT);
+            if let Ok(f) = File::open_native(&p_u16s, &opts) {
+                if f.posix_delete().is_ok() {
+                    return Ok(());
+                }
+            }
+        }
+        // return the original error if any of the above fails.
+        Err(io::Error::from_raw_os_error(err.code as i32))
+    } else {
+        Ok(())
+    }
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {