use std::fmt;
use std::io;
use std::marker::PhantomData;
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 super::raw_open;
use super::share_mode::ShareMode;
use durable_ioring::{DataAccess, FlushDomain, Geometry, ReadWrite};
#[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, Copy, Debug)]
#[must_use]
pub struct DiskOptions {
share: ShareMode,
}
impl Default for DiskOptions {
fn default() -> Self {
Self::new()
}
}
impl DiskOptions {
pub fn new() -> Self {
Self {
share: ShareMode::ALL,
}
}
pub fn share(mut self, share: ShareMode) -> Self {
self.share = share;
self
}
}
#[derive(Clone, Debug)]
pub struct OpenedDisk<B: Buffering = Unbuffered, A: DataAccess = ReadWrite> {
handle: SharedHandle,
geometry: Geometry,
disk_number: u32,
mode: PhantomData<(B, A)>,
}
impl<B: Buffering, A: DataAccess> OpenedDisk<B, A> {
pub fn open(path: DiskPath, options: DiskOptions) -> io::Result<Self> {
let file = raw_open::open::<B, A>(path.path(), options.share)?;
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(),
mode: 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,
mode: PhantomData,
}
}
}
impl<B: Buffering, A: DataAccess> AsHandle for OpenedDisk<B, A> {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.handle.as_handle()
}
}
impl<B: Buffering, A: DataAccess> AsRawHandle for OpenedDisk<B, A> {
fn as_raw_handle(&self) -> RawHandle {
self.handle.as_raw_handle()
}
}