diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 7889ffc..8feccfa 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -1,12 +1,10 @@ use core::mem; -use core::fmt::{self, Debug}; -use core::nonzero::NonZero; use alloc::Vec; use error::Error; use sector::{Address, SectorSize}; -use volume::{Volume, VolumeSlice}; +use volume::Volume; use sys::superblock::Superblock; use sys::block_group::BlockGroupDescriptor; use sys::inode::Inode as RawInode; @@ -64,104 +62,11 @@ impl> Ext2 { }) } - #[allow(dead_code)] - fn update_global(&mut self) -> Result<(), Error> { - // superblock - { - let slice = VolumeSlice::from_cast( - &self.superblock.inner, - self.superblock.offset, - ); - let commit = slice.commit(); - self.volume.commit(commit).map_err(|err| err.into())?; - } - - // block group descriptors - let mut offset = self.block_groups.offset; - for descr in &self.block_groups.inner { - let slice = VolumeSlice::from_cast(descr, offset); - let commit = slice.commit(); - self.volume.commit(commit).map_err(|err| err.into())?; - offset = - offset + Address::from(mem::size_of::()); - } - - Ok(()) - } - - pub fn read_inode<'vol>( - &'vol self, - buf: &mut [u8], - inode: &Inode<'vol, S, V>, - ) -> Result { - let total_size = inode.size(); - let block_size = self.block_size(); - let mut offset = 0; - - for block in inode.blocks() { - match block { - Ok((data, _)) => { - let data_size = block_size - .min(total_size - offset) - .min(buf.len() - offset); - let end = offset + data_size; - buf[offset..end].copy_from_slice(&data[..data_size]); - offset += data_size; - } - Err(err) => return Err(err.into()), - } - } - - Ok(offset) - } - - pub fn write_inode<'vol>( - &'vol self, - _inode: &(Inode<'vol, S, V>, Address), - _buf: &[u8], - ) -> Result { - unimplemented!() - } - - pub fn root_inode<'vol>(&'vol self) -> (Inode<'vol, S, V>, Address) { - self.inode_nth(2).unwrap() - } - - pub fn inode_nth<'vol>( - &'vol self, - index: usize, - ) -> Option<(Inode<'vol, S, V>, Address)> { - self.inodes_nth(index).next() - } - - pub fn inodes<'vol>(&'vol self) -> Inodes<'vol, S, V> { - self.inodes_nth(1) - } - - pub fn inodes_nth<'vol>(&'vol self, index: usize) -> Inodes<'vol, S, V> { - assert!(index > 0, "inodes are 1-indexed"); - Inodes { - 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, - } - } - - fn superblock(&self) -> &Superblock { - &self.superblock.inner - } - - #[allow(dead_code)] - fn superblock_mut(&mut self) -> &mut Superblock { - &mut self.superblock.inner - } - pub fn version(&self) -> (u32, u16) { - (self.superblock().rev_major, self.superblock().rev_minor) + ( + self.superblock.inner.rev_major, + self.superblock.inner.rev_minor, + ) } pub fn inode_size(&self) -> usize { @@ -169,20 +74,21 @@ impl> Ext2 { mem::size_of::() } else { // note: inodes bigger than 128 are not supported - self.superblock().inode_size as usize + self.superblock.inner.inode_size as usize } } pub fn inodes_count(&self) -> usize { - self.superblock().inodes_per_group as _ + self.superblock.inner.inodes_per_group as _ } pub fn total_inodes_count(&self) -> usize { - self.superblock().inodes_count as _ + self.superblock.inner.inodes_count as _ } pub fn block_group_count(&self) -> Result { - self.superblock() + self.superblock + .inner .block_group_count() .map(|count| count as usize) .map_err(|(a, b)| Error::BadBlockGroupCount { @@ -192,19 +98,19 @@ impl> Ext2 { } pub fn total_block_count(&self) -> usize { - self.superblock().blocks_count as _ + self.superblock.inner.blocks_count as _ } pub fn free_block_count(&self) -> usize { - self.superblock().free_blocks_count as _ + self.superblock.inner.free_blocks_count as _ } pub fn block_size(&self) -> usize { - self.superblock().block_size() + self.superblock.inner.block_size() } pub fn log_block_size(&self) -> u32 { - self.superblock().log_block_size + 10 + self.superblock.inner.log_block_size + 10 } pub fn sector_size(&self) -> usize { @@ -216,340 +122,15 @@ impl> Ext2 { } } -impl> Debug for Ext2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Ext2<{}>", S::SIZE) - } -} - -pub struct Inodes<'vol, S: SectorSize, V: 'vol + Volume> { - fs: &'vol Ext2, - block_groups: &'vol [BlockGroupDescriptor], - log_block_size: u32, - inode_size: usize, - inodes_per_group: usize, - inodes_count: usize, - index: usize, -} - -impl<'vol, S: SectorSize, V: 'vol + Volume> Iterator - for Inodes<'vol, S, V> -{ - type Item = (Inode<'vol, S, V>, Address); - - fn next(&mut self) -> Option { - if self.index < self.inodes_count { - let block_group = (self.index - 1) / self.inodes_per_group; - let index = (self.index - 1) % self.inodes_per_group; - self.index += 1; - - let inodes_block = self.block_groups[block_group].inode_table_block; - - let offset = Address::with_block_size( - inodes_block, - (index * self.inode_size) as i32, - self.log_block_size, - ); - let raw = unsafe { - RawInode::find_inode(&self.fs.volume, offset, self.inode_size) - .ok() - }; - raw.map(|(raw, offset)| (Inode::new(self.fs, raw), offset)) - } else { - None - } - } -} - -#[derive(Debug, Clone)] -pub struct Inode<'vol, S: SectorSize, V: 'vol + Volume> { - fs: &'vol Ext2, - inner: RawInode, -} - -impl<'vol, S: SectorSize, V: 'vol + Volume> Inode<'vol, S, V> { - pub fn new(fs: &'vol Ext2, inner: RawInode) -> Inode<'vol, S, V> { - Inode { fs, inner } - } - - pub fn blocks<'inode>(&'inode self) -> InodeBlocks<'vol, 'inode, S, V> { - InodeBlocks { - inode: self, - index: 0, - } - } - - pub fn directory<'inode>( - &'inode self, - ) -> Option> { - use sys::inode::TypePerm; - if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } { - Some(Directory { - blocks: self.blocks(), - offset: 0, - buffer: None, - block_size: self.fs.block_size(), - }) - } else { - None - } - } - - pub fn block(&self, index: usize) -> Option> { - self.try_block(index).ok().and_then(|block| block) - } - - pub fn try_block( - &self, - mut index: usize, - ) -> Result>, Error> { - // number of blocks in direct table: 12 - // number of blocks in indirect table: block_size/4 - // why? - // - a block is n bytes long - // - a block address occupies 32 bits, or 4 bytes - // - thus, n/4 - // number of blocks in doubly table: (block_size/4)^2 - // why? - // - every entry in the doubly table points to another block - // - that's n/4 blocks, where n is the block size - // - every block contains n/4 block pointers - // - that's n/4 blocks with n/4 pointers each = (n/4)^2 - // number of blocks in triply table: (block_size/4)^3 - - fn block_index>( - volume: &V, - block: u32, - index: usize, - log_block_size: u32, - ) -> Result>, Error> { - let offset = (index * 4) as i32; - let end = offset + 4; - let addr = Address::with_block_size(block, offset, log_block_size); - let end = Address::with_block_size(block, end, log_block_size); - let block = volume.slice(addr..end); - match block { - Ok(block) => unsafe { - Ok(NonZero::new(block.dynamic_cast::().0)) - }, - Err(err) => Err(err.into()), - } - } - - let bs4 = self.fs.block_size() / 4; - let log_block_size = self.fs.log_block_size(); - - if index < 12 { - return Ok(NonZero::new(self.inner.direct_pointer[index])); - } - - index -= 12; - - if index < bs4 { - let block = self.inner.indirect_pointer; - return block_index(&self.fs.volume, block, index, log_block_size); - } - - index -= bs4; - - if index < bs4 * bs4 { - let indirect_index = index >> (log_block_size + 2); - let block = match block_index( - &self.fs.volume, - self.inner.doubly_indirect, - indirect_index, - log_block_size, - ) { - Ok(Some(block)) => block.get(), - Ok(None) => return Ok(None), - Err(err) => return Err(err), - }; - return block_index( - &self.fs.volume, - block, - index & (bs4 - 1), - log_block_size, - ); - } - - index -= bs4 * bs4; - - if index < bs4 * bs4 * bs4 { - let doubly_index = index >> (2 * log_block_size + 4); - let indirect = match block_index( - &self.fs.volume, - self.inner.triply_indirect, - doubly_index, - log_block_size, - ) { - Ok(Some(block)) => block.get(), - Ok(None) => return Ok(None), - Err(err) => return Err(err), - }; - let indirect_index = (index >> (log_block_size + 2)) & (bs4 - 1); - let block = match block_index( - &self.fs.volume, - indirect as u32, - indirect_index, - log_block_size, - ) { - Ok(Some(block)) => block.get(), - Ok(None) => return Ok(None), - Err(err) => return Err(err), - }; - return block_index( - &self.fs.volume, - block, - index & (bs4 - 1), - log_block_size, - ); - } - - Ok(None) - } - - pub fn in_use(&self) -> bool { - self.inner.hard_links > 0 - } - - pub fn uid(&self) -> u16 { - self.inner.uid - } - - pub fn sectors(&self) -> usize { - self.inner.sectors_count as usize - } - - pub fn size32(&self) -> u32 { - self.inner.size_low - } - - pub fn size64(&self) -> u64 { - self.inner.size_low as u64 | (self.inner.size_high as u64) << 32 - } - - #[cfg(target_pointer_width = "64")] - #[inline] - pub fn size(&self) -> usize { - self.size64() as usize - } - - #[cfg(target_pointer_width = "32")] - #[inline] - pub fn size(&self) -> usize { - self.size32() as usize - } -} - -pub struct InodeBlocks< - 'vol: 'inode, - 'inode, - S: SectorSize, - V: 'vol + Volume, -> { - inode: &'inode Inode<'vol, S, V>, - index: usize, -} - -impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume> Iterator - for InodeBlocks<'vol, 'inode, S, V> -{ - type Item = Result<(VolumeSlice<'vol, u8, S>, Address), Error>; - - fn next(&mut self) -> Option { - let block = self.inode.try_block(self.index); - let block = match block { - Ok(Some(ok)) => ok, - Ok(None) => return None, - Err(err) => return Some(Err(err)), - }; - - self.index += 1; - - let block = block.get(); - let log_block_size = self.inode.fs.log_block_size(); - let offset = Address::with_block_size(block, 0, log_block_size); - let end = Address::with_block_size(block + 1, 0, log_block_size); - - let slice = self.inode - .fs - .volume - .slice(offset..end) - .map(|slice| (slice, offset)) - .map_err(|err| err.into()); - Some(slice) - } -} - -pub struct Directory< - 'vol: 'inode, - 'inode, - S: SectorSize, - V: 'vol + Volume, -> { - blocks: InodeBlocks<'vol, 'inode, S, V>, - offset: usize, - buffer: Option>, - block_size: usize, -} - -impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume> Iterator - for Directory<'vol, 'inode, S, V> -{ - type Item = Result; - - fn next(&mut self) -> Option { - if self.buffer.is_none() || self.offset >= self.block_size { - self.buffer = match self.blocks.next() { - None => return None, - Some(Ok((block, _))) => Some(block), - Some(Err(err)) => return Some(Err(err)), - }; - - self.offset = 0; - } - - let buffer = &self.buffer.as_ref().unwrap()[self.offset..]; - - let inode = buffer[0] as u32 | (buffer[1] as u32) << 8 - | (buffer[2] as u32) << 16 - | (buffer[3] as u32) << 24; - if inode == 0 { - return None; - } - - let size = buffer[4] as u16 | (buffer[5] as u16) << 8; - let len = buffer[6]; - let ty = buffer[7]; - - let name = buffer[8..8 + len as usize].to_vec(); - - self.offset += size as usize; - - Some(Ok(DirectoryEntry { - name: name, - inode: inode as usize, - ty: ty, - })) - } -} - -#[derive(Clone)] -pub struct DirectoryEntry { - pub name: Vec, - pub inode: usize, - pub ty: u8, -} - #[cfg(test)] mod tests { use std::fs::File; use std::cell::RefCell; - use sector::{Address, SectorSize, Size512}; + use sector::{Address, Size512}; use volume::Volume; - use super::{Ext2, Inode}; + use super::Ext2; #[test] fn file_len() { @@ -587,133 +168,4 @@ mod tests { println!("version: {}.{}", vers.0, vers.1); assert_eq!(128, fs.inode_size()); } - - #[test] - fn inodes() { - let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::::new(file); - - assert!( - fs.is_ok(), - "Err({:?})", - fs.err().unwrap_or_else(|| unreachable!()), - ); - - let fs = fs.unwrap(); - - let inodes = fs.inodes().filter(|inode| inode.0.in_use()); - for inode in inodes { - println!("{:?}", inode); - } - } - - #[test] - fn inode_blocks() { - use std::str; - let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::::new(file).unwrap(); - - let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 - }); - for inode in inodes { - println!("{:?}", inode.0); - let size = inode.0.size(); - for block in inode.0.blocks() { - let (data, _) = block.unwrap(); - assert_eq!(data.len(), fs.block_size()); - println!("{:?}", &data[..size]); - let _ = str::from_utf8(&data[..size]) - .map(|string| println!("{}", string)); - } - } - } - - #[test] - fn read_inode() { - let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::::new(file).unwrap(); - - let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 - }); - for (inode, _) in inodes { - let mut buf = Vec::with_capacity(inode.size()); - unsafe { - buf.set_len(inode.size()); - } - let size = fs.read_inode(&mut buf[..], &inode); - assert!(size.is_ok()); - let size = size.unwrap(); - assert_eq!(size, inode.size()); - unsafe { - buf.set_len(size); - } - } - } - - #[test] - fn read_big() { - let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::::new(file).unwrap(); - - let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 - && inode.0.size() == 537600 - }); - for (inode, _) in inodes { - let mut buf = Vec::with_capacity(inode.size()); - unsafe { - buf.set_len(inode.size()); - } - let size = fs.read_inode(&mut buf[..], &inode); - assert!(size.is_ok()); - let size = size.unwrap(); - assert_eq!(size, inode.size()); - unsafe { - buf.set_len(size); - } - - for (i, &x) in buf.iter().enumerate() { - if i & 1 == 0 { - assert_eq!(x, b'u', "{}", i); - } else { - assert_eq!(x, b'\n', "{}", i); - } - } - } - } - - #[test] - fn walkdir() { - use std::str; - - fn walk<'vol, S: SectorSize, V: Volume>( - fs: &'vol Ext2, - inode: Inode<'vol, S, V>, - name: String, - ) { - inode.directory().map(|dir| { - for entry in dir { - assert!(entry.is_ok()); - let entry = entry.unwrap(); - let entry_name = str::from_utf8(&entry.name).unwrap_or("?"); - println!("{}/{} => {}", name, entry_name, entry.inode,); - if entry_name != "." && entry_name != ".." { - walk( - fs, - fs.inode_nth(entry.inode).unwrap().0, - format!("{}/{}", name, entry_name), - ); - } - } - }); - } - - let file = RefCell::new(File::open("ext2.img").unwrap()); - let fs = Ext2::::new(file).unwrap(); - - let (root, _) = fs.root_inode(); - walk(&fs, root, String::new()); - } } diff --git a/src/fs/sync.rs b/src/fs/sync.rs index 7b997f1..e9e0e00 100644 --- a/src/fs/sync.rs +++ b/src/fs/sync.rs @@ -42,45 +42,6 @@ impl> Synced> { Ext2::new(volume).map(|inner| Synced::with_inner(inner)) } - #[allow(dead_code)] - fn update_global(&mut self) -> Result<(), Error> { - self.inner().update_global() - } - - pub fn read_inode( - &self, - buf: &mut [u8], - inode: &Inode, - ) -> Result { - let total_size = inode.size(); - let block_size = self.block_size(); - let mut offset = 0; - - for block in inode.blocks() { - match block { - Ok((data, _)) => { - let data_size = block_size - .min(total_size - offset) - .min(buf.len() - offset); - let end = offset + data_size; - buf[offset..end].copy_from_slice(&data[..data_size]); - offset += data_size; - } - Err(err) => return Err(err.into()), - } - } - - Ok(offset) - } - - pub fn write_inode( - &self, - _inode: &(Inode, Address), - _buf: &[u8], - ) -> Result { - unimplemented!() - } - pub fn root_inode(&self) -> (Inode, Address) { self.inode_nth(2).unwrap() } @@ -106,42 +67,6 @@ impl> Synced> { } } - pub fn version(&self) -> (u32, u16) { - self.inner().version() - } - - pub fn inode_size(&self) -> usize { - self.inner().inode_size() - } - - pub fn inodes_count(&self) -> usize { - self.inner().inodes_count() - } - - pub fn total_inodes_count(&self) -> usize { - self.inner().total_inodes_count() - } - - pub fn block_group_count(&self) -> Result { - self.inner().block_group_count() - } - - pub fn total_block_count(&self) -> usize { - self.inner().total_block_count() - } - - pub fn free_block_count(&self) -> usize { - self.inner().free_block_count() - } - - pub fn block_size(&self) -> usize { - self.inner().block_size() - } - - pub fn log_block_size(&self) -> u32 { - self.inner().log_block_size() - } - pub fn sector_size(&self) -> usize { S::SIZE } @@ -216,6 +141,31 @@ impl> Inode { Inode { fs, inner } } + pub fn read(&self, buf: &mut [u8]) -> Result { + let total_size = self.size(); + let block_size = { + let fs = self.fs.inner(); + fs.block_size() + }; + let mut offset = 0; + + for block in self.blocks() { + match block { + Ok((data, _)) => { + let data_size = block_size + .min(total_size - offset) + .min(buf.len() - offset); + let end = offset + data_size; + buf[offset..end].copy_from_slice(&data[..data_size]); + offset += data_size; + } + Err(err) => return Err(err.into()), + } + } + + Ok(offset) + } + pub fn blocks(&self) -> InodeBlocks { InodeBlocks { inode: self.clone(), @@ -230,7 +180,10 @@ impl> Inode { blocks: self.blocks(), offset: 0, buffer: None, - block_size: self.fs.block_size(), + block_size: { + let fs = self.fs.inner(); + fs.block_size() + }, }) } else { None @@ -278,8 +231,10 @@ impl> Inode { } } - let bs4 = self.fs.block_size() / 4; - let log_block_size = self.fs.log_block_size(); + let fs = self.fs.inner(); + + let bs4 = fs.block_size() / 4; + let log_block_size = fs.log_block_size(); if index < 12 { return Ok(NonZero::new(self.inner.direct_pointer[index])); @@ -289,12 +244,7 @@ impl> Inode { if index < bs4 { let block = self.inner.indirect_pointer; - return block_index( - &self.fs.inner().volume, - block, - index, - log_block_size, - ); + return block_index(&fs.volume, block, index, log_block_size); } index -= bs4; @@ -302,7 +252,7 @@ impl> Inode { if index < bs4 * bs4 { let indirect_index = index >> (log_block_size + 2); let block = match block_index( - &self.fs.inner().volume, + &fs.volume, self.inner.doubly_indirect, indirect_index, log_block_size, @@ -312,7 +262,7 @@ impl> Inode { Err(err) => return Err(err), }; return block_index( - &self.fs.inner().volume, + &fs.volume, block, index & (bs4 - 1), log_block_size, @@ -324,7 +274,7 @@ impl> Inode { if index < bs4 * bs4 * bs4 { let doubly_index = index >> (2 * log_block_size + 4); let indirect = match block_index( - &self.fs.inner().volume, + &fs.volume, self.inner.triply_indirect, doubly_index, log_block_size, @@ -335,7 +285,7 @@ impl> Inode { }; let indirect_index = (index >> (log_block_size + 2)) & (bs4 - 1); let block = match block_index( - &self.fs.inner().volume, + &fs.volume, indirect as u32, indirect_index, log_block_size, @@ -345,7 +295,7 @@ impl> Inode { Err(err) => return Err(err), }; return block_index( - &self.fs.inner().volume, + &fs.volume, block, index & (bs4 - 1), log_block_size, @@ -406,13 +356,13 @@ impl> Iterator for InodeBlocks { }; self.index += 1; + let fs = self.inode.fs.inner(); let block = block.get(); - let log_block_size = self.inode.fs.log_block_size(); + let log_block_size = fs.log_block_size(); let offset = Address::with_block_size(block, 0, log_block_size); let end = Address::with_block_size(block + 1, 0, log_block_size); - let fs = self.inode.fs.inner(); let slice = fs.volume .slice(offset..end) .map(|slice| (slice.to_vec(), offset)) @@ -497,10 +447,11 @@ mod tests { ); let fs = fs.unwrap(); + let inner = fs.inner(); - let vers = fs.version(); + let vers = inner.version(); println!("version: {}.{}", vers.0, vers.1); - assert_eq!(128, fs.inode_size()); + assert_eq!(128, inner.inode_size()); } #[test] @@ -536,7 +487,10 @@ mod tests { let size = inode.0.size(); for block in inode.0.blocks() { let (data, _) = block.unwrap(); - assert_eq!(data.len(), fs.block_size()); + assert_eq!(data.len(), { + let fs = fs.inner(); + fs.block_size() + }); println!("{:?}", &data[..size]); let _ = str::from_utf8(&data[..size]) .map(|string| println!("{}", string)); @@ -557,7 +511,7 @@ mod tests { unsafe { buf.set_len(inode.size()); } - let size = fs.read_inode(&mut buf[..], &inode); + let size = inode.read(&mut buf[..]); assert!(size.is_ok()); let size = size.unwrap(); assert_eq!(size, inode.size()); @@ -581,7 +535,7 @@ mod tests { unsafe { buf.set_len(inode.size()); } - let size = fs.read_inode(&mut buf[..], &inode); + let size = inode.read(&mut buf[..]); assert!(size.is_ok()); let size = size.unwrap(); assert_eq!(size, inode.size());