diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index b445f368aeb12..95a4ea53ce1e5 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -305,6 +305,18 @@ pub trait OpenOptionsExt { /// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut Self; + + /// If set to `true`, prevent the "last access time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self; + + /// If set to `true`, prevent the "last write time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self; } #[stable(feature = "open_options_ext", since = "1.10.0")] @@ -333,6 +345,16 @@ impl OpenOptionsExt for OpenOptions { self.as_inner_mut().security_qos_flags(flags); self } + + fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self { + self.as_inner_mut().freeze_last_access_time(freeze); + self + } + + fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self { + self.as_inner_mut().freeze_last_write_time(freeze); + self + } } /// Windows-specific extensions to [`fs::Metadata`]. diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index f2d325da35c7d..e214284a03a74 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -81,6 +81,8 @@ pub struct OpenOptions { share_mode: u32, security_qos_flags: u32, inherit_handle: bool, + freeze_last_access_time: bool, + freeze_last_write_time: bool, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -204,6 +206,8 @@ impl OpenOptions { attributes: 0, security_qos_flags: 0, inherit_handle: false, + freeze_last_access_time: false, + freeze_last_write_time: false, } } @@ -246,6 +250,12 @@ impl OpenOptions { pub fn inherit_handle(&mut self, inherit: bool) { self.inherit_handle = inherit; } + pub fn freeze_last_access_time(&mut self, freeze: bool) { + self.freeze_last_access_time = freeze; + } + pub fn freeze_last_write_time(&mut self, freeze: bool) { + self.freeze_last_write_time = freeze; + } fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append, self.access_mode) { @@ -343,6 +353,18 @@ impl File { }; let handle = unsafe { HandleOrInvalid::from_raw_handle(handle) }; if let Ok(handle) = OwnedHandle::try_from(handle) { + if opts.freeze_last_access_time || opts.freeze_last_write_time { + let file_time = + c::FILETIME { dwLowDateTime: 0xFFFFFFFF, dwHighDateTime: 0xFFFFFFFF }; + cvt(unsafe { + c::SetFileTime( + handle.as_raw_handle(), + core::ptr::null(), + if opts.freeze_last_access_time { &file_time } else { core::ptr::null() }, + if opts.freeze_last_write_time { &file_time } else { core::ptr::null() }, + ) + })?; + } // Manual truncation. See #115745. if opts.truncate && creation == c::OPEN_ALWAYS