use crate::co;
use crate::decl::*;
use crate::guard::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileAccess {
ExistingReadOnly,
ExistingRW,
OpenOrCreateRW,
CreateRW,
}
impl std::fmt::Display for FileAccess {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
FileAccess::ExistingReadOnly => "Existing file, read-only",
FileAccess::ExistingRW => "Existing file, read and write",
FileAccess::OpenOrCreateRW =>
"Open existing file or create new file, read and write",
FileAccess::CreateRW => "Create new file, read and write",
}
)
}
}
pub struct File {
hfile: CloseHandleGuard<HFILE>,
}
impl File {
#[must_use]
pub fn open(file_path: &str, access: FileAccess) -> SysResult<Self> {
let (acc, share, disp) = match access {
FileAccess::ExistingReadOnly => {
(co::GENERIC::READ, Some(co::FILE_SHARE::READ), co::DISPOSITION::OPEN_EXISTING)
},
FileAccess::ExistingRW => {
(co::GENERIC::READ | co::GENERIC::WRITE, None, co::DISPOSITION::OPEN_EXISTING)
},
FileAccess::OpenOrCreateRW => {
(co::GENERIC::READ | co::GENERIC::WRITE, None, co::DISPOSITION::OPEN_ALWAYS)
},
FileAccess::CreateRW => {
(co::GENERIC::READ | co::GENERIC::WRITE, None, co::DISPOSITION::CREATE_NEW)
},
};
let (hfile, _) = HFILE::CreateFile(
file_path,
acc,
share,
None,
disp,
co::FILE_ATTRIBUTE::NORMAL,
None,
None,
None,
)?;
Ok(Self { hfile })
}
pub fn erase_and_write(&self, data: &[u8]) -> SysResult<()> {
self.set_size(0)?;
self.write(data)
}
#[must_use]
pub fn hfile(&self) -> &HFILE {
&*self.hfile
}
#[must_use]
pub fn pointer_offset(&self) -> SysResult<u64> {
self.hfile
.SetFilePointerEx(0, co::FILE_STARTING_POINT::CURRENT) .map(|off| off as _)
}
#[must_use]
pub fn read_all(&self) -> SysResult<Vec<u8>> {
self.set_pointer_offset(0)?;
let mut buf = vec![0x00; self.size()? as _];
self.read_buffer(&mut buf)?;
Ok(buf)
}
pub fn read_buffer(&self, buffer: &mut [u8]) -> SysResult<u32> {
self.hfile.ReadFile(buffer)
}
pub fn set_pointer_offset(&self, offset: u64) -> SysResult<()> {
self.hfile
.SetFilePointerEx(offset as _, co::FILE_STARTING_POINT::BEGIN)
.map(|_| ())
}
pub fn set_size(&self, num_bytes: u64) -> SysResult<()> {
self.set_pointer_offset(num_bytes)?;
self.hfile.SetEndOfFile()?;
self.set_pointer_offset(0)
}
#[must_use]
pub fn size(&self) -> SysResult<u64> {
self.hfile.GetFileSizeEx()
}
#[must_use]
pub fn times(&self) -> SysResult<(SYSTEMTIME, SYSTEMTIME, SYSTEMTIME)> {
let (ft_creation, ft_last_access, ft_last_write) = self.hfile.GetFileTime()?;
let st_creation_utc = FileTimeToSystemTime(&ft_creation)?;
let st_last_access_utc = FileTimeToSystemTime(&ft_last_access)?;
let st_last_write_utc = FileTimeToSystemTime(&ft_last_write)?;
let st_creation_local = SystemTimeToTzSpecificLocalTime(None, &st_creation_utc)?;
let st_last_access_local = SystemTimeToTzSpecificLocalTime(None, &st_last_access_utc)?;
let st_last_write_local = SystemTimeToTzSpecificLocalTime(None, &st_last_write_utc)?;
Ok((st_creation_local, st_last_access_local, st_last_write_local))
}
pub fn write(&self, data: &[u8]) -> SysResult<()> {
self.hfile.WriteFile(data).map(|_| ())
}
}