about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2019-07-25 09:44:04 -0700
committerAlex Crichton <alex@alexcrichton.com>2019-07-26 07:35:59 -0700
commitc69f367bafb3a2f90d44fe54fc20d57996fa294a (patch)
tree7357175a38b067541a03d76c4d27a277d5c5f765
parent1a563362865e6051d4c350544131228e8eff5138 (diff)
downloadrust-c69f367bafb3a2f90d44fe54fc20d57996fa294a.tar.gz
rust-c69f367bafb3a2f90d44fe54fc20d57996fa294a.zip
std: Add more accessors for `Metadata` on Windows
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!
-rw-r--r--src/libstd/sys/windows/ext/fs.rs30
-rw-r--r--src/libstd/sys/windows/fs.rs55
2 files changed, 69 insertions, 16 deletions
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index 268a14ff0aa..23964dc5bd5 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -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")]
@@ -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`].
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 2f158c01406..5bae6ba4749 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -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)]
@@ -156,6 +159,9 @@ impl DirEntry {
                 } else {
                     0
                 },
+            volume_serial_number: None,
+            number_of_links: None,
+            file_index: None,
         })
     }
 }
@@ -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)),
+            })
         }
     }
 
@@ -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);
@@ -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) {
@@ -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)
@@ -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
     }
 }