implement doubly indirect pointer tables

This commit is contained in:
Szymon Walter 2018-03-20 15:44:12 +01:00
parent 30aed8bde7
commit e6218401ce

126
src/fs.rs
View file

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