make Buffer generic over its index, instead of usize

This commit is contained in:
Szymon Walter 2018-03-20 12:30:36 +01:00
parent 7e0af1b8f6
commit 7c57c047bc
7 changed files with 251 additions and 148 deletions

View file

@ -4,39 +4,33 @@ use core::ops::{Add, Sub};
use core::fmt::{self, Debug, Display, LowerHex}; use core::fmt::{self, Debug, Display, LowerHex};
use core::iter::Step; use core::iter::Step;
pub trait Size { pub trait Size: PartialOrd {
// log_block_size = log_2(block_size) - 10 // log_block_size = log_2(block_size)
// i.e. block_size = 1024 << log_block_size
const LOG_SIZE: u32; const LOG_SIZE: u32;
const SIZE: usize = 1024 << Self::LOG_SIZE; const SIZE: usize = 1 << Self::LOG_SIZE;
const OFFSET_MASK: usize = Self::SIZE - 1; const OFFSET_MASK: usize = Self::SIZE - 1;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size1024; pub struct Size512;
impl Size for Size1024 { impl Size for Size512 {
const LOG_SIZE: u32 = 0; const LOG_SIZE: u32 = 9;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size2048; pub struct Size2048;
impl Size for Size2048 { impl Size for Size2048 {
const LOG_SIZE: u32 = 1; const LOG_SIZE: u32 = 11;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size4096; pub struct Size4096;
impl Size for Size4096 { impl Size for Size4096 {
const LOG_SIZE: u32 = 2; const LOG_SIZE: u32 = 12;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] /// Address in a physical sector
pub struct Size8192; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
impl Size for Size8192 {
const LOG_SIZE: u32 = 3;
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address<S: Size> { pub struct Address<S: Size> {
block: usize, block: usize,
offset: usize, offset: usize,
@ -55,14 +49,30 @@ impl<S: Size> Address<S> {
} }
pub fn new(block: usize, offset: isize) -> Address<S> { pub fn new(block: usize, offset: isize) -> Address<S> {
let block = (block as isize + (offset >> (S::LOG_SIZE + 10))) as usize; let block = (block as isize + (offset >> S::LOG_SIZE)) as usize;
let offset = offset.abs() as usize & S::OFFSET_MASK; let offset = offset.abs() as usize & S::OFFSET_MASK;
unsafe { Address::new_unchecked(block, offset) } unsafe { Address::new_unchecked(block, offset) }
} }
pub fn with_block_size(
block: usize,
offset: usize,
log_block_size: u32,
) -> Address<S> {
let log_diff = log_block_size as isize - S::LOG_SIZE as isize;
let top_offset = offset >> S::LOG_SIZE;
let offset = offset >> log_diff;
let block = block << log_diff | top_offset;
Address::new(block, offset as isize)
}
pub fn index64(&self) -> u64 {
((self.block as u64) << S::LOG_SIZE) + self.offset as u64
}
pub fn into_index(&self) -> Option<usize> { pub fn into_index(&self) -> Option<usize> {
self.block self.block
.checked_shl(S::LOG_SIZE + 10) .checked_shl(S::LOG_SIZE)
.and_then(|block| block.checked_add(self.offset)) .and_then(|block| block.checked_add(self.offset))
} }
@ -137,9 +147,17 @@ impl<S: Size> LowerHex for Address<S> {
} }
} }
impl<S: Size> From<u64> for Address<S> {
fn from(idx: u64) -> Address<S> {
let block = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK as u64;
Address::new(block as usize, offset as isize)
}
}
impl<S: Size> From<usize> for Address<S> { impl<S: Size> From<usize> for Address<S> {
fn from(idx: usize) -> Address<S> { fn from(idx: usize) -> Address<S> {
let block = idx >> (S::LOG_SIZE + 10); let block = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK; let offset = idx & S::OFFSET_MASK;
Address::new(block, offset as isize) Address::new(block, offset as isize)
} }
@ -172,13 +190,13 @@ mod tests {
#[test] #[test]
fn arithmetic() { fn arithmetic() {
assert_eq!( assert_eq!(
Address::<Size1024>::new(0, 1024), Address::<Size512>::new(0, 512),
Address::<Size1024>::new(1, 0), Address::<Size512>::new(1, 0),
); );
assert_eq!( assert_eq!(
Address::<Size1024>::new(2, -512), Address::<Size512>::new(2, -256),
Address::<Size1024>::new(1, 512), Address::<Size512>::new(1, 256),
); );
let a = Address::<Size2048>::new(0, 1024); let a = Address::<Size2048>::new(0, 1024);
@ -186,9 +204,9 @@ mod tests {
assert_eq!(a + b, Address::<Size2048>::new(1, 0)); assert_eq!(a + b, Address::<Size2048>::new(1, 0));
assert_eq!((a + b).into_index(), Some(2048)); assert_eq!((a + b).into_index(), Some(2048));
let a = Address::<Size1024>::new(0, 4096); let a = Address::<Size512>::new(0, 2048);
let b = Address::<Size1024>::new(0, 512); let b = Address::<Size512>::new(0, 256);
assert_eq!(a - b, Address::<Size1024>::new(3, 512)); assert_eq!(a - b, Address::<Size512>::new(3, 256));
assert_eq!((a - b).into_index(), Some(3584)); assert_eq!((a - b).into_index(), Some(1792));
} }
} }

View file

@ -7,6 +7,7 @@ use alloc::boxed::Box;
use alloc::borrow::{Cow, ToOwned}; use alloc::borrow::{Cow, ToOwned};
use error::Infallible; use error::Infallible;
use block::{Address, Size};
pub mod length; pub mod length;
use self::length::Length; use self::length::Length;
@ -21,14 +22,17 @@ where
fn len(&self) -> Length<Idx>; fn len(&self) -> Length<Idx>;
fn commit( fn commit(
&mut self, &mut self,
slice: Option<BufferCommit<T>>, slice: Option<BufferCommit<T, Idx>>,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<Idx>, range: Range<Idx>,
) -> BufferSlice<'a, T>; ) -> BufferSlice<'a, T, Idx>;
fn slice<'a>(&'a self, range: Range<Idx>) -> Option<BufferSlice<'a, T>> { fn slice<'a>(
&'a self,
range: Range<Idx>,
) -> Option<BufferSlice<'a, T, Idx>> {
if self.len() >= range.end && self.len() > range.start { if self.len() >= range.end && self.len() > range.start {
unsafe { Some(self.slice_unchecked(range)) } unsafe { Some(self.slice_unchecked(range)) }
} else { } else {
@ -37,29 +41,34 @@ where
} }
} }
pub struct BufferSlice<'a, T: 'a> pub struct BufferSlice<'a, T: 'a, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
{ {
inner: Cow<'a, [T]>, inner: Cow<'a, [T]>,
index: usize, index: Idx,
} }
impl<T> BufferSlice<'static, T> impl<T, Idx: Default> BufferSlice<'static, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
{ {
pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T> { pub fn with_static(inner: &'static [T]) -> BufferSlice<'static, T, Idx> {
BufferSlice { BufferSlice {
inner: Cow::Borrowed(inner), inner: Cow::Borrowed(inner),
index: 0, index: Idx::default(),
} }
} }
}
impl<T, Idx> BufferSlice<'static, T, Idx>
where
[T]: ToOwned,
{
pub fn new_owned( pub fn new_owned(
inner: <[T] as ToOwned>::Owned, inner: <[T] as ToOwned>::Owned,
index: usize, index: Idx,
) -> BufferSlice<'static, T> { ) -> BufferSlice<'static, T, Idx> {
BufferSlice { BufferSlice {
inner: Cow::Owned(inner), inner: Cow::Owned(inner),
index, index,
@ -67,11 +76,11 @@ where
} }
} }
impl<'a, T> BufferSlice<'a, T> impl<'a, T, Idx> BufferSlice<'a, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
{ {
pub fn new(inner: &'a [T], index: usize) -> BufferSlice<'a, T> { pub fn new(inner: &'a [T], index: Idx) -> BufferSlice<'a, T, Idx> {
BufferSlice { BufferSlice {
inner: Cow::Borrowed(inner), inner: Cow::Borrowed(inner),
index, index,
@ -85,14 +94,13 @@ where
} }
} }
#[inline] pub fn at_index(&self) -> &Idx {
pub fn at_index(&self) -> usize { &self.index
self.index
} }
} }
impl<'a> BufferSlice<'a, u8> { impl<'a, Idx: Copy> BufferSlice<'a, u8, Idx> {
pub unsafe fn dynamic_cast<T: Copy>(&self) -> (T, usize) { pub unsafe fn dynamic_cast<T: Copy>(&self) -> (T, Idx) {
assert!(self.inner.len() >= mem::size_of::<T>()); assert!(self.inner.len() >= mem::size_of::<T>());
let index = self.index; let index = self.index;
let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()); let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap());
@ -101,8 +109,8 @@ impl<'a> BufferSlice<'a, u8> {
pub fn from_cast<T: Copy>( pub fn from_cast<T: Copy>(
cast: &'a T, cast: &'a T,
index: usize, index: Idx,
) -> BufferSlice<'a, u8> { ) -> BufferSlice<'a, u8, Idx> {
let len = mem::size_of::<T>(); let len = mem::size_of::<T>();
let ptr = cast as *const T as *const u8; let ptr = cast as *const T as *const u8;
let slice = unsafe { slice::from_raw_parts(ptr, len) }; let slice = unsafe { slice::from_raw_parts(ptr, len) };
@ -110,11 +118,11 @@ impl<'a> BufferSlice<'a, u8> {
} }
} }
impl<'a, T> BufferSlice<'a, T> impl<'a, T, Idx> BufferSlice<'a, T, Idx>
where where
[T]: ToOwned<Owned = Vec<T>>, [T]: ToOwned<Owned = Vec<T>>,
{ {
pub fn commit(self) -> Option<BufferCommit<T>> { pub fn commit(self) -> Option<BufferCommit<T, Idx>> {
if self.is_mutated() { if self.is_mutated() {
Some(BufferCommit::new(self.inner.into_owned(), self.index)) Some(BufferCommit::new(self.inner.into_owned(), self.index))
} else { } else {
@ -123,7 +131,7 @@ where
} }
} }
impl<'a, T> AsRef<[T]> for BufferSlice<'a, T> impl<'a, T, Idx> AsRef<[T]> for BufferSlice<'a, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
{ {
@ -132,7 +140,7 @@ where
} }
} }
impl<'a, T> AsMut<[T]> for BufferSlice<'a, T> impl<'a, T, Idx> AsMut<[T]> for BufferSlice<'a, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
<[T] as ToOwned>::Owned: AsMut<[T]>, <[T] as ToOwned>::Owned: AsMut<[T]>,
@ -142,7 +150,7 @@ where
} }
} }
impl<'a, T> Deref for BufferSlice<'a, T> impl<'a, T, Idx> Deref for BufferSlice<'a, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
{ {
@ -153,7 +161,7 @@ where
} }
} }
impl<'a, T> DerefMut for BufferSlice<'a, T> impl<'a, T, Idx> DerefMut for BufferSlice<'a, T, Idx>
where where
[T]: ToOwned, [T]: ToOwned,
<[T] as ToOwned>::Owned: AsMut<[T]>, <[T] as ToOwned>::Owned: AsMut<[T]>,
@ -163,17 +171,22 @@ where
} }
} }
pub struct BufferCommit<T> { pub struct BufferCommit<T, Idx> {
inner: Vec<T>, inner: Vec<T>,
index: usize, index: Idx,
} }
impl<T> BufferCommit<T> { impl<T, Idx: Default> BufferCommit<T, Idx> {
pub fn with_vec(inner: Vec<T>) -> BufferCommit<T> { pub fn with_vec(inner: Vec<T>) -> BufferCommit<T, Idx> {
BufferCommit { inner, index: 0 } BufferCommit {
inner,
index: Idx::default(),
} }
}
}
pub fn new(inner: Vec<T>, index: usize) -> BufferCommit<T> { impl<T, Idx> BufferCommit<T, Idx> {
pub fn new(inner: Vec<T>, index: Idx) -> BufferCommit<T, Idx> {
BufferCommit { inner, index } BufferCommit { inner, index }
} }
@ -181,25 +194,24 @@ impl<T> BufferCommit<T> {
self.inner self.inner
} }
#[inline] pub fn at_index(&self) -> &Idx {
pub fn at_index(&self) -> usize { &self.index
self.index
} }
} }
impl<T> AsRef<[T]> for BufferCommit<T> { impl<T, Idx> AsRef<[T]> for BufferCommit<T, Idx> {
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.inner.as_ref() self.inner.as_ref()
} }
} }
impl<T> AsMut<[T]> for BufferCommit<T> { impl<T, Idx> AsMut<[T]> for BufferCommit<T, Idx> {
fn as_mut(&mut self) -> &mut [T] { fn as_mut(&mut self) -> &mut [T] {
self.inner.as_mut() self.inner.as_mut()
} }
} }
impl<T> Deref for BufferCommit<T> { impl<T, Idx> Deref for BufferCommit<T, Idx> {
type Target = [T]; type Target = [T];
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -207,7 +219,7 @@ impl<T> Deref for BufferCommit<T> {
} }
} }
impl<T> DerefMut for BufferCommit<T> { impl<T, Idx> DerefMut for BufferCommit<T, Idx> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut() self.as_mut()
} }
@ -215,20 +227,20 @@ impl<T> DerefMut for BufferCommit<T> {
macro_rules! impl_slice { macro_rules! impl_slice {
(@inner $buffer:ty $( , $lt:lifetime )* ) => { (@inner $buffer:ty $( , $lt:lifetime )* ) => {
impl<$( $lt, )* T> Buffer<T, usize> for $buffer impl<$( $lt, )* S: Size + PartialOrd + Copy, T> Buffer<T, Address<S>> for $buffer
where where
T: Clone, T: Clone,
[T]: ToOwned, [T]: ToOwned,
{ {
type Error = Infallible; type Error = Infallible;
fn len(&self) -> Length<usize> { fn len(&self) -> Length<Address<S>> {
Length::Bounded(<Self as AsRef<[T]>>::as_ref(self).len()) Length::Bounded(Address::from(<Self as AsRef<[T]>>::as_ref(self).len()))
} }
fn commit(&mut self, slice: Option<BufferCommit<T>>) -> Result<(), Infallible> { fn commit(&mut self, slice: Option<BufferCommit<T, Address<S>>>) -> Result<(), Infallible> {
slice.map(|slice| { slice.map(|slice| {
let index = slice.at_index(); let index = slice.at_index().index64() as usize;
let end = index + slice.as_ref().len(); let end = index + slice.as_ref().len();
// XXX: it would be much better to drop the contents of dst // XXX: it would be much better to drop the contents of dst
// and move the contents of slice instead of cloning // and move the contents of slice instead of cloning
@ -241,9 +253,10 @@ macro_rules! impl_slice {
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<Address<S>>,
) -> BufferSlice<'a, T> { ) -> BufferSlice<'a, T, Address<S>> {
let index = range.start; let index = range.start;
let range = range.start.index64() as usize..range.end.index64() as usize;
BufferSlice::new( BufferSlice::new(
<Self as AsRef<[T]>>::as_ref(self).get_unchecked(range), <Self as AsRef<[T]>>::as_ref(self).get_unchecked(range),
index, index,
@ -270,33 +283,35 @@ mod file {
use std::fs::File; use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use block::{Address, Size};
use super::{Buffer, BufferCommit, BufferSlice}; use super::{Buffer, BufferCommit, BufferSlice};
use super::length::Length; use super::length::Length;
impl Buffer<u8, usize> for RefCell<File> { impl<S: Size + PartialOrd + Copy> Buffer<u8, Address<S>> for RefCell<File> {
type Error = io::Error; type Error = io::Error;
fn len(&self) -> Length<usize> { fn len(&self) -> Length<Address<S>> {
Length::Bounded( Length::Bounded(
self.borrow() self.borrow()
.metadata() .metadata()
.map(|data| data.len() as usize) .map(|data| Address::from(data.len()))
.unwrap_or(0), .unwrap_or(Address::from(0_usize)),
) )
} }
fn commit( fn commit(
&mut self, &mut self,
slice: Option<BufferCommit<u8>>, slice: Option<BufferCommit<u8, Address<S>>>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
slice slice
.map(|slice| { .map(|slice| {
let index = slice.at_index(); let index = *slice.at_index();
let end = index + slice.as_ref().len(); let end = index + Address::from(slice.as_ref().len());
let mut refmut = self.borrow_mut(); let mut refmut = self.borrow_mut();
refmut refmut
.seek(SeekFrom::Start(index as u64)) .seek(SeekFrom::Start(index.index64()))
.and_then(|_| refmut.write(&slice.as_ref()[index..end])) .and_then(|_| refmut.write(slice.as_ref()))
.map(|_| ()) .map(|_| ())
}) })
.unwrap_or(Ok(())) .unwrap_or(Ok(()))
@ -304,15 +319,15 @@ mod file {
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<Address<S>>,
) -> BufferSlice<'a, u8> { ) -> BufferSlice<'a, u8, Address<S>> {
let index = range.start; let index = range.start;
let len = range.end - range.start; let len = range.end - range.start;
let mut vec = Vec::with_capacity(len); let mut vec = Vec::with_capacity(len.index64() as usize);
vec.set_len(len); vec.set_len(len.index64() as usize);
let mut refmut = self.borrow_mut(); let mut refmut = self.borrow_mut();
refmut refmut
.seek(SeekFrom::Start(index as u64)) .seek(SeekFrom::Start(index.index64()))
.and_then(|_| refmut.read_exact(&mut vec[..])) .and_then(|_| refmut.read_exact(&mut vec[..]))
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
panic!("could't read from File Buffer: {:?}", err) panic!("could't read from File Buffer: {:?}", err)
@ -322,14 +337,16 @@ mod file {
fn slice<'a>( fn slice<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<Address<S>>,
) -> Option<BufferSlice<'a, u8>> { ) -> Option<BufferSlice<'a, u8, Address<S>>> {
let index = range.start; let index = range.start;
let mut vec = Vec::with_capacity(range.end - range.start); let mut vec = Vec::with_capacity(
(range.end - range.start).index64() as usize,
);
let mut refmut = self.borrow_mut(); let mut refmut = self.borrow_mut();
refmut refmut
.seek(SeekFrom::Start(index as u64)) .seek(SeekFrom::Start(index.index64()))
.and_then(|_| refmut.read_exact(&mut vec[range])) .and_then(|_| refmut.read_exact(&mut vec[..]))
.map(move |_| BufferSlice::new_owned(vec, index)) .map(move |_| BufferSlice::new_owned(vec, index))
.ok() .ok()
} }
@ -338,13 +355,19 @@ mod file {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use block::{Address, Size512};
use super::*; use super::*;
#[test] #[test]
fn buffer() { fn buffer() {
let mut buffer = vec![0; 1024]; let mut buffer = vec![0; 1024];
let commit = { let commit = {
let mut slice = buffer.slice(256..512).unwrap(); let mut slice = buffer
.slice(
Address::<Size512>::from(256_usize)
..Address::<Size512>::from(512_usize),
)
.unwrap();
slice.iter_mut().for_each(|x| *x = 1); slice.iter_mut().for_each(|x| *x = 1);
slice.commit() slice.commit()
}; };

View file

@ -6,6 +6,7 @@ use std::io;
pub enum Error { pub enum Error {
BadMagic(u16), BadMagic(u16),
OutOfBounds(usize), OutOfBounds(usize),
AddressOutOfBounds(usize, usize, usize),
BadBlockGroupCount(u32, u32), BadBlockGroupCount(u32, u32),
#[cfg(any(test, not(feature = "no_std")))] #[cfg(any(test, not(feature = "no_std")))]
Io(io::Error), Io(io::Error),

View file

@ -1,41 +1,45 @@
use core::mem; use core::mem;
use core::marker::PhantomData;
use alloc::Vec; use alloc::Vec;
use error::Error; use error::Error;
use block::Address; // TODO use block::{Address, Size};
use buffer::{Buffer, BufferSlice}; use buffer::{Buffer, BufferSlice};
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;
struct Struct<T> { struct Struct<T, S: Size> {
pub inner: T, pub inner: T,
pub offset: usize, pub offset: Address<S>,
} }
impl<T> From<(T, usize)> for Struct<T> { impl<T, S: Size> From<(T, Address<S>)> for Struct<T, S> {
#[inline] #[inline]
fn from((inner, offset): (T, usize)) -> Struct<T> { fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> {
Struct { inner, offset } Struct { inner, offset }
} }
} }
/// Safe wrapper for raw sys structs /// Safe wrapper for raw sys structs
pub struct Ext2<B: Buffer<u8, usize>> { pub struct Ext2<S: Size, B: Buffer<u8, Address<S>>> {
buffer: B, buffer: B,
superblock: Struct<Superblock>, superblock: Struct<Superblock, S>,
block_groups: Struct<Vec<BlockGroupDescriptor>>, block_groups: Struct<Vec<BlockGroupDescriptor>, S>,
} }
impl<B: Buffer<u8, usize>> Ext2<B> impl<S: Size + Copy, B: Buffer<u8, Address<S>>> Ext2<S, B>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
pub fn new(buffer: B) -> Result<Ext2<B>, Error> { pub fn new(buffer: B) -> Result<Ext2<S, B>, Error> {
let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) }; let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) };
let block_size = superblock.inner.block_size(); let block_groups_offset = Address::with_block_size(
let block_groups_offset = superblock.inner.first_data_block as usize + 1,
(superblock.inner.first_data_block as usize + 1) * block_size; 0,
superblock.inner.log_block_size + 10,
);
let block_groups_count = superblock let block_groups_count = superblock
.inner .inner
.block_group_count() .block_group_count()
@ -74,7 +78,8 @@ where
let slice = BufferSlice::from_cast(descr, offset); let slice = BufferSlice::from_cast(descr, offset);
let commit = slice.commit(); let commit = slice.commit();
self.buffer.commit(commit).map_err(|err| Error::from(err))?; self.buffer.commit(commit).map_err(|err| Error::from(err))?;
offset += mem::size_of::<BlockGroupDescriptor>(); offset =
offset + Address::from(mem::size_of::<BlockGroupDescriptor>());
} }
Ok(()) Ok(())
@ -83,35 +88,36 @@ where
#[allow(dead_code)] #[allow(dead_code)]
fn update_inode( fn update_inode(
&mut self, &mut self,
&(ref inode, offset): &(Inode, usize), &(ref inode, offset): &(Inode, Address<S>),
) -> Result<(), Error> { ) -> Result<(), Error> {
let slice = BufferSlice::from_cast(inode, offset); let slice = BufferSlice::from_cast(inode, offset);
let commit = slice.commit(); let commit = slice.commit();
self.buffer.commit(commit).map_err(|err| Error::from(err)) self.buffer.commit(commit).map_err(|err| Error::from(err))
} }
pub fn root_inode(&self) -> (Inode, usize) { pub fn root_inode(&self) -> (Inode, Address<S>) {
self.inode_nth(2).unwrap() self.inode_nth(2).unwrap()
} }
pub fn inode_nth(&self, index: usize) -> Option<(Inode, usize)> { pub fn inode_nth(&self, index: usize) -> Option<(Inode, Address<S>)> {
self.inodes_nth(index).next() self.inodes_nth(index).next()
} }
pub fn inodes<'a>(&'a self) -> Inodes<'a, B> { pub fn inodes<'a>(&'a self) -> Inodes<'a, S, B> {
self.inodes_nth(1) self.inodes_nth(1)
} }
pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, B> { pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, B> {
assert!(index > 0, "inodes are 1-indexed"); assert!(index > 0, "inodes are 1-indexed");
Inodes { Inodes {
buffer: &self.buffer, buffer: &self.buffer,
block_groups: &self.block_groups.inner, block_groups: &self.block_groups.inner,
block_size: self.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,
} }
} }
@ -163,23 +169,29 @@ where
pub fn block_size(&self) -> usize { pub fn block_size(&self) -> usize {
self.superblock().block_size() self.superblock().block_size()
} }
pub fn log_block_size(&self) -> u32 {
self.superblock().log_block_size
}
} }
pub struct Inodes<'a, B: 'a + Buffer<u8, usize>> { pub struct Inodes<'a, S: Size, B: 'a + Buffer<u8, Address<S>>> {
buffer: &'a B, buffer: &'a B,
block_groups: &'a [BlockGroupDescriptor], block_groups: &'a [BlockGroupDescriptor],
block_size: usize, 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, B: 'a + Buffer<u8, usize>> Iterator for Inodes<'a, B> impl<'a, S: Size + Copy, B: 'a + Buffer<u8, Address<S>>> Iterator
for Inodes<'a, S, B>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
type Item = (Inode, usize); type Item = (Inode, 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 {
@ -190,8 +202,11 @@ where
let inodes_block = let inodes_block =
self.block_groups[block_group].inode_table_block as usize; self.block_groups[block_group].inode_table_block as usize;
let offset = let offset = Address::with_block_size(
inodes_block * self.block_size + index * self.inode_size; inodes_block,
index * self.inode_size,
self.log_block_size,
);
unsafe { unsafe {
Inode::find_inode(self.buffer, offset, self.inode_size).ok() Inode::find_inode(self.buffer, offset, self.inode_size).ok()
} }
@ -206,6 +221,7 @@ mod tests {
use std::fs::File; use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use block::{Address, Size512};
use buffer::Buffer; use buffer::Buffer;
use super::Ext2; use super::Ext2;
@ -213,13 +229,21 @@ mod tests {
#[test] #[test]
fn file_len() { fn file_len() {
let file = RefCell::new(File::open("ext2.img").unwrap()); let file = RefCell::new(File::open("ext2.img").unwrap());
assert_eq!(unsafe { file.slice_unchecked(1024..2048).len() }, 1024); assert_eq!(
unsafe {
file.slice_unchecked(
Address::<Size512>::from(1024_usize)
..Address::<Size512>::from(2048_usize),
).len()
},
1024
);
} }
#[test] #[test]
fn file() { fn file() {
let file = RefCell::new(File::open("ext2.img").unwrap()); let file = RefCell::new(File::open("ext2.img").unwrap());
let fs = Ext2::new(file); let fs = Ext2::<Size512, _>::new(file);
assert!( assert!(
fs.is_ok(), fs.is_ok(),
@ -237,7 +261,7 @@ mod tests {
#[test] #[test]
fn inodes() { fn inodes() {
let file = RefCell::new(File::open("ext2.img").unwrap()); let file = RefCell::new(File::open("ext2.img").unwrap());
let fs = Ext2::new(file); let fs = Ext2::<Size512, _>::new(file);
assert!( assert!(
fs.is_ok(), fs.is_ok(),

View file

@ -4,6 +4,7 @@ use core::fmt::{self, Debug};
use alloc::Vec; use alloc::Vec;
use error::Error; use error::Error;
use block::{Address, Size};
use buffer::Buffer; use buffer::Buffer;
/// The Block Group Descriptor Table contains a descriptor for each block group /// The Block Group Descriptor Table contains a descriptor for each block group
@ -51,16 +52,24 @@ impl Debug for BlockGroupDescriptor {
} }
impl BlockGroupDescriptor { impl BlockGroupDescriptor {
pub unsafe fn find_descriptor<B: Buffer<u8, usize>>( pub unsafe fn find_descriptor<
S: Size + Copy + PartialOrd,
B: Buffer<u8, Address<S>>,
>(
haystack: &B, haystack: &B,
offset: usize, offset: Address<S>,
) -> Result<(BlockGroupDescriptor, usize), Error> ) -> Result<(BlockGroupDescriptor, Address<S>), Error>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
let end = offset + mem::size_of::<BlockGroupDescriptor>(); let end =
offset + Address::from(mem::size_of::<BlockGroupDescriptor>());
if haystack.len() < end { if haystack.len() < end {
return Err(Error::OutOfBounds(end)); return Err(Error::AddressOutOfBounds(
end.block(),
end.offset(),
end.block_size(),
));
} }
let descr = haystack let descr = haystack
@ -70,22 +79,31 @@ impl BlockGroupDescriptor {
Ok(descr) Ok(descr)
} }
pub unsafe fn find_descriptor_table<B: Buffer<u8, usize>>( pub unsafe fn find_descriptor_table<
S: Size + Copy + PartialOrd,
B: Buffer<u8, Address<S>>,
>(
haystack: &B, haystack: &B,
offset: usize, offset: Address<S>,
count: usize, count: usize,
) -> Result<(Vec<BlockGroupDescriptor>, usize), Error> ) -> Result<(Vec<BlockGroupDescriptor>, Address<S>), Error>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
let end = offset + count * mem::size_of::<BlockGroupDescriptor>(); let end = offset
+ Address::from(count * mem::size_of::<BlockGroupDescriptor>());
if haystack.len() < end { if haystack.len() < end {
return Err(Error::OutOfBounds(end)); return Err(Error::AddressOutOfBounds(
end.block(),
end.offset(),
end.block_size(),
));
} }
let mut vec = Vec::with_capacity(count); let mut vec = Vec::with_capacity(count);
for i in 0..count { for i in 0..count {
let offset = offset + i * mem::size_of::<BlockGroupDescriptor>(); let offset = offset
+ Address::from(i * mem::size_of::<BlockGroupDescriptor>());
vec.push({ vec.push({
BlockGroupDescriptor::find_descriptor(haystack, offset)?.0 BlockGroupDescriptor::find_descriptor(haystack, offset)?.0
}); });
@ -97,13 +115,18 @@ impl BlockGroupDescriptor {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use block::{Address, Size512};
use super::*; use super::*;
#[test] #[test]
fn find() { fn find() {
let buffer = vec![0_u8; 4096]; let buffer = vec![0_u8; 4096];
let table = unsafe { let table = unsafe {
BlockGroupDescriptor::find_descriptor_table(&buffer, 2048, 8) BlockGroupDescriptor::find_descriptor_table(
&buffer,
Address::<Size512>::new(4, 0),
8,
)
}; };
assert!( assert!(
table.is_ok(), table.is_ok(),

View file

@ -2,6 +2,7 @@ use core::mem;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use error::Error; use error::Error;
use block::{Address, Size};
use buffer::Buffer; use buffer::Buffer;
/// An inode is a structure on the disk that represents a file, directory, /// An inode is a structure on the disk that represents a file, directory,
@ -96,11 +97,14 @@ impl Debug for Inode {
} }
impl Inode { impl Inode {
pub unsafe fn find_inode<B: Buffer<u8, usize>>( pub unsafe fn find_inode<
S: Size + Copy + PartialOrd,
B: Buffer<u8, Address<S>>,
>(
haystack: &B, haystack: &B,
offset: usize, offset: Address<S>,
size: usize, size: usize,
) -> Result<(Inode, usize), Error> ) -> Result<(Inode, Address<S>), Error>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
@ -108,9 +112,13 @@ impl Inode {
unimplemented!("inodes with a size != 128"); unimplemented!("inodes with a size != 128");
} }
let end = offset + size; let end = offset + Address::from(size);
if haystack.len() < end { if haystack.len() < end {
return Err(Error::OutOfBounds(end)); return Err(Error::AddressOutOfBounds(
end.block(),
end.offset(),
end.block_size(),
));
} }
let inode = haystack let inode = haystack

View file

@ -2,6 +2,7 @@ use core::mem;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use error::Error; use error::Error;
use block::{Address, Size};
use buffer::Buffer; use buffer::Buffer;
/// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a
@ -194,16 +195,20 @@ impl Debug for Superblock {
} }
impl Superblock { impl Superblock {
pub unsafe fn find<B: Buffer<u8, usize>>( pub unsafe fn find<S: Size + Copy + PartialOrd, B: Buffer<u8, Address<S>>>(
haystack: &B, haystack: &B,
) -> Result<(Superblock, usize), Error> ) -> Result<(Superblock, Address<S>), Error>
where where
Error: From<B::Error>, Error: From<B::Error>,
{ {
let offset = 1024; let offset = Address::from(1024_usize);
let end = offset + mem::size_of::<Superblock>(); let end = offset + Address::from(mem::size_of::<Superblock>());
if haystack.len() < end { if haystack.len() < end {
return Err(Error::OutOfBounds(end)); return Err(Error::AddressOutOfBounds(
end.block(),
end.offset(),
end.block_size(),
));
} }
let superblock = { let superblock = {
@ -291,6 +296,7 @@ bitflags! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use block::Size512;
use super::*; use super::*;
#[test] #[test]
@ -299,7 +305,7 @@ mod tests {
// magic // magic
buffer[1024 + 56] = EXT2_MAGIC as u8; buffer[1024 + 56] = EXT2_MAGIC as u8;
buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8; buffer[1024 + 57] = (EXT2_MAGIC >> 8) as u8;
let superblock = unsafe { Superblock::find(&buffer) }; let superblock = unsafe { Superblock::find::<Size512, _>(&buffer) };
assert!( assert!(
superblock.is_ok(), superblock.is_ok(),
"Err({:?})", "Err({:?})",
@ -314,7 +320,7 @@ mod tests {
use std::fs::File; use std::fs::File;
let file = RefCell::new(File::open("ext2.img").unwrap()); let file = RefCell::new(File::open("ext2.img").unwrap());
let superblock = unsafe { Superblock::find(&file) }; let superblock = unsafe { Superblock::find::<Size512, _>(&file) };
assert!( assert!(
superblock.is_ok(), superblock.is_ok(),
"Err({:?})", "Err({:?})",