diff --git a/src/fs.rs b/src/fs.rs index bbb010b..ef40187 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,5 +1,5 @@ use core::mem; -use core::marker::PhantomData; +use core::fmt::{self, Debug}; use core::nonzero::NonZero; use alloc::Vec; @@ -86,27 +86,17 @@ where Ok(()) } - #[allow(dead_code)] - fn update_inode( - &mut self, - &(ref inode, offset): &(Inode, Address), - ) -> Result<(), Error> { - let slice = VolumeSlice::from_cast(&inode.inner, offset); - let commit = slice.commit(); - self.volume.commit(commit).map_err(|err| Error::from(err)) - } - - pub fn read_inode( - &self, + pub fn read_inode<'a>( + &'a self, buf: &mut [u8], - inode: &Inode, + inode: &Inode<'a, S, V>, ) -> Result { let total_size = inode.size(); let mut read_size = 0; let block_size = self.block_size(); let offset = 0; - for (data, _) in InodeBlocks::new(self, &inode) { + for (data, _) in InodeBlocks::new(&inode) { let data_size = block_size .min(total_size - read_size) .min(buf.len() - offset); @@ -118,19 +108,22 @@ where Ok(read_size) } - pub fn write_inode( - &self, - &(ref inode, offset): &(Inode, Address), - buf: &[u8], + pub fn write_inode<'a>( + &'a self, + _inode: &(Inode<'a, S, V>, Address), + _buf: &[u8], ) -> Result { unimplemented!() } - pub fn root_inode(&self) -> (Inode, Address) { + pub fn root_inode<'a>(&'a self) -> (Inode<'a, S, V>, Address) { self.inode_nth(2).unwrap() } - pub fn inode_nth(&self, index: usize) -> Option<(Inode, Address)> { + pub fn inode_nth<'a>( + &'a self, + index: usize, + ) -> Option<(Inode<'a, S, V>, Address)> { self.inodes_nth(index).next() } @@ -141,17 +134,18 @@ where pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, V> { assert!(index > 0, "inodes are 1-indexed"); Inodes { - volume: &self.volume, + fs: self, block_groups: &self.block_groups.inner, log_block_size: self.log_block_size(), inode_size: self.inode_size(), inodes_per_group: self.inodes_count(), inodes_count: self.total_inodes_count(), index, - _phantom: PhantomData, } } +} +impl>> Ext2 { fn superblock(&self) -> &Superblock { &self.superblock.inner } @@ -165,9 +159,9 @@ where (self.superblock().rev_major, self.superblock().rev_minor) } - pub fn inode_size(&self) -> usize { + pub fn inode_size<'a>(&'a self) -> usize { if self.version().0 == 0 { - mem::size_of::() + mem::size_of::>() } else { // note: inodes bigger than 128 are not supported self.superblock().inode_size as usize @@ -214,15 +208,20 @@ where } } -pub struct Inodes<'a, S: Size, V: 'a + Volume>> { - volume: &'a V, +impl>> Debug for Ext2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Ext2<{}>", S::SIZE) + } +} + +pub struct Inodes<'a, S: 'a + Size, V: 'a + Volume>> { + fs: &'a Ext2, block_groups: &'a [BlockGroupDescriptor], log_block_size: u32, inode_size: usize, inodes_per_group: usize, inodes_count: usize, index: usize, - _phantom: PhantomData, } impl<'a, S: Size + Copy, V: 'a + Volume>> Iterator @@ -230,7 +229,7 @@ impl<'a, S: Size + Copy, V: 'a + Volume>> Iterator where Error: From, { - type Item = (Inode, Address); + type Item = (Inode<'a, S, V>, Address); fn next(&mut self) -> Option { if self.index < self.inodes_count { @@ -247,9 +246,10 @@ where self.log_block_size, ); let raw = unsafe { - RawInode::find_inode(self.volume, offset, self.inode_size).ok() + RawInode::find_inode(&self.fs.volume, offset, self.inode_size) + .ok() }; - raw.map(|(raw, offset)| (Inode::new(raw), offset)) + raw.map(|(raw, offset)| (Inode::new(self.fs, raw), offset)) } else { None } @@ -257,13 +257,14 @@ where } #[derive(Debug, Clone)] -pub struct Inode { +pub struct Inode<'a, S: 'a + Size, V: 'a + Volume>> { + fs: &'a Ext2, inner: RawInode, } -impl Inode { - pub fn new(inner: RawInode) -> Inode { - Inode { inner } +impl<'a, S: 'a + Size + Copy, V: 'a + Volume>> Inode<'a, S, V> { + pub fn new(fs: &'a Ext2, inner: RawInode) -> Inode<'a, S, V> { + Inode { fs, inner } } pub fn block(&self, index: usize) -> Option> { @@ -281,14 +282,25 @@ impl Inode { // - that's n/4 blocks with n/4 pointers each = (n/4)^2 // number of blocks in triply table: (block_size/4)^3 - let bs4 = self.block_size() / 4; + let bs4 = self.fs.block_size() / 4; if index < 12 { NonZero::new(self.inner.direct_pointer[index] as usize) - } else if index < bs4 { - unimplemented!("indirect pointer table"); - } else if index < bs4 * bs4 { + } else if index < bs4 + 12 { + let block = self.inner.indirect_pointer as usize; + let offset = index - 12; + let addr = Address::with_block_size( + block, + offset as isize, + self.fs.log_block_size(), + ); + let size = Address::from(4_usize); + let slice = self.fs.volume.slice(addr..addr + size); + slice.and_then(|slice| unsafe { + NonZero::new(u32::from_le(slice.dynamic_cast::().0) as usize) + }) + } else if index < bs4 * bs4 + bs4 + 12 { unimplemented!("doubly indirect pointer table"); - } else if index < bs4 * bs4 * bs4 { + } else if index < bs4 * bs4 * bs4 + bs4 * bs4 + bs4 + 12 { unimplemented!("triply indirect pointer table"); } else { None @@ -328,9 +340,9 @@ impl Inode { } } -pub struct InodeBlocks<'a, 'b, S: 'a + Size, V: 'a + Volume>> { - fs: &'a Ext2, - inode: &'b Inode, +pub struct InodeBlocks<'a: 'b, 'b, S: 'a + Size, V: 'a + Volume>> +{ + inode: &'b Inode<'a, S, V>, index: usize, } @@ -339,15 +351,8 @@ impl<'a, 'b, S: Size + Copy, V: 'a + Volume>> where Error: From, { - pub fn new( - fs: &'a Ext2, - inode: &'b Inode, - ) -> InodeBlocks<'a, 'b, S, V> { - InodeBlocks { - fs: fs, - inode, - index: 0, - } + pub fn new(inode: &'b Inode<'a, S, V>) -> InodeBlocks<'a, 'b, S, V> { + InodeBlocks { inode, index: 0 } } } @@ -364,16 +369,24 @@ where .map(|block| { let block = block.get(); self.index += 1; - Address::with_block_size(block, 0, self.fs.log_block_size()) + Address::with_block_size( + block, + 0, + self.inode.fs.log_block_size(), + ) ..Address::with_block_size( block + 1, 0, - self.fs.log_block_size(), + self.inode.fs.log_block_size(), ) }) .and_then(|block| { let offset = block.start; - self.fs.volume.slice(block).map(|slice| (slice, offset)) + self.inode + .fs + .volume + .slice(block) + .map(|slice| (slice, offset)) }) } } @@ -456,7 +469,7 @@ mod tests { for inode in inodes { println!("{:?}", inode.0); let size = inode.0.size(); - for block in InodeBlocks::new(&fs, &inode.0) { + for block in InodeBlocks::new(&inode.0) { let (data, _) = block; assert_eq!(data.len(), fs.block_size()); println!("{:?}", &data[..size]); @@ -468,7 +481,6 @@ mod tests { #[test] fn read_inode() { - use std::str; let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Ext2::::new(file).unwrap();