make Buffer
generic over its index, instead of usize
This commit is contained in:
parent
7e0af1b8f6
commit
7c57c047bc
78
src/block.rs
78
src/block.rs
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
};
|
};
|
||||||
|
|
|
@ -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),
|
||||||
|
|
82
src/fs.rs
82
src/fs.rs
|
@ -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(),
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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({:?})",
|
||||||
|
|
Reference in a new issue