1 use std::io;
2 use std::mem;
3 
4 use winapi::shared::minwindef::FILETIME;
5 use winapi::shared::winerror::NO_ERROR;
6 use winapi::um::errhandlingapi::GetLastError;
7 use winapi::um::fileapi::{
8     GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION,
9 };
10 use winapi::um::winnt;
11 
12 use crate::AsHandleRef;
13 
14 /// Return various pieces of information about a file.
15 ///
16 /// This includes information such as a file's size, unique identifier and
17 /// time related fields.
18 ///
19 /// This corresponds to calling [`GetFileInformationByHandle`].
20 ///
21 /// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle
information<H: AsHandleRef>(h: H) -> io::Result<Information>22 pub fn information<H: AsHandleRef>(h: H) -> io::Result<Information> {
23     unsafe {
24         let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed();
25         let rc = GetFileInformationByHandle(h.as_raw(), &mut info);
26         if rc == 0 {
27             return Err(io::Error::last_os_error());
28         };
29         Ok(Information(info))
30     }
31 }
32 
33 /// Returns the file type of the given handle.
34 ///
35 /// If there was a problem querying the file type, then an error is returned.
36 ///
37 /// This corresponds to calling [`GetFileType`].
38 ///
39 /// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype
typ<H: AsHandleRef>(h: H) -> io::Result<Type>40 pub fn typ<H: AsHandleRef>(h: H) -> io::Result<Type> {
41     unsafe {
42         let rc = GetFileType(h.as_raw());
43         if rc == 0 && GetLastError() != NO_ERROR {
44             return Err(io::Error::last_os_error());
45         }
46         Ok(Type(rc))
47     }
48 }
49 
50 /// Returns true if and only if the given file attributes contain the
51 /// `FILE_ATTRIBUTE_HIDDEN` attribute.
is_hidden(file_attributes: u64) -> bool52 pub fn is_hidden(file_attributes: u64) -> bool {
53     file_attributes & (winnt::FILE_ATTRIBUTE_HIDDEN as u64) > 0
54 }
55 
56 /// Represents file information such as creation time, file size, etc.
57 ///
58 /// This wraps a [`BY_HANDLE_FILE_INFORMATION`].
59 ///
60 /// [`BY_HANDLE_FILE_INFORMATION`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information
61 #[derive(Clone)]
62 pub struct Information(BY_HANDLE_FILE_INFORMATION);
63 
64 impl Information {
65     /// Returns file attributes.
66     ///
67     /// This corresponds to `dwFileAttributes`.
file_attributes(&self) -> u6468     pub fn file_attributes(&self) -> u64 {
69         self.0.dwFileAttributes as u64
70     }
71 
72     /// Returns true if and only if this file information has the
73     /// `FILE_ATTRIBUTE_HIDDEN` attribute.
is_hidden(&self) -> bool74     pub fn is_hidden(&self) -> bool {
75         is_hidden(self.file_attributes())
76     }
77 
78     /// Return the creation time, if one exists.
79     ///
80     /// This corresponds to `ftCreationTime`.
creation_time(&self) -> Option<u64>81     pub fn creation_time(&self) -> Option<u64> {
82         filetime_to_u64(self.0.ftCreationTime)
83     }
84 
85     /// Return the last access time, if one exists.
86     ///
87     /// This corresponds to `ftLastAccessTime`.
last_access_time(&self) -> Option<u64>88     pub fn last_access_time(&self) -> Option<u64> {
89         filetime_to_u64(self.0.ftLastAccessTime)
90     }
91 
92     /// Return the last write time, if one exists.
93     ///
94     /// This corresponds to `ftLastWriteTime`.
last_write_time(&self) -> Option<u64>95     pub fn last_write_time(&self) -> Option<u64> {
96         filetime_to_u64(self.0.ftLastWriteTime)
97     }
98 
99     /// Return the serial number of the volume that the file is on.
100     ///
101     /// This corresponds to `dwVolumeSerialNumber`.
volume_serial_number(&self) -> u64102     pub fn volume_serial_number(&self) -> u64 {
103         self.0.dwVolumeSerialNumber as u64
104     }
105 
106     /// Return the file size, in bytes.
107     ///
108     /// This corresponds to `nFileSizeHigh` and `nFileSizeLow`.
file_size(&self) -> u64109     pub fn file_size(&self) -> u64 {
110         ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64)
111     }
112 
113     /// Return the number of links to this file.
114     ///
115     /// This corresponds to `nNumberOfLinks`.
number_of_links(&self) -> u64116     pub fn number_of_links(&self) -> u64 {
117         self.0.nNumberOfLinks as u64
118     }
119 
120     /// Return the index of this file. The index of a file is a purpotedly
121     /// unique identifier for a file within a particular volume.
file_index(&self) -> u64122     pub fn file_index(&self) -> u64 {
123         ((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64)
124     }
125 }
126 
127 /// Represents a Windows file type.
128 ///
129 /// This wraps the result of [`GetFileType`].
130 ///
131 /// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype
132 #[derive(Clone)]
133 pub struct Type(u32);
134 
135 impl Type {
136     /// Returns true if this type represents a character file, which is
137     /// typically an LPT device or a console.
is_char(&self) -> bool138     pub fn is_char(&self) -> bool {
139         self.0 == ::winapi::um::winbase::FILE_TYPE_CHAR
140     }
141 
142     /// Returns true if this type represents a disk file.
is_disk(&self) -> bool143     pub fn is_disk(&self) -> bool {
144         self.0 == ::winapi::um::winbase::FILE_TYPE_DISK
145     }
146 
147     /// Returns true if this type represents a sock, named pipe or an
148     /// anonymous pipe.
is_pipe(&self) -> bool149     pub fn is_pipe(&self) -> bool {
150         self.0 == ::winapi::um::winbase::FILE_TYPE_PIPE
151     }
152 
153     /// Returns true if this type is not known.
154     ///
155     /// Note that this never corresponds to a failure.
is_unknown(&self) -> bool156     pub fn is_unknown(&self) -> bool {
157         self.0 == ::winapi::um::winbase::FILE_TYPE_UNKNOWN
158     }
159 }
160 
filetime_to_u64(t: FILETIME) -> Option<u64>161 fn filetime_to_u64(t: FILETIME) -> Option<u64> {
162     let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64);
163     if v == 0 {
164         None
165     } else {
166         Some(v)
167     }
168 }
169