implement doubly indirect pointer tables
This commit is contained in:
parent
30aed8bde7
commit
e6218401ce
126
src/fs.rs
126
src/fs.rs
|
@ -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();
|
||||||
|
|
||||||
|
|
Reference in a new issue