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
This commit is contained in:
commit
34182470eb
4 changed files with 35 additions and 5 deletions
|
|
@ -2307,8 +2307,8 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
|
|||
///
|
||||
/// # Platform-specific behavior
|
||||
///
|
||||
/// This function currently corresponds to the `unlink` function on Unix
|
||||
/// and the `DeleteFile` function on Windows.
|
||||
/// This function currently corresponds to the `unlink` function on Unix.
|
||||
/// On Windows, `DeleteFile` is used or `CreateFileW` and `SetInformationByHandle` for readonly files.
|
||||
/// Note that, this [may change in the future][changes].
|
||||
///
|
||||
/// [changes]: io#platform-specific-behavior
|
||||
|
|
|
|||
|
|
@ -1384,7 +1384,7 @@ fn file_try_clone() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
#[cfg(not(target_vendor = "win7"))]
|
||||
fn unlink_readonly() {
|
||||
let tmpdir = tmpdir();
|
||||
let path = tmpdir.join("file");
|
||||
|
|
|
|||
|
|
@ -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<()> {
|
||||
|
|
|
|||
8
library/std/tests/win_delete_self.rs
Normal file
8
library/std/tests/win_delete_self.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#![cfg(windows)]
|
||||
|
||||
/// Attempting to delete a running binary should return an error on Windows.
|
||||
#[test]
|
||||
fn win_delete_self() {
|
||||
let path = std::env::current_exe().unwrap();
|
||||
assert!(std::fs::remove_file(path).is_err());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue