diff --git a/src/dir.rs b/src/dir.rs index 03564a3..656fa7b 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -76,7 +76,7 @@ impl Display for RegularDirEntry { write!( f, - "DirEntry {{ {} {: <16} created: {} modified: {} }}", + "{} {: <16} created: {} modified: {}", self.attr, name, self.create_time().format("%a %b %d %H:%M:%S%.3f %Y"), @@ -167,6 +167,30 @@ impl RegularDirEntry { self.attr.contains(Attr::Directory) && !self.attr.intersects(Attr::System | Attr::VolumeId) } + pub fn is_dot(&self) -> bool { + if !self.is_dir() { + return false; + } + + // &self.name[..2] == &[b'.', b' '] + + self.name[0] == b'.' && &self.name[1..] == &[b' '; 10] + } + + pub fn is_dotdot(&self) -> bool { + if !self.is_dir() { + return false; + } + + // &self.name[..3] == &[b'.', b'.', b' '] + + &self.name[..2] == &[b'.', b'.'] && &self.name[2..] == &[b' '; 9] + } + + pub fn is_hidden(&self) -> bool { + self.is_dot() || self.is_dotdot() || self.attr.contains(Attr::Hidden) + } + pub fn name(&self) -> &[u8] { &self.name } diff --git a/src/dump.rs b/src/dump.rs index 43c2517..0633697 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,7 +1,8 @@ use std::io::Read; -use fat_rs::FatFs; +use fat_rs::dir::{DirIter, RegularDirEntry}; use fat_rs::fat::Fatty as _; +use fat_rs::{FatFs, SliceLike}; pub fn main() -> anyhow::Result<()> { let args = std::env::args(); @@ -38,5 +39,45 @@ pub fn main() -> anyhow::Result<()> { println!("{}", dir_entry); } + println!(); + println!(); + + tree(&fat_fs); + Ok(()) } + +fn tree(fat_fs: &FatFs) { + fn do_indent(indent: u32) { + for _ in 0..indent { + print!(" "); + } + } + + fn tree_impl( + fat_fs: &FatFs, + iter: impl Iterator, + indent: u32, + ) { + for dir_entry in iter.filter(|x| !x.is_hidden()) { + do_indent(indent); + + println!("{}", dir_entry); + + if dir_entry.is_dot() || dir_entry.is_dotdot() { + // do not descent into . and .. + continue; + } + + if dir_entry.is_dir() { + let reader = fat_fs.chain_reader(dir_entry.first_cluster()); + + let iter = DirIter::new(reader); + + tree_impl(fat_fs, iter, indent + 1); + } + } + } + + tree_impl(fat_fs, fat_fs.root_dir_iter(), 0); +} diff --git a/src/iter.rs b/src/iter.rs index 0e0922e..2e34765 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -1,6 +1,5 @@ use std::io::Read; -use crate::fat::Fatty; use crate::subslice::SubSlice; use crate::utils::replace; use crate::{FatFs, SliceLike}; @@ -12,7 +11,7 @@ pub struct ClusterChainReader<'a, S: SliceLike> { } impl<'a, S: SliceLike> ClusterChainReader<'a, S> { - pub fn new(fat_fs: &'a mut FatFs, first_cluster: u32) -> ClusterChainReader<'a, S> { + pub fn new(fat_fs: &'a FatFs, first_cluster: u32) -> ClusterChainReader<'a, S> { let next_cluster = fat_fs.next_cluster(first_cluster).unwrap_or(None); let sub_slice = fat_fs.cluster_as_subslice(first_cluster); diff --git a/src/lib.rs b/src/lib.rs index e948f4b..a0f086c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ -use std::io::{Read as _, Seek as _, SeekFrom, Write as _}; +use std::cell::RefCell; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::rc::Rc; use crate::dir::{DirIter, RegularDirEntry}; use crate::fat::{FatError, Fatty}; @@ -94,7 +96,7 @@ impl SliceLike for std::fs::File { #[allow(dead_code)] pub struct FatFs { - data: S, + inner: Rc>, fat_offset: u64, fat_size: usize, @@ -150,8 +152,10 @@ impl FatFs { let bytes_per_cluster = bpb.bytes_per_cluster(); + let data = Rc::new(RefCell::new(data)); + Ok(FatFs { - data, + inner: data, fat_offset, fat_size, root_dir_offset, @@ -194,7 +198,7 @@ impl FatFs { SubSliceMut::new(self, offset, self.bytes_per_cluster) } - pub fn cluster_as_subslice(&mut self, cluster: u32) -> SubSlice<'_, S> { + pub fn cluster_as_subslice(&self, cluster: u32) -> SubSlice<'_, S> { let offset = self.data_cluster_to_offset(cluster); SubSlice::new(self, offset, self.bytes_per_cluster) @@ -215,20 +219,20 @@ impl FatFs { let mut data = vec![0; self.bytes_per_cluster]; - self.data - .read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?; + let mut inner = self.inner.borrow_mut(); + + inner.read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?; while let Ok(Some(next_cluster)) = self.next_cluster(cluster) { cluster = next_cluster; - self.data - .read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?; + inner.read_at_offset(self.data_cluster_to_offset(cluster), &mut data)?; } Ok(data) } - pub fn root_dir_iter(&mut self) -> Box + '_> { + pub fn root_dir_iter(&self) -> Box + '_> { // TODO: maybe wrap this in another RootDirIter enum, so we don't have to Box if let Some(root_dir_offset) = self.root_dir_offset { @@ -248,4 +252,8 @@ impl FatFs { Box::new(DirIter::new(cluster_iter)) } + + pub fn chain_reader(&self, first_cluster: u32) -> impl Read { + iter::ClusterChainReader::new(self, first_cluster) + } } diff --git a/src/subslice.rs b/src/subslice.rs index 4dbb43c..821081c 100644 --- a/src/subslice.rs +++ b/src/subslice.rs @@ -44,7 +44,8 @@ impl Read for SubSliceMut<'_, S> { let bytes_to_read = self.len.min(buf.len()); self.fat_fs - .data + .inner + .borrow_mut() .read_at_offset(self.offset, &mut buf[..bytes_to_read])?; self.offset += bytes_to_read as u64; @@ -59,7 +60,8 @@ impl Write for SubSliceMut<'_, S> { let bytes_to_write = self.len.min(buf.len()); self.fat_fs - .data + .inner + .borrow_mut() .write_at_offset(self.offset, &buf[..bytes_to_write])?; self.offset += bytes_to_write as u64; @@ -74,7 +76,7 @@ impl Write for SubSliceMut<'_, S> { } pub struct SubSlice<'a, S: SliceLike> { - fat_fs: &'a mut FatFs, + fat_fs: &'a FatFs, offset: u64, len: usize, @@ -90,7 +92,7 @@ impl Debug for SubSlice<'_, S> { } impl SubSlice<'_, S> { - pub fn new(fat_fs: &mut FatFs, offset: u64, len: usize) -> SubSlice<'_, S> { + pub fn new(fat_fs: &FatFs, offset: u64, len: usize) -> SubSlice<'_, S> { SubSlice { fat_fs, offset, @@ -115,7 +117,7 @@ impl SubSlice<'_, S> { } impl<'a, S: SliceLike> SubSlice<'a, S> { - pub fn release(self) -> &'a mut FatFs { + pub fn release(self) -> &'a FatFs { self.fat_fs } } @@ -125,7 +127,8 @@ impl Read for SubSlice<'_, S> { let bytes_to_read = self.len.min(buf.len()); self.fat_fs - .data + .inner + .borrow_mut() .read_at_offset(self.offset, &mut buf[..bytes_to_read])?; self.offset += bytes_to_read as u64;