enable reading the entire contents of inodes
This commit is contained in:
parent
117b8d4e75
commit
f83ad71b3c
205
src/fs.rs
205
src/fs.rs
|
@ -92,25 +92,24 @@ impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> {
|
||||||
inode: &Inode<'a, S, V>,
|
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 block_size = self.block_size();
|
let block_size = self.block_size();
|
||||||
let offset = 0;
|
let mut offset = 0;
|
||||||
|
|
||||||
for block in InodeBlocks::new(&inode) {
|
for block in InodeBlocks::new(&inode) {
|
||||||
match block {
|
match block {
|
||||||
Ok((data, _)) => {
|
Ok((data, _)) => {
|
||||||
let data_size = block_size
|
let data_size = block_size
|
||||||
.min(total_size - read_size)
|
.min(total_size - offset)
|
||||||
.min(buf.len() - offset);
|
.min(buf.len() - offset);
|
||||||
let end = offset + data_size;
|
let end = offset + data_size;
|
||||||
buf[offset..end].copy_from_slice(&data[..data_size]);
|
buf[offset..end].copy_from_slice(&data[..data_size]);
|
||||||
read_size += data_size;
|
offset += data_size;
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(read_size)
|
Ok(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_inode<'a>(
|
pub fn write_inode<'a>(
|
||||||
|
@ -273,6 +272,13 @@ impl<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> Inode<'a, S, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block(&self, index: usize) -> Option<NonZero<u32>> {
|
pub fn block(&self, index: usize) -> Option<NonZero<u32>> {
|
||||||
|
self.try_block(index).ok().and_then(|block| block)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_block(
|
||||||
|
&self,
|
||||||
|
mut index: usize,
|
||||||
|
) -> Result<Option<NonZero<u32>>, Error> {
|
||||||
// number of blocks in direct table: 12
|
// number of blocks in direct table: 12
|
||||||
// number of blocks in indirect table: block_size/4
|
// number of blocks in indirect table: block_size/4
|
||||||
// why?
|
// why?
|
||||||
|
@ -287,29 +293,95 @@ impl<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> Inode<'a, S, V> {
|
||||||
// - 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.fs.block_size() / 4;
|
fn block_index<S: Size, V: Volume<u8, Address<S>>>(
|
||||||
if index < 12 {
|
volume: &V,
|
||||||
NonZero::new(self.inner.direct_pointer[index])
|
block: u32,
|
||||||
} else if index < bs4 + 12 {
|
index: usize,
|
||||||
let block = self.inner.indirect_pointer;
|
log_block_size: u32,
|
||||||
let offset = index - 12;
|
) -> Result<Option<NonZero<u32>>, Error> {
|
||||||
let addr = Address::with_block_size(
|
let offset = (index * 4) as i32;
|
||||||
block,
|
let end = offset + 4;
|
||||||
offset as i32,
|
let addr = Address::with_block_size(block, offset, log_block_size);
|
||||||
self.fs.log_block_size(),
|
let end = Address::with_block_size(block, end, log_block_size);
|
||||||
);
|
let block = volume.slice(addr..end);
|
||||||
let size = Address::from(4_u64);
|
match block {
|
||||||
let slice = self.fs.volume.slice(addr..addr + size);
|
Ok(block) => unsafe {
|
||||||
slice.ok().and_then(|slice| unsafe {
|
Ok(NonZero::new(block.dynamic_cast::<u32>().0))
|
||||||
NonZero::new(u32::from_le(slice.dynamic_cast::<u32>().0))
|
},
|
||||||
})
|
Err(err) => Err(err.into()),
|
||||||
} else if index < bs4 * bs4 + bs4 + 12 {
|
}
|
||||||
unimplemented!("doubly indirect pointer table");
|
|
||||||
} else if index < bs4 * bs4 * bs4 + bs4 * bs4 + bs4 + 12 {
|
|
||||||
unimplemented!("triply indirect pointer table");
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
pub fn in_use(&self) -> bool {
|
||||||
|
@ -362,33 +434,30 @@ impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>>
|
||||||
impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator
|
impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator
|
||||||
for InodeBlocks<'a, 'b, S, V>
|
for InodeBlocks<'a, 'b, S, V>
|
||||||
{
|
{
|
||||||
type Item = Result<(VolumeSlice<'a, u8, Address<S>>, Address<S>), V::Error>;
|
type Item = Result<(VolumeSlice<'a, u8, Address<S>>, Address<S>), Error>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let block = self.inode.block(self.index);
|
let block = self.inode.try_block(self.index);
|
||||||
block
|
let block = match block {
|
||||||
.map(|block| {
|
Ok(Some(ok)) => ok,
|
||||||
let block = block.get();
|
Ok(None) => return None,
|
||||||
self.index += 1;
|
Err(err) => return Some(Err(err)),
|
||||||
Address::with_block_size(
|
};
|
||||||
block,
|
|
||||||
0,
|
self.index += 1;
|
||||||
self.inode.fs.log_block_size(),
|
|
||||||
)
|
let block = block.get();
|
||||||
..Address::with_block_size(
|
let log_block_size = self.inode.fs.log_block_size();
|
||||||
block + 1,
|
let offset = Address::with_block_size(block, 0, log_block_size);
|
||||||
0,
|
let end = Address::with_block_size(block + 1, 0, log_block_size);
|
||||||
self.inode.fs.log_block_size(),
|
|
||||||
)
|
let slice = self.inode
|
||||||
})
|
.fs
|
||||||
.map(|block| {
|
.volume
|
||||||
let offset = block.start;
|
.slice(offset..end)
|
||||||
self.inode
|
.map(|slice| (slice, offset))
|
||||||
.fs
|
.map_err(|err| err.into());
|
||||||
.volume
|
Some(slice)
|
||||||
.slice(block)
|
|
||||||
.map(|slice| (slice, offset))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,4 +571,36 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_big() {
|
||||||
|
let file = RefCell::new(File::open("ext2.img").unwrap());
|
||||||
|
let fs = Ext2::<Size512, _>::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue