use std::path::Path;
use std::sync::Arc;
use crate::error::{A2FuseError, Result};
pub const BLOCK_SIZE: usize = 512;
#[derive(Clone, Debug)]
pub struct BlockDevice {
bytes: Arc<[u8]>,
}
impl BlockDevice {
pub fn open(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
let bytes = std::fs::read(path).map_err(|source| A2FuseError::ReadImage {
path: path.to_path_buf(),
source,
})?;
Self::from_bytes(bytes)
}
pub fn from_bytes(bytes: impl Into<Vec<u8>>) -> Result<Self> {
let bytes = bytes.into();
if bytes.len() % BLOCK_SIZE != 0 {
return Err(A2FuseError::InvalidImageLength {
length: bytes.len(),
});
}
Ok(Self {
bytes: bytes.into(),
})
}
pub fn block_count(&self) -> usize {
self.bytes.len() / BLOCK_SIZE
}
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
pub fn read_block(&self, block: u16) -> Result<&[u8; BLOCK_SIZE]> {
let start = usize::from(block) * BLOCK_SIZE;
let end = start + BLOCK_SIZE;
let bytes = self
.bytes
.get(start..end)
.ok_or(A2FuseError::BlockOutOfRange {
block,
block_count: self.block_count(),
})?;
Ok(bytes.try_into().expect("a block slice is always 512 bytes"))
}
}