use std::io;
use std::ops::Range;
use win_shared_os_owned_handle::SharedHandle;
use windows_namespace_request_sys::file_id::{FileIdInfo, QueryFileIdInfo};
use windows_namespace_request_sys::open_by_id::FileIdentifier as RequestIdentifier;
use super::{Buffering, DataAccess, OpenedFile};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FileId {
volume_serial_number: u64,
id: [u8; 16],
}
impl FileId {
#[must_use]
pub const fn new(volume_serial_number: u64, id: [u8; 16]) -> Self {
Self {
volume_serial_number,
id,
}
}
pub fn of(handle: &SharedHandle) -> io::Result<Self> {
QueryFileIdInfo::new(handle.clone())
.perform()
.map(Self::from_info)
.map_err(|error| error.to_io_error())
}
#[must_use]
pub const fn volume_serial_number(&self) -> u64 {
self.volume_serial_number
}
#[must_use]
pub const fn id(&self) -> [u8; 16] {
self.id
}
fn from_info(info: FileIdInfo) -> Self {
Self::new(info.volume_serial_number(), info.file_id())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FileIdentifier {
Extended(FileId),
FileId64(u64),
ObjectId([u8; 16]),
}
impl From<FileId> for FileIdentifier {
fn from(id: FileId) -> Self {
Self::Extended(id)
}
}
impl FileIdentifier {
pub(super) fn to_request(self) -> RequestIdentifier {
match self {
Self::Extended(id) => RequestIdentifier::ExtendedFileId(id.id()),
Self::FileId64(id) => RequestIdentifier::FileId(id),
Self::ObjectId(bytes) => RequestIdentifier::ObjectId(guid_value(bytes)),
}
}
}
mod guid_layout {
use std::ops::Range;
pub const DATA1: Range<usize> = 0..4;
pub const DATA2: Range<usize> = 4..6;
pub const DATA3: Range<usize> = 6..8;
}
fn guid_value(bytes: [u8; 16]) -> u128 {
let mut text_order = bytes;
for field in [guid_layout::DATA1, guid_layout::DATA2, guid_layout::DATA3] {
reverse(&mut text_order, field);
}
u128::from_be_bytes(text_order)
}
fn reverse(bytes: &mut [u8; 16], field: Range<usize>) {
bytes[field].reverse();
}
impl<B: Buffering, A: DataAccess> OpenedFile<B, A> {
pub fn file_id(&self) -> io::Result<FileId> {
FileId::of(self.handle())
}
}