//! Read-only physical sector mapping for a validated partition interval. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { EmptyDevice, EmptyPartition, OutsideDevice, EmptyRead, OutsidePartition, Overflow, } #[derive(Debug, PartialEq, Eq)] pub enum ReadError { View(Error), Device(E), } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct View { pub start_lba: u64, pub sectors: u64, pub end_lba: u64, pub disk_sectors: u64, } impl View { pub fn new(start_lba: u64, sectors: u64, disk_sectors: u64) -> Result { if disk_sectors == 0 { return Err(Error::EmptyDevice); } if sectors == 0 { return Err(Error::EmptyPartition); } let end_lba = start_lba.checked_add(sectors).ok_or(Error::Overflow)?; if end_lba > disk_sectors { return Err(Error::OutsideDevice); } Ok(Self { start_lba, sectors, end_lba, disk_sectors }) } pub fn translate(&self, logical_lba: u64, sector_count: u64) -> Result<(u64, u64), Error> { if sector_count == 0 { return Err(Error::EmptyRead); } let logical_end = logical_lba.checked_add(sector_count) .ok_or(Error::Overflow)?; if logical_end > self.sectors { return Err(Error::OutsidePartition); } let physical_lba = self.start_lba.checked_add(logical_lba) .ok_or(Error::Overflow)?; Ok((physical_lba, sector_count)) } pub fn read(&self, logical_lba: u64, sector_count: u64, io: F) -> Result<(), ReadError> where F: FnOnce(u64, u64) -> Result<(), E> { let (physical_lba, count) = self.translate(logical_lba, sector_count) .map_err(ReadError::View)?; io(physical_lba, count).map_err(ReadError::Device) } }