Rollup merge of #149718 - windows_freeze_file_times, r=ChrisDenton

Add freeze file times on Windows

This PR add two new methods on [OpenOptionsExt](https://doc.rust-lang.org/stable/std/os/windows/fs/trait.OpenOptionsExt.html) in order to not change the "last access time" and "last write time" of the file on Windows.

- Tracking Issue: https://github.com/rust-lang/rust/issues/149715
- ACP: https://github.com/rust-lang/libs-team/issues/708
This commit is contained in:
Matthias Krüger 2026-01-12 00:02:52 +01:00 committed by GitHub
commit e1c13ff160
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 0 deletions

View file

@ -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`].

View file

@ -82,6 +82,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)]
@ -205,6 +207,8 @@ impl OpenOptions {
attributes: 0,
security_qos_flags: 0,
inherit_handle: false,
freeze_last_access_time: false,
freeze_last_write_time: false,
}
}
@ -247,6 +251,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<u32> {
match (self.read, self.write, self.append, self.access_mode) {
@ -352,6 +362,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