diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 3dcde43cfec7..7fd90cdb2750 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -298,7 +298,7 @@ impl OpenOptionsExt for OpenOptions { /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// /// [`BY_HANDLE_FILE_INFORMATION`]: -/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information +/// https://docs.microsoft.com/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the value of the `dwFileAttributes` field of this metadata. @@ -322,7 +322,7 @@ pub trait MetadataExt { /// ``` /// /// [File Attribute Constants]: - /// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants + /// https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_attributes(&self) -> u32; @@ -351,7 +351,7 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn creation_time(&self) -> u64; @@ -386,7 +386,7 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_access_time(&self) -> u64; @@ -419,7 +419,7 @@ pub trait MetadataExt { /// } /// ``` /// - /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime + /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_write_time(&self) -> u64; @@ -471,10 +471,21 @@ pub trait MetadataExt { #[unstable(feature = "windows_by_handle", issue = "63010")] fn file_index(&self) -> Option; - /// Returns the change time, which is the last time file metadata was changed, such as - /// renames, attributes, etc - /// - /// This will return `None` if the `Metadata` instance was not created using the `FILE_BASIC_INFO` type. + /// Returns the value of the `ChangeTime{Low,High}` field from the + /// [`FILE_BASIC_INFO`] struct associated with the current file handle. + /// [`ChangeTime`], is the last time file metadata was changed, such as + /// renames, attributes, etc. + /// + /// This will return `None` if `Metadata` was populated without access to + /// [`FILE_BASIC_INFO`]. For example, the result of `std::fs::read_dir` + /// will be derived from [`WIN32_FIND_DATA`] which does not have access to + /// `ChangeTime`. + /// + /// [`FILE_BASIC_INFO`]: https://learn.microsoft.com/windows/win32/api/winbase/ns-winbase-file_basic_info + /// [`WIN32_FIND_DATA`]: https://learn.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw + /// [`FindFirstFile`]: https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-findfirstfilea + /// [`FindNextFile`]: https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-findnextfilea + /// [`ChangeTime`]: https://devblogs.microsoft.com/oldnewthing/20100709-00/?p=13463#:~:text=I%E2%80%99m%20told%20that%20the%20difference%20is%20metadata.%20The,attributes%20%28hidden%2C%20read-only%2C%20etc.%29%20or%20renaming%20the%20file. #[unstable(feature = "windows_change_time", issue = "121478")] fn change_time(&self) -> Option; } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 5b360640c4e6..ee2d92a231eb 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -371,12 +371,19 @@ impl File { reparse_tag = attr_tag.ReparseTag; } } + + // FILE_BASIC_INFO contains additional fields not returned by GetFileInformationByHandle + let basic_info = self.basic_info()?; + Ok(FileAttr { attributes: info.dwFileAttributes, creation_time: info.ftCreationTime, last_access_time: info.ftLastAccessTime, last_write_time: info.ftLastWriteTime, - change_time: None, // Only available in FILE_BASIC_INFO + change_time: Some(c::FILETIME { + dwLowDateTime: basic_info.ChangeTime as u32, + dwHighDateTime: (basic_info.ChangeTime >> 32) as u32, + }), file_size: (info.nFileSizeLow as u64) | ((info.nFileSizeHigh as u64) << 32), reparse_tag, volume_serial_number: Some(info.dwVolumeSerialNumber), @@ -391,14 +398,7 @@ impl File { #[cfg(target_vendor = "uwp")] pub fn file_attr(&self) -> io::Result { unsafe { - let mut info: c::FILE_BASIC_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); - cvt(c::GetFileInformationByHandleEx( - self.handle.as_raw_handle(), - c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, - size as u32, - ))?; + let mut info: c::FILE_BASIC_INFO = self.basic_info()?; let mut attr = FileAttr { attributes: info.FileAttributes, creation_time: c::FILETIME {