use std::mem::MaybeUninit;
use windows_sys::Win32::Storage::FileSystem::{FILE_ID_INFO, GetFileInformationByHandleEx};
use win_shared_os_owned_handle::SharedHandle;
use crate::handle::SharedRaw;
use crate::outcome::{Outcome, perform_bool};
use crate::query::FileInformationClass;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FileIdInfo {
volume_serial_number: u64,
file_id: [u8; 16],
}
impl FileIdInfo {
#[must_use]
pub const fn new(volume_serial_number: u64, file_id: [u8; 16]) -> Self {
Self {
volume_serial_number,
file_id,
}
}
#[must_use]
pub const fn volume_serial_number(&self) -> u64 {
self.volume_serial_number
}
#[must_use]
pub const fn file_id(&self) -> [u8; 16] {
self.file_id
}
}
fn from_raw(info: &FILE_ID_INFO) -> FileIdInfo {
FileIdInfo::new(info.VolumeSerialNumber, info.FileId.Identifier)
}
#[derive(Clone, Debug)]
#[must_use = "an unperformed request queries nothing"]
pub struct QueryFileIdInfo {
handle: SharedHandle,
}
impl QueryFileIdInfo {
pub fn new(handle: impl Into<SharedHandle>) -> Self {
Self {
handle: handle.into(),
}
}
pub fn handle(&self) -> &SharedHandle {
&self.handle
}
pub fn perform(&self) -> Outcome<FileIdInfo> {
let mut information = MaybeUninit::<FILE_ID_INFO>::uninit();
let size = u32::try_from(size_of::<FILE_ID_INFO>())
.expect("this fixed, small struct's size always fits a u32");
perform_bool(|| {
unsafe {
GetFileInformationByHandleEx(
self.handle.raw(),
FileInformationClass::ID.as_raw(),
information.as_mut_ptr().cast(),
size,
)
}
})?;
Ok(from_raw(unsafe { information.assume_init_ref() }))
}
}
impl crate::request::Request for QueryFileIdInfo {
type Error = crate::Win32Error;
type Output = FileIdInfo;
fn perform(&self) -> Outcome<FileIdInfo> {
Self::perform(self)
}
}
#[cfg(test)]
mod tests;