use crate::cache::CachedPartition;
use crate::{ArcMutex, ClusterId, Result, SectorId, fat_table};
pub(crate) struct ClusterChainReader {
device: ArcMutex<CachedPartition>,
current_cluster: Option<ClusterId>,
current_sector: SectorId,
offset_byte_in_current_sector: usize,
}
impl ClusterChainReader {
pub(crate) fn new(device: ArcMutex<CachedPartition>, start_cluster: ClusterId) -> Self {
let current_sector = device.cluster_to_sector(start_cluster);
Self {
current_cluster: Some(start_cluster),
offset_byte_in_current_sector: 0,
current_sector,
device,
}
}
fn next_cluster(&self) -> Result<Option<ClusterId>> {
if self.current_cluster.is_none() {
return Ok(None);
}
fat_table::next_cluster(self.current_cluster.unwrap(), self.device.clone())
}
pub fn seek(&mut self, offset: usize) -> Result<()> {
let cluster_size = self.device.sectors_per_cluster as usize * self.device.sector_size;
let cluster_offset = offset / cluster_size;
let sector_offset =
offset / self.device.sector_size % self.device.sectors_per_cluster as usize;
let offset_in_sector = offset % self.device.sector_size;
for _ in 0..cluster_offset {
self.current_cluster = self.next_cluster()?;
}
let start_sector = self.device.cluster_to_sector(self.current_cluster.unwrap())
+ SectorId(sector_offset as u32);
self.current_sector = start_sector;
self.offset_byte_in_current_sector = offset_in_sector;
Ok(())
}
pub(crate) fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.current_cluster.is_none() || buf.is_empty() {
return Ok(0);
}
let mut amount = 0;
while amount < buf.len() && self.current_cluster.is_some() {
let current_amount_read = self.read_cluster(&mut buf[amount..])?;
amount += current_amount_read;
if current_amount_read == 0 {
self.current_cluster = self.next_cluster()?;
if let Some(cluster) = self.current_cluster {
self.current_sector = self.device.cluster_to_sector(cluster);
self.offset_byte_in_current_sector = 0;
}
}
}
Ok(amount)
}
fn read_cluster(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.cluster_is_over() || buf.is_empty() {
return Ok(0);
}
let mut total = 0;
let buf_len = buf.len();
while total < buf_len && !self.cluster_is_over() {
let space_left_in_current_sector =
self.device.sector_size - self.offset_byte_in_current_sector;
let amount = self.device.clone().read_sector_offset(
self.current_sector,
self.offset_byte_in_current_sector,
&mut buf[total..core::cmp::min(buf_len, space_left_in_current_sector)],
)?;
total += amount;
self.offset_byte_in_current_sector += amount;
assert!(self.offset_byte_in_current_sector <= self.device.sector_size);
if self.offset_byte_in_current_sector == self.device.sector_size {
self.current_sector = self.current_sector + 1;
self.offset_byte_in_current_sector = 0;
}
}
Ok(total)
}
fn cluster_is_over(&self) -> bool {
let cluster_start = self.device.cluster_to_sector(self.current_cluster.unwrap());
let final_sector = SectorId(self.device.sectors_per_cluster) + cluster_start;
self.current_sector >= final_sector
}
}