use std::io; use std::mem; use winapi::shared::minwindef::FILETIME; use winapi::shared::winerror::NO_ERROR; use winapi::um::errhandlingapi::GetLastError; use winapi::um::fileapi::{ GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION, }; use winapi::um::winnt; use crate::AsHandleRef; /// Return various pieces of information about a file. /// /// This includes information such as a file's size, unique identifier and /// time related fields. /// /// This corresponds to calling [`GetFileInformationByHandle`]. /// /// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle pub fn information(h: H) -> io::Result { unsafe { let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed(); let rc = GetFileInformationByHandle(h.as_raw(), &mut info); if rc == 0 { return Err(io::Error::last_os_error()); }; Ok(Information(info)) } } /// Returns the file type of the given handle. /// /// If there was a problem querying the file type, then an error is returned. /// /// This corresponds to calling [`GetFileType`]. /// /// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype pub fn typ(h: H) -> io::Result { unsafe { let rc = GetFileType(h.as_raw()); if rc == 0 && GetLastError() != NO_ERROR { return Err(io::Error::last_os_error()); } Ok(Type(rc)) } } /// Returns true if and only if the given file attributes contain the /// `FILE_ATTRIBUTE_HIDDEN` attribute. pub fn is_hidden(file_attributes: u64) -> bool { file_attributes & (winnt::FILE_ATTRIBUTE_HIDDEN as u64) > 0 } /// Represents file information such as creation time, file size, etc. /// /// This wraps a [`BY_HANDLE_FILE_INFORMATION`]. /// /// [`BY_HANDLE_FILE_INFORMATION`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information #[derive(Clone)] pub struct Information(BY_HANDLE_FILE_INFORMATION); impl Information { /// Returns file attributes. /// /// This corresponds to `dwFileAttributes`. pub fn file_attributes(&self) -> u64 { self.0.dwFileAttributes as u64 } /// Returns true if and only if this file information has the /// `FILE_ATTRIBUTE_HIDDEN` attribute. pub fn is_hidden(&self) -> bool { is_hidden(self.file_attributes()) } /// Return the creation time, if one exists. /// /// This corresponds to `ftCreationTime`. pub fn creation_time(&self) -> Option { filetime_to_u64(self.0.ftCreationTime) } /// Return the last access time, if one exists. /// /// This corresponds to `ftLastAccessTime`. pub fn last_access_time(&self) -> Option { filetime_to_u64(self.0.ftLastAccessTime) } /// Return the last write time, if one exists. /// /// This corresponds to `ftLastWriteTime`. pub fn last_write_time(&self) -> Option { filetime_to_u64(self.0.ftLastWriteTime) } /// Return the serial number of the volume that the file is on. /// /// This corresponds to `dwVolumeSerialNumber`. pub fn volume_serial_number(&self) -> u64 { self.0.dwVolumeSerialNumber as u64 } /// Return the file size, in bytes. /// /// This corresponds to `nFileSizeHigh` and `nFileSizeLow`. pub fn file_size(&self) -> u64 { ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64) } /// Return the number of links to this file. /// /// This corresponds to `nNumberOfLinks`. pub fn number_of_links(&self) -> u64 { self.0.nNumberOfLinks as u64 } /// Return the index of this file. The index of a file is a purpotedly /// unique identifier for a file within a particular volume. pub fn file_index(&self) -> u64 { ((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64) } } /// Represents a Windows file type. /// /// This wraps the result of [`GetFileType`]. /// /// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype #[derive(Clone)] pub struct Type(u32); impl Type { /// Returns true if this type represents a character file, which is /// typically an LPT device or a console. pub fn is_char(&self) -> bool { self.0 == ::winapi::um::winbase::FILE_TYPE_CHAR } /// Returns true if this type represents a disk file. pub fn is_disk(&self) -> bool { self.0 == ::winapi::um::winbase::FILE_TYPE_DISK } /// Returns true if this type represents a sock, named pipe or an /// anonymous pipe. pub fn is_pipe(&self) -> bool { self.0 == ::winapi::um::winbase::FILE_TYPE_PIPE } /// Returns true if this type is not known. /// /// Note that this never corresponds to a failure. pub fn is_unknown(&self) -> bool { self.0 == ::winapi::um::winbase::FILE_TYPE_UNKNOWN } } fn filetime_to_u64(t: FILETIME) -> Option { let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64); if v == 0 { None } else { Some(v) } }