Skip to content

Commit

Permalink
std: Add more accessors for Metadata on Windows
Browse files Browse the repository at this point in the history
This commit adds accessors for more fields in `fs::Metadata` on Windows
which weren't previously exposed. There's two sources of `fs::Metadata`
on Windows currently, one from `DirEntry` and one from a file itself.
These two sources of information don't actually have the same set of
fields exposed in their stat information, however. To handle this the
platform-specific accessors of Windows-specific information all return
`Option` to return `None` in the case a metadata comes from a
`DirEntry`, but they're guaranteed to return `Some` if it comes from a
file itself.

This is motivated by some changes in CraneStation/wasi-common#42, and
I'm curious how others feel about this platform-specific functionality!
  • Loading branch information
alexcrichton committed Jul 26, 2019
1 parent 1a56336 commit c69f367
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 16 deletions.
30 changes: 30 additions & 0 deletions src/libstd/sys/windows/ext/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,33 @@ 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.
///
/// 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`.
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn volume_serial_number(&self) -> Option<u32>;

/// Returns the value of the `nNumberOfLinks` field of this
/// metadata.
///
/// 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`.
#[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.
///
/// 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`.
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn file_index(&self) -> Option<u64>;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
Expand All @@ -446,6 +473,9 @@ impl MetadataExt for Metadata {
fn last_access_time(&self) -> u64 { self.as_inner().accessed_u64() }
fn last_write_time(&self) -> u64 { self.as_inner().modified_u64() }
fn file_size(&self) -> u64 { self.as_inner().size() }
fn volume_serial_number(&self) -> Option<u32> { self.as_inner().volume_serial_number() }
fn number_of_links(&self) -> Option<u32> { self.as_inner().number_of_links() }
fn file_index(&self) -> Option<u64> { self.as_inner().file_index() }
}

/// Windows-specific extensions to [`FileType`].
Expand Down
55 changes: 39 additions & 16 deletions src/libstd/sys/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub struct FileAttr {
last_write_time: c::FILETIME,
file_size: u64,
reparse_tag: c::DWORD,
volume_serial_number: Option<u32>,
number_of_links: Option<u32>,
file_index: Option<u64>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -156,6 +159,9 @@ impl DirEntry {
} else {
0
},
volume_serial_number: None,
number_of_links: None,
file_index: None,
})
}
}
Expand Down Expand Up @@ -291,23 +297,26 @@ impl File {
pub fn file_attr(&self) -> io::Result<FileAttr> {
unsafe {
let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed();
cvt(c::GetFileInformationByHandle(self.handle.raw(),
&mut info))?;
let mut attr = FileAttr {
attributes: info.dwFileAttributes,
creation_time: info.ftCreationTime,
last_access_time: info.ftLastAccessTime,
last_write_time: info.ftLastWriteTime,
file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64),
reparse_tag: 0,
};
if attr.is_reparse_point() {
cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?;
let mut reparse_tag = 0;
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
if let Ok((_, buf)) = self.reparse_point(&mut b) {
attr.reparse_tag = buf.ReparseTag;
reparse_tag = buf.ReparseTag;
}
}
Ok(attr)
Ok(FileAttr {
attributes: info.dwFileAttributes,
creation_time: info.ftCreationTime,
last_access_time: info.ftLastAccessTime,
last_write_time: info.ftLastWriteTime,
file_size: (info.nFileSizeLow as u64) | ((info.nFileSizeHigh as u64) << 32),
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)),
})
}
}

Expand Down Expand Up @@ -336,6 +345,9 @@ impl File {
},
file_size: 0,
reparse_tag: 0,
volume_serial_number: None,
number_of_links: None,
file_index: None,
};
let mut info: c::FILE_STANDARD_INFO = mem::zeroed();
let size = mem::size_of_val(&info);
Expand All @@ -344,6 +356,7 @@ impl File {
&mut info as *mut _ as *mut libc::c_void,
size as c::DWORD))?;
attr.file_size = info.AllocationSize as u64;
attr.number_of_links = Some(info.NumberOfLinks);
if attr.is_reparse_point() {
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
if let Ok((_, buf)) = self.reparse_point(&mut b) {
Expand Down Expand Up @@ -507,7 +520,9 @@ impl FileAttr {
FilePermissions { attrs: self.attributes }
}

pub fn attrs(&self) -> u32 { self.attributes as u32 }
pub fn attrs(&self) -> u32 {
self.attributes
}

pub fn file_type(&self) -> FileType {
FileType::new(self.attributes, self.reparse_tag)
Expand Down Expand Up @@ -537,8 +552,16 @@ impl FileAttr {
to_u64(&self.creation_time)
}

fn is_reparse_point(&self) -> bool {
self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
pub fn volume_serial_number(&self) -> Option<u32> {
self.volume_serial_number
}

pub fn number_of_links(&self) -> Option<u32> {
self.number_of_links
}

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

Expand Down

0 comments on commit c69f367

Please sign in to comment.