add an InodeBlocks
Iterator
for iterating over the blocks of an inode
This commit is contained in:
parent
83a9d706a3
commit
30aed8bde7
220
src/fs.rs
220
src/fs.rs
|
@ -1,5 +1,6 @@
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use core::nonzero::NonZero;
|
||||||
|
|
||||||
use alloc::Vec;
|
use alloc::Vec;
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ use sector::{Address, Size};
|
||||||
use volume::{Volume, VolumeSlice};
|
use volume::{Volume, VolumeSlice};
|
||||||
use sys::superblock::Superblock;
|
use sys::superblock::Superblock;
|
||||||
use sys::block_group::BlockGroupDescriptor;
|
use sys::block_group::BlockGroupDescriptor;
|
||||||
use sys::inode::Inode;
|
use sys::inode::Inode as RawInode;
|
||||||
|
|
||||||
struct Struct<T, S: Size> {
|
struct Struct<T, S: Size> {
|
||||||
pub inner: T,
|
pub inner: T,
|
||||||
|
@ -90,11 +91,41 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
&(ref inode, offset): &(Inode, Address<S>),
|
&(ref inode, offset): &(Inode, Address<S>),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let slice = VolumeSlice::from_cast(inode, offset);
|
let slice = VolumeSlice::from_cast(&inode.inner, offset);
|
||||||
let commit = slice.commit();
|
let commit = slice.commit();
|
||||||
self.volume.commit(commit).map_err(|err| Error::from(err))
|
self.volume.commit(commit).map_err(|err| Error::from(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_inode(
|
||||||
|
&self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
inode: &Inode,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
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) {
|
||||||
|
let data_size = block_size
|
||||||
|
.min(total_size - read_size)
|
||||||
|
.min(buf.len() - offset);
|
||||||
|
let end = offset + data_size;
|
||||||
|
buf[offset..end].copy_from_slice(&data[..data_size]);
|
||||||
|
read_size += data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(read_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_inode(
|
||||||
|
&self,
|
||||||
|
&(ref inode, offset): &(Inode, Address<S>),
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn root_inode(&self) -> (Inode, Address<S>) {
|
pub fn root_inode(&self) -> (Inode, Address<S>) {
|
||||||
self.inode_nth(2).unwrap()
|
self.inode_nth(2).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -173,6 +204,14 @@ where
|
||||||
pub fn log_block_size(&self) -> u32 {
|
pub fn log_block_size(&self) -> u32 {
|
||||||
self.superblock().log_block_size + 10
|
self.superblock().log_block_size + 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sector_size(&self) -> usize {
|
||||||
|
S::SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_sector_size(&self) -> u32 {
|
||||||
|
S::LOG_SIZE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Inodes<'a, S: Size, V: 'a + Volume<u8, Address<S>>> {
|
pub struct Inodes<'a, S: Size, V: 'a + Volume<u8, Address<S>>> {
|
||||||
|
@ -204,18 +243,141 @@ where
|
||||||
|
|
||||||
let offset = Address::with_block_size(
|
let offset = Address::with_block_size(
|
||||||
inodes_block,
|
inodes_block,
|
||||||
index * self.inode_size,
|
(index * self.inode_size) as isize,
|
||||||
self.log_block_size,
|
self.log_block_size,
|
||||||
);
|
);
|
||||||
unsafe {
|
let raw = unsafe {
|
||||||
Inode::find_inode(self.volume, offset, self.inode_size).ok()
|
RawInode::find_inode(self.volume, offset, self.inode_size).ok()
|
||||||
}
|
};
|
||||||
|
raw.map(|(raw, offset)| (Inode::new(raw), offset))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Inode {
|
||||||
|
inner: RawInode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inode {
|
||||||
|
pub fn new(inner: RawInode) -> Inode {
|
||||||
|
Inode { inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block(&self, index: usize) -> Option<NonZero<usize>> {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
let bs4 = self.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 {
|
||||||
|
unimplemented!("doubly indirect pointer table");
|
||||||
|
} else if index < bs4 * bs4 * bs4 {
|
||||||
|
unimplemented!("triply indirect pointer table");
|
||||||
|
} else {
|
||||||
|
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<'a, 'b, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> {
|
||||||
|
fs: &'a Ext2<S, V>,
|
||||||
|
inode: &'b Inode,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, S: Size + Copy, V: 'a + Volume<u8, Address<S>>>
|
||||||
|
InodeBlocks<'a, 'b, S, V>
|
||||||
|
where
|
||||||
|
Error: From<V::Error>,
|
||||||
|
{
|
||||||
|
pub fn new(
|
||||||
|
fs: &'a Ext2<S, V>,
|
||||||
|
inode: &'b Inode,
|
||||||
|
) -> InodeBlocks<'a, 'b, S, V> {
|
||||||
|
InodeBlocks {
|
||||||
|
fs: fs,
|
||||||
|
inode,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, S: Size + Copy, V: 'a + Volume<u8, Address<S>>> Iterator
|
||||||
|
for InodeBlocks<'a, 'b, S, V>
|
||||||
|
where
|
||||||
|
Error: From<V::Error>,
|
||||||
|
{
|
||||||
|
type Item = (VolumeSlice<'a, u8, Address<S>>, Address<S>);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let block = self.inode.block(self.index);
|
||||||
|
block
|
||||||
|
.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 + 1,
|
||||||
|
0,
|
||||||
|
self.fs.log_block_size(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.and_then(|block| {
|
||||||
|
let offset = block.start;
|
||||||
|
self.fs.volume.slice(block).map(|slice| (slice, offset))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -224,7 +386,7 @@ mod tests {
|
||||||
use sector::{Address, Size512};
|
use sector::{Address, Size512};
|
||||||
use volume::Volume;
|
use volume::Volume;
|
||||||
|
|
||||||
use super::Ext2;
|
use super::{Ext2, InodeBlocks};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn file_len() {
|
fn file_len() {
|
||||||
|
@ -281,4 +443,48 @@ mod tests {
|
||||||
println!("{:?}", inode);
|
println!("{:?}", inode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inode_blocks() {
|
||||||
|
use std::str;
|
||||||
|
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() < 1024
|
||||||
|
});
|
||||||
|
for inode in inodes {
|
||||||
|
println!("{:?}", inode.0);
|
||||||
|
let size = inode.0.size();
|
||||||
|
for block in InodeBlocks::new(&fs, &inode.0) {
|
||||||
|
let (data, _) = block;
|
||||||
|
assert_eq!(data.len(), fs.block_size());
|
||||||
|
println!("{:?}", &data[..size]);
|
||||||
|
let _ = str::from_utf8(&data[..size])
|
||||||
|
.map(|string| println!("{}", string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_inode() {
|
||||||
|
use std::str;
|
||||||
|
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() < 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_eq!(size, Ok(inode.size()));
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(size.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#![feature(macro_lifetime_matcher)]
|
#![feature(macro_lifetime_matcher)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(step_trait)]
|
#![feature(step_trait)]
|
||||||
|
#![feature(nonzero)]
|
||||||
#![cfg_attr(all(not(test), feature = "no_std"), no_std)]
|
#![cfg_attr(all(not(test), feature = "no_std"), no_std)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
Reference in a new issue