use crate::{ClusterId, SectorId, VfatFS, error::Result, fat_table};
use log::debug;
#[derive(Debug)]
pub(crate) struct ClusterChainWriter {
vfat_fs: VfatFS,
pub(crate) current_cluster: ClusterId,
pub(crate) current_sector: SectorId,
pub(crate) offset_byte_in_current_sector: usize,
}
impl ClusterChainWriter {
pub(crate) fn new(
vfat_fs: VfatFS,
start_cluster: ClusterId,
offset_sector_in_cluster: SectorId,
offset_in_sector: usize,
) -> Self {
let current_sector =
vfat_fs.device.cluster_to_sector(start_cluster) + offset_sector_in_cluster;
Self {
current_cluster: start_cluster,
offset_byte_in_current_sector: offset_in_sector,
current_sector,
vfat_fs,
}
}
fn next_cluster_alloc(&mut self) -> Result<ClusterId> {
let ret = fat_table::next_cluster(self.current_cluster, self.vfat_fs.device.clone())?;
Ok(match ret {
None => self
.vfat_fs
.allocate_cluster_to_chain(self.current_cluster)?,
Some(r) => r,
})
}
pub fn seek(&mut self, offset: usize) -> Result<()> {
debug!(
"offset: {}, sector size: {} sectors per cluster: {}",
offset, self.vfat_fs.device.sector_size, self.vfat_fs.device.sectors_per_cluster
);
let cluster_size =
self.vfat_fs.device.sectors_per_cluster as usize * self.vfat_fs.device.sector_size;
let cluster_offset = offset / cluster_size;
debug!("Cluster offset: {}", cluster_offset);
let sector_offset = offset / self.vfat_fs.device.sector_size
% self.vfat_fs.device.sectors_per_cluster as usize;
let offset_in_sector = offset % self.vfat_fs.device.sector_size;
for _ in 0..cluster_offset {
self.current_cluster = self.next_cluster_alloc()?;
}
debug!(
"offset in sector: {}, current cluster:{}",
offset_in_sector, self.current_cluster
);
self.current_sector = self.vfat_fs.device.cluster_to_sector(self.current_cluster)
+ SectorId(sector_offset as u32);
self.offset_byte_in_current_sector = offset_in_sector;
Ok(())
}
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
if buf.is_empty() {
return Ok(0);
}
assert_ne!(
self.current_cluster,
ClusterId::new(0),
"current cluster is ClusterId(0)."
);
let mut amount = 0;
while amount < buf.len() {
let current_amount_written = self.write_cluster(&buf[amount..])?;
amount += current_amount_written;
if current_amount_written == 0 {
self.current_cluster = self.next_cluster_alloc()?;
self.current_sector = self.vfat_fs.device.cluster_to_sector(self.current_cluster);
self.offset_byte_in_current_sector = 0;
}
}
debug!("CWW: Amount written: {}", amount);
Ok(amount)
}
fn write_cluster(&mut self, buf: &[u8]) -> Result<usize> {
if self.cluster_is_over() || buf.is_empty() {
return Ok(0);
}
let mut total = 0;
while total < buf.len() && !self.cluster_is_over() {
let space_left_in_current_sector =
self.vfat_fs.device.sector_size - self.offset_byte_in_current_sector;
let amount = self.vfat_fs.device.clone().write_sector_offset(
self.current_sector,
self.offset_byte_in_current_sector,
&buf[total..core::cmp::min(total + space_left_in_current_sector, buf.len())],
)?;
total += amount;
self.offset_byte_in_current_sector += amount;
assert!(self.offset_byte_in_current_sector <= self.vfat_fs.device.sector_size);
if self.offset_byte_in_current_sector == self.vfat_fs.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.vfat_fs.device.cluster_to_sector(self.current_cluster);
let final_sector = SectorId(self.vfat_fs.device.sectors_per_cluster) + cluster_start;
self.current_sector >= final_sector
}
}