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