use crate::{ Fat32FileSystem, ReadSeek, ReadWriteSeek, consts::{FAT32_BAD_CLUSTER, FAT32_END_OF_CHAIN}, error::Error, }; use io::{self, IoBase, Read, Seek, Write}; #[derive(Debug, Clone)] pub struct RawFile<'a, T> { pub(crate) fs: &'a Fat32FileSystem, first_cluster: u32, current_cluster: u32, pos: u64, size: Option, } impl<'a, T> RawFile<'a, T> { pub fn new(fs: &'a Fat32FileSystem, start_cluster: u32, size: Option) -> Self { Self { fs, first_cluster: start_cluster, current_cluster: start_cluster, pos: 0, size, } } pub fn first_cluster(&self) -> u32 { self.first_cluster } } impl<'a, T: IoBase> IoBase for RawFile<'a, T> { type Error = Error; } impl<'a, T: ReadSeek> Seek for RawFile<'a, T> { fn seek(&mut self, pos: io::SeekFrom) -> Result { let new_pos = match pos { io::SeekFrom::Start(s) => s, io::SeekFrom::Current(c) => (self.pos as i64 + c) as u64, io::SeekFrom::End(e) => { let s = self.size.unwrap_or(0) as i64; (s + e) as u64 } }; // Position changed, compute the new cluster if new_pos != self.pos { let cluster_size = self.fs.cluster_size(); let cluster_index = new_pos / cluster_size; // Find the new cluster from the start let mut c = self.first_cluster; for _ in 0..cluster_index { c = self.fs.get_next_cluster(c)?; if c >= FAT32_BAD_CLUSTER { break; } } self.current_cluster = c; self.pos = new_pos; } Ok(self.pos) } } impl<'a, T: ReadSeek> Read for RawFile<'a, T> { fn read(&mut self, buf: &mut [u8]) -> Result { let max_len = self .size .map(|size| core::cmp::min(buf.len(), size as usize - self.pos as usize)) .unwrap_or(buf.len()); let mut total_read = 0; let cluster_size = self.fs.cluster_size(); while total_read < max_len { // Compute how much can be read in the current cluster let offset_in_cluster = self.pos % cluster_size; let remaining_in_cluster = cluster_size - offset_in_cluster; let to_read = core::cmp::min(max_len - total_read, remaining_in_cluster as usize); // Read from disk let physical_offset = self.fs.cluster_to_offset(self.current_cluster) + offset_in_cluster; self.fs .device .borrow_mut() .seek(io::SeekFrom::Start(physical_offset))?; let read = self .fs .device .borrow_mut() .read(&mut buf[total_read..total_read + to_read])?; total_read += read; self.pos += read as u64; if read != to_read { // The read call didn't read all bytes to fill buf, we can return early return Ok(total_read); } // At the end of a cluster, go to the next one for the next read operation if self.pos.is_multiple_of(cluster_size) { if self.current_cluster >= FAT32_END_OF_CHAIN { break; // End of the fat file } self.current_cluster = self.fs.get_next_cluster(self.current_cluster)?; } } Ok(total_read) } } impl<'a, T: ReadWriteSeek> Write for RawFile<'a, T> { fn write(&mut self, _buf: &[u8]) -> Result { todo!() } fn flush(&mut self) -> Result<(), Self::Error> { todo!() } } #[allow(unused)] #[derive(Debug)] pub struct File<'a, T> { raw: RawFile<'a, T>, fs: &'a Fat32FileSystem, } impl<'a, T: IoBase> IoBase for File<'a, T> { type Error = Error; } impl<'a, T: ReadSeek> Seek for File<'a, T> { fn seek(&mut self, pos: io::SeekFrom) -> Result { self.raw.seek(pos) } } impl<'a, T: ReadSeek> Read for File<'a, T> { fn read(&mut self, buf: &mut [u8]) -> Result { self.raw.read(buf) } } impl<'a, T: ReadWriteSeek> Write for File<'a, T> { fn write(&mut self, buf: &[u8]) -> Result { self.raw.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.raw.flush() } } impl<'a, T> File<'a, T> { pub fn new(raw: RawFile<'a, T>, fs: &'a Fat32FileSystem) -> Self { Self { raw, fs } } }