use std::fmt;
use std::fs::OpenOptions;
use std::io;
use std::marker::PhantomData;
use std::os::windows::fs::OpenOptionsExt;
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, RawHandle};
use win_shared_os_owned_handle::SharedHandle;
use win_volume_sys::bytes_per_sector;
use super::opened_file::{Buffering, Unbuffered};
use super::opened_volume::disk_flush_domain;
use durable_ioring::{FlushDomain, Geometry};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DiskPath(u32);
impl DiskPath {
#[must_use]
pub fn number(disk_number: u32) -> Self {
Self(disk_number)
}
#[must_use]
pub fn disk_number(&self) -> u32 {
self.0
}
#[must_use]
pub fn path(&self) -> String {
format!(r"\\.\PhysicalDrive{}", self.0)
}
}
impl fmt::Display for DiskPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.path())
}
}
#[derive(Clone, Debug)]
pub struct OpenedDisk<B: Buffering = Unbuffered> {
handle: SharedHandle,
geometry: Geometry,
disk_number: u32,
buffering: PhantomData<B>,
}
impl<B: Buffering> OpenedDisk<B> {
pub fn open(path: DiskPath) -> io::Result<Self> {
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(B::FLAGS)
.open(path.path())?;
let sector = bytes_per_sector(&file)?;
let geometry = B::sector_geometry(sector)
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
Ok(Self {
handle: SharedHandle::from(file),
geometry,
disk_number: path.disk_number(),
buffering: PhantomData,
})
}
#[must_use]
pub fn handle(&self) -> &SharedHandle {
&self.handle
}
#[must_use]
pub fn geometry(&self) -> Geometry {
self.geometry
}
#[must_use]
pub fn disk_number(&self) -> u32 {
self.disk_number
}
#[must_use]
pub fn flush_domain(&self) -> FlushDomain {
disk_flush_domain(self.disk_number)
}
#[cfg(test)]
pub(crate) fn assembled(handle: SharedHandle, disk_number: u32, sector: u32) -> Self {
Self {
handle,
geometry: B::sector_geometry(sector).expect("a power of two"),
disk_number,
buffering: PhantomData,
}
}
}
impl<B: Buffering> AsHandle for OpenedDisk<B> {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.handle.as_handle()
}
}
impl<B: Buffering> AsRawHandle for OpenedDisk<B> {
fn as_raw_handle(&self) -> RawHandle {
self.handle.as_raw_handle()
}
}