Sync computers
This commit is contained in:
160
crates/bffs/src/file.rs
Normal file
160
crates/bffs/src/file.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use crate::{
|
||||
consts::{FAT32_BAD_CLUSTER, FAT32_END_OF_CHAIN},
|
||||
error::Error,
|
||||
io::{self, IoBase, Read, Seek, Write},
|
||||
Fat32FileSystem, ReadSeek, ReadWriteSeek,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RawFile<'a, T> {
|
||||
pub(crate) fs: &'a Fat32FileSystem<T>,
|
||||
first_cluster: u32,
|
||||
current_cluster: u32,
|
||||
pos: u64,
|
||||
size: Option<u32>,
|
||||
}
|
||||
|
||||
impl<'a, T> RawFile<'a, T> {
|
||||
pub fn new(fs: &'a Fat32FileSystem<T>, start_cluster: u32, size: Option<u32>) -> 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 = T::Error;
|
||||
}
|
||||
|
||||
impl<'a, T: ReadSeek> Seek for RawFile<'a, T> {
|
||||
fn seek(&mut self, pos: io::SeekFrom) -> Result<u64, Error<Self::Error>> {
|
||||
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<usize, Error<Self::Error>> {
|
||||
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<usize, Error<Self::Error>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Error<Self::Error>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct File<'a, T> {
|
||||
raw: RawFile<'a, T>,
|
||||
fs: &'a Fat32FileSystem<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: IoBase> IoBase for File<'a, T> {
|
||||
type Error = T::Error;
|
||||
}
|
||||
impl<'a, T: ReadSeek> Seek for File<'a, T> {
|
||||
fn seek(&mut self, pos: io::SeekFrom) -> Result<u64, Error<Self::Error>> {
|
||||
self.raw.seek(pos)
|
||||
}
|
||||
}
|
||||
impl<'a, T: ReadSeek> Read for File<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error<Self::Error>> {
|
||||
self.raw.read(buf)
|
||||
}
|
||||
}
|
||||
impl<'a, T: ReadWriteSeek> Write for File<'a, T> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Error<Self::Error>> {
|
||||
self.raw.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Error<Self::Error>> {
|
||||
self.raw.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> File<'a, T> {
|
||||
pub fn new(raw: RawFile<'a, T>, fs: &'a Fat32FileSystem<T>) -> Self {
|
||||
Self { raw, fs }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user