use std::{io, mem};
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Foundation::{GetLastError, FILETIME, NO_ERROR};
use windows_sys::Win32::Storage::FileSystem::{
GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION,
FILE_ATTRIBUTE_HIDDEN,
};
use crate::AsHandleRef;
pub fn information<H: AsHandleRef>(h: H) -> io::Result<Information> {
unsafe {
let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed();
let rc = GetFileInformationByHandle(h.as_raw() as HANDLE, &mut info);
if rc == 0 {
return Err(io::Error::last_os_error());
};
Ok(Information(info))
}
}
pub fn typ<H: AsHandleRef>(h: H) -> io::Result<Type> {
unsafe {
let rc = GetFileType(h.as_raw() as HANDLE);
if rc == 0 && GetLastError() != NO_ERROR {
return Err(io::Error::last_os_error());
}
Ok(Type(rc))
}
}
pub fn is_hidden(file_attributes: u64) -> bool {
file_attributes & (FILE_ATTRIBUTE_HIDDEN as u64) > 0
}
#[derive(Clone)]
pub struct Information(BY_HANDLE_FILE_INFORMATION);
impl Information {
pub fn file_attributes(&self) -> u64 {
self.0.dwFileAttributes as u64
}
pub fn is_hidden(&self) -> bool {
is_hidden(self.file_attributes())
}
pub fn creation_time(&self) -> Option<u64> {
filetime_to_u64(self.0.ftCreationTime)
}
pub fn last_access_time(&self) -> Option<u64> {
filetime_to_u64(self.0.ftLastAccessTime)
}
pub fn last_write_time(&self) -> Option<u64> {
filetime_to_u64(self.0.ftLastWriteTime)
}
pub fn volume_serial_number(&self) -> u64 {
self.0.dwVolumeSerialNumber as u64
}
pub fn file_size(&self) -> u64 {
((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64)
}
pub fn number_of_links(&self) -> u64 {
self.0.nNumberOfLinks as u64
}
pub fn file_index(&self) -> u64 {
((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64)
}
}
#[derive(Clone)]
pub struct Type(u32);
impl Type {
pub fn is_char(&self) -> bool {
self.0 == ::windows_sys::Win32::Storage::FileSystem::FILE_TYPE_CHAR
}
pub fn is_disk(&self) -> bool {
self.0 == ::windows_sys::Win32::Storage::FileSystem::FILE_TYPE_DISK
}
pub fn is_pipe(&self) -> bool {
self.0 == ::windows_sys::Win32::Storage::FileSystem::FILE_TYPE_PIPE
}
pub fn is_unknown(&self) -> bool {
self.0 == ::windows_sys::Win32::Storage::FileSystem::FILE_TYPE_UNKNOWN
}
}
fn filetime_to_u64(t: FILETIME) -> Option<u64> {
let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64);
if v == 0 {
None
} else {
Some(v)
}
}