diff options
| author | Chris Denton <chris@chrisdenton.dev> | 2023-10-05 03:15:50 +0100 |
|---|---|---|
| committer | Chris Denton <chris@chrisdenton.dev> | 2023-10-15 10:51:20 +0100 |
| commit | c6f7aa0eea9af919ade663bb3a4bb4b6761c3f83 (patch) | |
| tree | 985834a80c3f400598bb62dfd83bf3271cbf0799 /library/std/src/sys/windows | |
| parent | b0fedc07ce52a7647272a34fadbf4c5585a79c0b (diff) | |
| download | rust-c6f7aa0eea9af919ade663bb3a4bb4b6761c3f83.tar.gz rust-c6f7aa0eea9af919ade663bb3a4bb4b6761c3f83.zip | |
Make File::create work on Windows hidden files
Previously it failed on Windows if the file had the `FILE_ATTRIBUTE_HIDDEN` attribute set. This was inconsistent with `OpenOptions::new().write(true).truncate(true)` which can truncate an existing hidden file.
Diffstat (limited to 'library/std/src/sys/windows')
| -rw-r--r-- | library/std/src/sys/windows/c/windows_sys.lst | 1 | ||||
| -rw-r--r-- | library/std/src/sys/windows/c/windows_sys.rs | 10 | ||||
| -rw-r--r-- | library/std/src/sys/windows/fs.rs | 33 |
3 files changed, 38 insertions, 6 deletions
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst index dad4a4223b2..31e5de4bce4 100644 --- a/library/std/src/sys/windows/c/windows_sys.lst +++ b/library/std/src/sys/windows/c/windows_sys.lst @@ -2224,6 +2224,7 @@ Windows.Win32.Storage.FileSystem.FILE_ACCESS_RIGHTS Windows.Win32.Storage.FileSystem.FILE_ADD_FILE Windows.Win32.Storage.FileSystem.FILE_ADD_SUBDIRECTORY Windows.Win32.Storage.FileSystem.FILE_ALL_ACCESS +Windows.Win32.Storage.FileSystem.FILE_ALLOCATION_INFO Windows.Win32.Storage.FileSystem.FILE_APPEND_DATA Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_ARCHIVE Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_COMPRESSED diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs index 20b44966a39..a3400eb3ac6 100644 --- a/library/std/src/sys/windows/c/windows_sys.rs +++ b/library/std/src/sys/windows/c/windows_sys.rs @@ -3107,6 +3107,16 @@ impl ::core::clone::Clone for FILETIME { pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; +#[repr(C)] +pub struct FILE_ALLOCATION_INFO { + pub AllocationSize: i64, +} +impl ::core::marker::Copy for FILE_ALLOCATION_INFO {} +impl ::core::clone::Clone for FILE_ALLOCATION_INFO { + fn clone(&self) -> Self { + *self + } +} pub const FILE_ALL_ACCESS: FILE_ACCESS_RIGHTS = 2032127u32; pub const FILE_APPEND_DATA: FILE_ACCESS_RIGHTS = 4u32; pub const FILE_ATTRIBUTE_ARCHIVE: FILE_FLAGS_AND_ATTRIBUTES = 32u32; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 6ded683aade..75c7dc57c95 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::borrow::Cow; -use crate::ffi::OsString; +use crate::ffi::{c_void, OsString}; use crate::fmt; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit}; @@ -16,8 +16,6 @@ use crate::sys::{c, cvt, Align8}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::thread; -use core::ffi::c_void; - use super::path::maybe_verbatim; use super::to_u16s; @@ -273,7 +271,9 @@ impl OpenOptions { (false, false, false) => c::OPEN_EXISTING, (true, false, false) => c::OPEN_ALWAYS, (false, true, false) => c::TRUNCATE_EXISTING, - (true, true, false) => c::CREATE_ALWAYS, + // `CREATE_ALWAYS` has weird semantics so we emulate it using + // `OPEN_ALWAYS` and a manual truncation step. See #115745. + (true, true, false) => c::OPEN_ALWAYS, (_, _, true) => c::CREATE_NEW, }) } @@ -289,19 +289,40 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { let path = maybe_verbatim(path)?; + let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( path.as_ptr(), opts.get_access_mode()?, opts.share_mode, opts.security_attributes, - opts.get_creation_mode()?, + creation, opts.get_flags_and_attributes(), ptr::null_mut(), ) }; let handle = unsafe { HandleOrInvalid::from_raw_handle(handle) }; - if let Ok(handle) = handle.try_into() { + if let Ok(handle) = OwnedHandle::try_from(handle) { + // Manual truncation. See #115745. + if opts.truncate + && creation == c::OPEN_ALWAYS + && unsafe { c::GetLastError() } == c::ERROR_ALREADY_EXISTS + { + unsafe { + // Setting the allocation size to zero also sets the + // EOF position to zero. + let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; + let result = c::SetFileInformationByHandle( + handle.as_raw_handle(), + c::FileAllocationInfo, + ptr::addr_of!(alloc).cast::<c_void>(), + mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32, + ); + if result == 0 { + return Err(io::Error::last_os_error()); + } + } + } Ok(File { handle: Handle::from_inner(handle) }) } else { Err(Error::last_os_error()) |
