Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for os::windows::fs::MetadataExt on uwp #86075

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 63 additions & 31 deletions library/std/src/os/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,18 +288,22 @@ impl OpenOptionsExt for OpenOptions {

/// Windows-specific extensions to [`fs::Metadata`].
///
/// The data members that this trait exposes correspond to the members
/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
/// The members of this trait correspond to metadata exposed by calls to either
/// [`GetFileInformationByHandle`] or [`GetFileInformationByHandleEx`].
///
/// [`BY_HANDLE_FILE_INFORMATION`]:
/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the value of the `dwFileAttributes` field of this metadata.
/// Returns the file attributes of a file or directory;
/// corresponds to the `dwFileAttributes` field returned by [`GetFileInformationByHandle`],
/// or the `FileAttributes` field returned by [`GetFileInformationByHandleEx`].
///
/// This field contains the file system attribute information for a file
/// or directory. For possible values and their descriptions, see
/// [File Attribute Constants] in the Windows Dev Center.
/// For possible values and their descriptions, see [File Attribute Constants] in the Windows Dev Center.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
/// [File Attribute Constants]: https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
///
/// # Examples
///
Expand All @@ -314,13 +318,12 @@ pub trait MetadataExt {
/// Ok(())
/// }
/// ```
///
/// [File Attribute Constants]:
/// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn file_attributes(&self) -> u32;

/// Returns the value of the `ftCreationTime` field of this metadata.
/// Returns the creation time of a file or directory;
/// corresponds to the `ftCreationTime` field returned by [`GetFileInformationByHandle`],
/// or the `CreationTime` field returned by [`GetFileInformationByHandleEx`].
///
/// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
/// which represents the number of 100-nanosecond intervals since
Expand All @@ -331,6 +334,10 @@ pub trait MetadataExt {
/// If the underlying filesystem does not support creation time, the
/// returned value is 0.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
///
/// # Examples
///
/// ```no_run
Expand All @@ -344,12 +351,12 @@ pub trait MetadataExt {
/// Ok(())
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn creation_time(&self) -> u64;

/// Returns the value of the `ftLastAccessTime` field of this metadata.
/// Returns the last access time of a file or directory;
/// corresponds to the `ftLastAccessTime` field returned by [`GetFileInformationByHandle`],
/// or the `LastAccessTime` field returned by [`GetFileInformationByHandleEx`].
///
/// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
/// which represents the number of 100-nanosecond intervals since
Expand All @@ -366,6 +373,10 @@ pub trait MetadataExt {
/// If the underlying filesystem does not support last access time, the
/// returned value is 0.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
///
/// # Examples
///
/// ```no_run
Expand All @@ -379,12 +390,12 @@ pub trait MetadataExt {
/// Ok(())
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn last_access_time(&self) -> u64;

/// Returns the value of the `ftLastWriteTime` field of this metadata.
/// Returns the last write time of a file or directory;
/// corresponds to the `ftLastWriteTime` field returned by [`GetFileInformationByHandle`],
/// or the `LastWriteTime` field returned by [`GetFileInformationByHandleEx`].
///
/// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
/// which represents the number of 100-nanosecond intervals since
Expand All @@ -399,6 +410,10 @@ pub trait MetadataExt {
/// If the underlying filesystem does not support the last write time,
/// the returned value is 0.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
///
/// # Examples
///
/// ```no_run
Expand All @@ -412,16 +427,18 @@ pub trait MetadataExt {
/// Ok(())
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn last_write_time(&self) -> u64;

/// Returns the value of the `nFileSize{High,Low}` fields of this
/// metadata.
/// Returns the size of a file;
/// corresponds to the `nFileSize{High,Low}` fields returned by [`GetFileInformationByHandle`],
/// or the `AllocationSize` field returned by [`GetFileInformationByHandleEx`].
///
/// The returned value does not have meaning for directories.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
///
/// # Examples
///
/// ```no_run
Expand All @@ -438,32 +455,47 @@ pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn file_size(&self) -> u64;

/// Returns the value of the `dwVolumeSerialNumber` field of this
/// metadata.
/// Returns the volume serial number of a file or directory;
/// corresponds to the `dwVolumeSerialNumber` field returned by [`GetFileInformationByHandle`],
/// or the `VolumeSerialNumber` field returned by [`GetFileInformationByHandleEx`].
///
/// This will return `None` if the `Metadata` instance was created from a
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn volume_serial_number(&self) -> Option<u32>;

/// Returns the value of the `nNumberOfLinks` field of this
/// metadata.
/// Returns the number of links to a file or directory;
/// corresponds to the `nNumberOfLinks` field returned by [`GetFileInformationByHandle`],
/// or the `NumberOfLinks` field returned by [`GetFileInformationByHandleEx`].
///
/// This will return `None` if the `Metadata` instance was created from a
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn number_of_links(&self) -> Option<u32>;

/// Returns the value of the `nFileIndex{Low,High}` fields of this
/// metadata.
/// Returns the file identifier of a file or directory;
/// corresponds to the `nFileIndex{Low,High}` fields returned by [`GetFileInformationByHandle`],
/// or the `FileId` field returned by [`GetFileInformationByHandleEx`].
///
/// Note that this is a `u128`, since `GetFileInformationByHandle` returns a 64-bit value,
/// and `GetFileInformationByHandleEx` returns a 128-bit value.
///
/// This will return `None` if the `Metadata` instance was created from a
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
///
/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
/// [`GetFileInformationByHandleEx`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn file_index(&self) -> Option<u64>;
fn file_identifier(&self) -> Option<u128>;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
Expand All @@ -489,8 +521,8 @@ impl MetadataExt for Metadata {
fn number_of_links(&self) -> Option<u32> {
self.as_inner().number_of_links()
}
fn file_index(&self) -> Option<u64> {
self.as_inner().file_index()
fn file_identifier(&self) -> Option<u128> {
self.as_inner().file_identifier()
}
}

Expand Down
9 changes: 9 additions & 0 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,9 @@ if #[cfg(not(target_vendor = "uwp"))] {
// UWP specific functions & types
cfg_if::cfg_if! {
if #[cfg(target_vendor = "uwp")] {
use use crate::os::raw::c_ulonglong;
pub type ULONGLONG = c_ulonglong;

pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002;

#[repr(C)]
Expand All @@ -769,6 +772,12 @@ if #[cfg(target_vendor = "uwp")] {
pub Directory: BOOLEAN,
}

#[repr(C)]
pub struct FILE_ID_INFO {
pub VolumeSerialNumber: ULONGLONG,
pub FileId: u128
}

#[link(name = "bcrypt")]
extern "system" {
pub fn BCryptGenRandom(
Expand Down
24 changes: 17 additions & 7 deletions library/std/src/sys/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct FileAttr {
reparse_tag: c::DWORD,
volume_serial_number: Option<u32>,
number_of_links: Option<u32>,
file_index: Option<u64>,
file_identifier: Option<u128>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -163,7 +163,7 @@ impl DirEntry {
},
volume_serial_number: None,
number_of_links: None,
file_index: None,
file_identifier: None,
})
}
}
Expand Down Expand Up @@ -343,8 +343,8 @@ impl File {
reparse_tag,
volume_serial_number: Some(info.dwVolumeSerialNumber),
number_of_links: Some(info.nNumberOfLinks),
file_index: Some(
(info.nFileIndexLow as u64) | ((info.nFileIndexHigh as u64) << 32),
file_identifier: Some(
((info.nFileIndexLow as u64) | ((info.nFileIndexHigh as u64) << 32)) as u128,
),
})
}
Expand Down Expand Up @@ -379,7 +379,7 @@ impl File {
reparse_tag: 0,
volume_serial_number: None,
number_of_links: None,
file_index: None,
file_identifier: None,
};
let mut info: c::FILE_STANDARD_INFO = mem::zeroed();
let size = mem::size_of_val(&info);
Expand All @@ -397,6 +397,16 @@ impl File {
attr.reparse_tag = buf.ReparseTag;
}
}
let mut info: c::FILE_ID_INFO = mem::zeroed();
let size = mem::size_of_val(&info);
cvt(c::GetFileInformationByHandleEx(
self.handle.raw(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given I/O safety has been merged, as_raw_handle should be used instead of raw.

c::FileIdInfo,
&mut info as *mut _ as *mut libc::c_void,
size as c::DWORD,
))?;
attr.volume_serial_number = Some(info.VolumeSerialNumber);
attr.file_identifier = Some(info.FileId);
Ok(attr)
}
}
Expand Down Expand Up @@ -618,8 +628,8 @@ impl FileAttr {
self.number_of_links
}

pub fn file_index(&self) -> Option<u64> {
self.file_index
pub fn file_identifier(&self) -> Option<u128> {
self.file_identifier
}
}

Expand Down