winapi_util/
file.rs

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