use super::{EntryLoc, Error, SectorDriver, Volume};
pub const MAX_FILE_LEN: u32 = u32::MAX;
impl<D: SectorDriver, const S: usize> Volume<D, S> {
fn read_sectors_direct(&mut self, first: u32, buf: &mut [u8]) -> Result<(), Error<D::Error>> {
let count = (buf.len() / self.bps()) as u32;
self.check_range(first, count)?;
self.invalidate(first, count)?;
let abs = self.abs(first);
self.dev.read_sectors(abs, buf).map_err(Error::Io)
}
fn write_sectors_direct(&mut self, first: u32, buf: &[u8]) -> Result<(), Error<D::Error>> {
let count = (buf.len() / self.bps()) as u32;
self.check_range(first, count)?;
self.invalidate(first, count)?;
let abs = self.abs(first);
self.dev.write_sectors(abs, buf).map_err(Error::Io)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct File {
first_cluster: u32,
len: u32,
pos: u32,
cur_cluster: u32,
cur_index: u32,
loc: EntryLoc,
dirty: bool,
}
impl File {
pub(crate) fn new(first_cluster: u32, len: u32, loc: EntryLoc) -> Self {
Self {
first_cluster,
len,
pos: 0,
cur_cluster: first_cluster,
cur_index: 0,
loc,
dirty: false,
}
}
pub fn len(&self) -> u32 {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn pos(&self) -> u32 {
self.pos
}
pub fn seek<D: SectorDriver, const S: usize>(
&mut self,
_vol: &mut Volume<D, S>,
pos: u32,
) -> Result<(), Error<D::Error>> {
self.pos = pos;
Ok(())
}
pub fn seek_to_end<D: SectorDriver, const S: usize>(
&mut self,
_vol: &mut Volume<D, S>,
) -> Result<(), Error<D::Error>> {
self.pos = self.len;
Ok(())
}
fn cluster_at<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
index: u32,
) -> Result<Option<u32>, Error<D::Error>> {
if self.first_cluster == 0 {
return Ok(None);
}
let (mut cluster, mut at) = if index >= self.cur_index && self.cur_cluster != 0 {
(self.cur_cluster, self.cur_index)
} else {
(self.first_cluster, 0)
};
if index > vol.geom.cluster_count {
return Err(Error::CorruptChain);
}
while at < index {
match vol.next_cluster(cluster)? {
Some(next) => {
cluster = next;
at += 1;
}
None => return Ok(None),
}
}
if !vol.geom.is_data_cluster(cluster) {
return Err(Error::CorruptChain);
}
self.cur_cluster = cluster;
self.cur_index = at;
Ok(Some(cluster))
}
fn cluster_at_or_alloc<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
index: u32,
zero_new: bool,
) -> Result<u32, Error<D::Error>> {
if self.first_cluster == 0 {
let cluster = if zero_new {
vol.alloc_zeroed_cluster(None)?
} else {
vol.alloc_cluster(None)?
};
self.first_cluster = cluster;
self.cur_cluster = cluster;
self.cur_index = 0;
self.dirty = true;
}
if index > vol.geom.cluster_count {
return Err(Error::CorruptChain);
}
let (mut cluster, mut at) = if index >= self.cur_index && self.cur_cluster != 0 {
(self.cur_cluster, self.cur_index)
} else {
(self.first_cluster, 0)
};
if !vol.geom.is_data_cluster(cluster) {
return Err(Error::CorruptChain);
}
while at < index {
cluster = match vol.next_cluster(cluster)? {
Some(next) => next,
None => {
if zero_new {
vol.alloc_zeroed_cluster(Some(cluster))?
} else {
vol.alloc_cluster(Some(cluster))?
}
}
};
at += 1;
}
self.cur_cluster = cluster;
self.cur_index = at;
Ok(cluster)
}
pub fn read<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
buf: &mut [u8],
) -> Result<usize, Error<D::Error>> {
let want = buf.len().min(self.len.saturating_sub(self.pos) as usize);
if want == 0 {
return Ok(0);
}
let bps = vol.bps();
let spc = vol.geom.sectors_per_cluster;
let cb = vol.geom.cluster_bytes();
let mut done = 0;
while done < want {
let index = self.pos / cb;
let in_cluster = self.pos % cb;
let cluster = self
.cluster_at(vol, index)?
.ok_or(Error::CorruptChain)?;
let sector_in_cluster = in_cluster / bps as u32;
let in_sector = (in_cluster % bps as u32) as usize;
let first_sector = vol.geom.cluster_first_sector(cluster) + sector_in_cluster;
let left = want - done;
if in_sector == 0 && left >= bps {
let max = (spc - sector_in_cluster) as usize;
let n = (left / bps).min(max);
let bytes = n * bps;
vol.read_sectors_direct(first_sector, &mut buf[done..done + bytes])?;
done += bytes;
self.pos += bytes as u32;
} else {
let n = left.min(bps - in_sector);
let sector = vol.sector(first_sector)?;
buf[done..done + n].copy_from_slice(§or[in_sector..in_sector + n]);
done += n;
self.pos += n as u32;
}
}
Ok(done)
}
pub fn read_exact<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
buf: &mut [u8],
) -> Result<(), Error<D::Error>> {
let n = self.read(vol, buf)?;
if n == buf.len() {
Ok(())
} else {
Err(Error::InvalidOffset)
}
}
pub fn write<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
buf: &[u8],
) -> Result<usize, Error<D::Error>> {
if buf.is_empty() {
return Ok(0);
}
if self.pos > self.len {
let gap_to = self.pos;
self.pos = self.len;
self.zero_extend(vol, gap_to)?;
self.pos = gap_to;
}
let len = u32::try_from(buf.len()).map_err(|_| Error::FileTooLarge)?;
let end = self.pos.checked_add(len).ok_or(Error::FileTooLarge)?;
let bps = vol.bps();
let spc = vol.geom.sectors_per_cluster;
let cb = vol.geom.cluster_bytes();
let mut done = 0usize;
while done < buf.len() {
let index = self.pos / cb;
let in_cluster = self.pos % cb;
let left = buf.len() - done;
let covers_cluster = in_cluster == 0 && left >= cb as usize;
let cluster = self.cluster_at_or_alloc(vol, index, !covers_cluster)?;
let sector_in_cluster = in_cluster / bps as u32;
let in_sector = (in_cluster % bps as u32) as usize;
let first_sector = vol.geom.cluster_first_sector(cluster) + sector_in_cluster;
if in_sector == 0 && left >= bps {
let max = (spc - sector_in_cluster) as usize;
let n = (left / bps).min(max);
let bytes = n * bps;
vol.write_sectors_direct(first_sector, &buf[done..done + bytes])?;
done += bytes;
self.pos += bytes as u32;
} else {
let n = left.min(bps - in_sector);
let sector = vol.sector_mut(first_sector)?;
sector[in_sector..in_sector + n].copy_from_slice(&buf[done..done + n]);
done += n;
self.pos += n as u32;
}
}
if end > self.len {
self.len = end;
}
self.dirty = true;
Ok(done)
}
pub fn write_all<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
buf: &[u8],
) -> Result<(), Error<D::Error>> {
let n = self.write(vol, buf)?;
if n == buf.len() {
Ok(())
} else {
Err(Error::NoSpace)
}
}
fn zero_extend<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
new_len: u32,
) -> Result<(), Error<D::Error>> {
let cb = vol.geom.cluster_bytes();
let bps = vol.bps();
let mut at = self.len;
while at < new_len {
let index = at / cb;
let in_cluster = at % cb;
let left = new_len - at;
let covers = in_cluster == 0 && left >= cb;
let existed = self.cluster_at(vol, index)?.is_some();
let cluster = self.cluster_at_or_alloc(vol, index, !covers)?;
let step = left.min(cb - in_cluster);
if existed {
let mut off = in_cluster;
let mut remaining = step;
while remaining > 0 {
let sector_in_cluster = off / bps as u32;
let in_sector = (off % bps as u32) as usize;
let n = (remaining as usize).min(bps - in_sector);
let first = vol.geom.cluster_first_sector(cluster) + sector_in_cluster;
let sector = vol.sector_mut(first)?;
sector[in_sector..in_sector + n].fill(0);
off += n as u32;
remaining -= n as u32;
}
}
at += step;
}
self.len = self.len.max(new_len);
self.dirty = true;
Ok(())
}
pub fn set_len<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
new_len: u32,
) -> Result<(), Error<D::Error>> {
if new_len > self.len {
let keep = self.pos;
self.zero_extend(vol, new_len)?;
self.pos = keep;
return Ok(());
}
if new_len == self.len {
return Ok(());
}
let cb = vol.geom.cluster_bytes();
if new_len == 0 {
if self.first_cluster != 0 {
vol.free_chain(self.first_cluster)?;
}
self.first_cluster = 0;
self.cur_cluster = 0;
self.cur_index = 0;
} else {
let last_index = (new_len - 1) / cb;
if let Some(cluster) = self.cluster_at(vol, last_index)? {
vol.truncate_chain(cluster)?;
}
}
self.len = new_len;
self.pos = self.pos.min(new_len);
self.cur_cluster = self.first_cluster;
self.cur_index = 0;
self.dirty = true;
Ok(())
}
pub fn flush<D: SectorDriver, const S: usize>(
&mut self,
vol: &mut Volume<D, S>,
) -> Result<(), Error<D::Error>> {
if self.dirty {
vol.update_entry(self.loc, self.first_cluster, self.len)?;
self.dirty = false;
}
vol.flush()
}
pub fn first_cluster(&self) -> u32 {
self.first_cluster
}
}