Merge pull request #4 from pi-pi3/sync

Enforce thread-safety
This commit is contained in:
Szymon Walter 2018-03-22 11:28:24 +01:00 committed by GitHub
commit f06ed46397
5 changed files with 355 additions and 310 deletions

View file

@ -6,6 +6,7 @@ authors = ["Szymon Walter <walter.szymon.98@gmail.com>"]
[dependencies] [dependencies]
bitflags = "1.0" bitflags = "1.0"
rlibc = { version = "1.0", optional = true } rlibc = { version = "1.0", optional = true }
spin = "0.4"
[features] [features]
default = ["no_std"] default = ["no_std"]

171
src/fs/mod.rs Normal file
View file

@ -0,0 +1,171 @@
use core::mem;
use alloc::Vec;
use error::Error;
use sector::{Address, SectorSize};
use volume::Volume;
use sys::superblock::Superblock;
use sys::block_group::BlockGroupDescriptor;
use sys::inode::Inode as RawInode;
pub mod sync;
pub(crate) struct Struct<T, S: SectorSize> {
pub inner: T,
pub offset: Address<S>,
}
impl<T, S: SectorSize> From<(T, Address<S>)> for Struct<T, S> {
#[inline]
fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> {
Struct { inner, offset }
}
}
/// Safe wrapper for raw sys structs
pub struct Ext2<S: SectorSize, V: Volume<u8, S>> {
// TODO: should this have some different vis?
pub(crate) volume: V,
pub(crate) superblock: Struct<Superblock, S>,
pub(crate) block_groups: Struct<Vec<BlockGroupDescriptor>, S>,
}
impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
pub fn new(volume: V) -> Result<Ext2<S, V>, Error> {
let superblock = unsafe { Struct::from(Superblock::find(&volume)?) };
let block_groups_offset = Address::with_block_size(
superblock.inner.first_data_block + 1,
0,
superblock.inner.log_block_size + 10,
);
let block_groups_count = superblock
.inner
.block_group_count()
.map(|count| count as usize)
.map_err(|(a, b)| Error::BadBlockGroupCount {
by_blocks: a,
by_inodes: b,
})?;
let block_groups = unsafe {
BlockGroupDescriptor::find_descriptor_table(
&volume,
block_groups_offset,
block_groups_count,
)?
};
let block_groups = Struct::from(block_groups);
Ok(Ext2 {
volume,
superblock,
block_groups,
})
}
pub fn version(&self) -> (u32, u16) {
(
self.superblock.inner.rev_major,
self.superblock.inner.rev_minor,
)
}
pub fn inode_size(&self) -> usize {
if self.version().0 == 0 {
mem::size_of::<RawInode>()
} else {
// note: inodes bigger than 128 are not supported
self.superblock.inner.inode_size as usize
}
}
pub fn inodes_count(&self) -> usize {
self.superblock.inner.inodes_per_group as _
}
pub fn total_inodes_count(&self) -> usize {
self.superblock.inner.inodes_count as _
}
pub fn block_group_count(&self) -> Result<usize, Error> {
self.superblock
.inner
.block_group_count()
.map(|count| count as usize)
.map_err(|(a, b)| Error::BadBlockGroupCount {
by_blocks: a,
by_inodes: b,
})
}
pub fn total_block_count(&self) -> usize {
self.superblock.inner.blocks_count as _
}
pub fn free_block_count(&self) -> usize {
self.superblock.inner.free_blocks_count as _
}
pub fn block_size(&self) -> usize {
self.superblock.inner.block_size()
}
pub fn log_block_size(&self) -> u32 {
self.superblock.inner.log_block_size + 10
}
pub fn sector_size(&self) -> usize {
S::SIZE
}
pub fn log_sector_size(&self) -> u32 {
S::LOG_SIZE
}
}
#[cfg(test)]
mod tests {
use std::fs::File;
use std::cell::RefCell;
use sector::{Address, Size512};
use volume::Volume;
use super::Ext2;
#[test]
fn file_len() {
let file = RefCell::new(File::open("ext2.img").unwrap());
assert_eq!(
Address::<Size512>::from(2048_u64)
- Address::<Size512>::from(1024_u64),
Address::<Size512>::new(2, 0)
);
assert_eq!(
unsafe {
file.slice_unchecked(
Address::<Size512>::from(1024_u64)
..Address::<Size512>::from(2048_u64),
).len()
},
1024
);
}
#[test]
fn file() {
let file = RefCell::new(File::open("ext2.img").unwrap());
let fs = Ext2::<Size512, _>::new(file);
assert!(
fs.is_ok(),
"Err({:?})",
fs.err().unwrap_or_else(|| unreachable!()),
);
let fs = fs.unwrap();
let vers = fs.version();
println!("version: {}.{}", vers.0, vers.1);
assert_eq!(128, fs.inode_size());
}
}

View file

@ -1,102 +1,155 @@
use core::mem;
use core::slice;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use core::nonzero::NonZero; use core::nonzero::NonZero;
use alloc::Vec; use alloc::Vec;
use alloc::arc::Arc;
use spin::{Mutex, MutexGuard};
use error::Error; use error::Error;
use sector::{Address, SectorSize}; use sector::{Address, SectorSize};
use volume::{Volume, VolumeSlice}; use volume::Volume;
use sys::superblock::Superblock;
use sys::block_group::BlockGroupDescriptor;
use sys::inode::Inode as RawInode; use sys::inode::Inode as RawInode;
struct Struct<T, S: SectorSize> { use super::Ext2;
pub inner: T,
pub offset: Address<S>, pub struct Synced<T> {
inner: Arc<Mutex<T>>,
} }
impl<T, S: SectorSize> From<(T, Address<S>)> for Struct<T, S> { impl<T> Synced<T> {
#[inline] pub fn with_inner(inner: T) -> Synced<T> {
fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> { Synced {
Struct { inner, offset } inner: Arc::new(Mutex::new(inner)),
}
}
pub fn inner<'a>(&'a self) -> MutexGuard<'a, T> {
self.inner.lock()
} }
} }
/// Safe wrapper for raw sys structs impl<T> Clone for Synced<T> {
pub struct Ext2<S: SectorSize, V: Volume<u8, S>> { fn clone(&self) -> Self {
volume: V, Synced {
superblock: Struct<Superblock, S>, inner: self.inner.clone(),
block_groups: Struct<Vec<BlockGroupDescriptor>, S>, }
}
} }
impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> { impl<S: SectorSize, V: Volume<u8, S>> Synced<Ext2<S, V>> {
pub fn new(volume: V) -> Result<Ext2<S, V>, Error> { pub fn new(volume: V) -> Result<Synced<Ext2<S, V>>, Error> {
let superblock = unsafe { Struct::from(Superblock::find(&volume)?) }; Ext2::new(volume).map(|inner| Synced::with_inner(inner))
let block_groups_offset = Address::with_block_size(
superblock.inner.first_data_block + 1,
0,
superblock.inner.log_block_size + 10,
);
let block_groups_count = superblock
.inner
.block_group_count()
.map(|count| count as usize)
.map_err(|(a, b)| Error::BadBlockGroupCount {
by_blocks: a,
by_inodes: b,
})?;
let block_groups = unsafe {
BlockGroupDescriptor::find_descriptor_table(
&volume,
block_groups_offset,
block_groups_count,
)?
};
let block_groups = Struct::from(block_groups);
Ok(Ext2 {
volume,
superblock,
block_groups,
})
} }
#[allow(dead_code)] pub fn root_inode(&self) -> (Inode<S, V>, Address<S>) {
fn update_global(&mut self) -> Result<(), Error> { self.inode_nth(2).unwrap()
// superblock }
{
let slice = VolumeSlice::from_cast( pub fn inode_nth(&self, index: usize) -> Option<(Inode<S, V>, Address<S>)> {
&self.superblock.inner, self.inodes_nth(index).next()
self.superblock.offset, }
pub fn inodes(&self) -> Inodes<S, V> {
self.inodes_nth(1)
}
pub fn inodes_nth(&self, index: usize) -> Inodes<S, V> {
assert!(index > 0, "inodes are 1-indexed");
let inner = self.inner();
Inodes {
fs: self.clone(),
log_block_size: inner.log_block_size(),
inode_size: inner.inode_size(),
inodes_per_group: inner.inodes_count(),
inodes_count: inner.total_inodes_count(),
index,
}
}
pub fn sector_size(&self) -> usize {
S::SIZE
}
pub fn log_sector_size(&self) -> u32 {
S::LOG_SIZE
}
}
impl<S: SectorSize, V: Volume<u8, S>> Debug for Synced<Ext2<S, V>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Synced<Ext2<{}>>", S::SIZE)
}
}
#[derive(Debug, Clone)]
pub struct Inodes<S: SectorSize, V: Volume<u8, S>> {
fs: Synced<Ext2<S, V>>,
log_block_size: u32,
inode_size: usize,
inodes_per_group: usize,
inodes_count: usize,
index: usize,
}
impl<S: SectorSize, V: Volume<u8, S>> Iterator for Inodes<S, V> {
type Item = (Inode<S, V>, Address<S>);
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.inodes_count {
let block_group = (self.index - 1) / self.inodes_per_group;
let index = (self.index - 1) % self.inodes_per_group;
self.index += 1;
let fs = self.fs.inner();
let inodes_block =
fs.block_groups.inner[block_group].inode_table_block;
let offset = Address::with_block_size(
inodes_block,
(index * self.inode_size) as i32,
self.log_block_size,
); );
let commit = slice.commit(); let raw = unsafe {
self.volume.commit(commit).map_err(|err| err.into())?; RawInode::find_inode(&fs.volume, offset, self.inode_size).ok()
};
raw.map(|(raw, offset)| (Inode::new(self.fs.clone(), raw), offset))
} else {
None
} }
}
}
// block group descriptors #[derive(Debug)]
let mut offset = self.block_groups.offset; pub struct Inode<S: SectorSize, V: Volume<u8, S>> {
for descr in &self.block_groups.inner { fs: Synced<Ext2<S, V>>,
let slice = VolumeSlice::from_cast(descr, offset); inner: RawInode,
let commit = slice.commit(); }
self.volume.commit(commit).map_err(|err| err.into())?;
offset = impl<S: SectorSize, V: Volume<u8, S>> Clone for Inode<S, V> {
offset + Address::from(mem::size_of::<BlockGroupDescriptor>()); fn clone(&self) -> Self {
Inode {
fs: self.fs.clone(),
inner: self.inner,
} }
}
}
Ok(()) impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
pub fn new(fs: Synced<Ext2<S, V>>, inner: RawInode) -> Inode<S, V> {
Inode { fs, inner }
} }
pub fn read_inode<'vol>( pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
&'vol self, let total_size = self.size();
buf: &mut [u8], let block_size = {
inode: &Inode<'vol, S, V>, let fs = self.fs.inner();
) -> Result<usize, Error> { fs.block_size()
let total_size = inode.size(); };
let block_size = self.block_size();
let mut offset = 0; let mut offset = 0;
for block in inode.blocks() { for block in self.blocks() {
match block { match block {
Ok((data, _)) => { Ok((data, _)) => {
let data_size = block_size let data_size = block_size
@ -113,180 +166,24 @@ impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
Ok(offset) Ok(offset)
} }
pub fn write_inode<'vol>( pub fn blocks(&self) -> InodeBlocks<S, V> {
&'vol self,
_inode: &(Inode<'vol, S, V>, Address<S>),
_buf: &[u8],
) -> Result<usize, Error> {
unimplemented!()
}
pub fn root_inode<'vol>(&'vol self) -> (Inode<'vol, S, V>, Address<S>) {
self.inode_nth(2).unwrap()
}
pub fn inode_nth<'vol>(
&'vol self,
index: usize,
) -> Option<(Inode<'vol, S, V>, Address<S>)> {
self.inodes_nth(index).next()
}
pub fn inodes<'vol>(&'vol self) -> Inodes<'vol, S, V> {
self.inodes_nth(1)
}
pub fn inodes_nth<'vol>(&'vol self, index: usize) -> Inodes<'vol, S, V> {
assert!(index > 0, "inodes are 1-indexed");
Inodes {
fs: self,
block_groups: &self.block_groups.inner,
log_block_size: self.log_block_size(),
inode_size: self.inode_size(),
inodes_per_group: self.inodes_count(),
inodes_count: self.total_inodes_count(),
index,
}
}
fn superblock(&self) -> &Superblock {
&self.superblock.inner
}
#[allow(dead_code)]
fn superblock_mut(&mut self) -> &mut Superblock {
&mut self.superblock.inner
}
pub fn version(&self) -> (u32, u16) {
(self.superblock().rev_major, self.superblock().rev_minor)
}
pub fn inode_size<'vol>(&'vol self) -> usize {
if self.version().0 == 0 {
mem::size_of::<Inode<'vol, S, V>>()
} else {
// note: inodes bigger than 128 are not supported
self.superblock().inode_size as usize
}
}
pub fn inodes_count(&self) -> usize {
self.superblock().inodes_per_group as _
}
pub fn total_inodes_count(&self) -> usize {
self.superblock().inodes_count as _
}
pub fn block_group_count(&self) -> Result<usize, Error> {
self.superblock()
.block_group_count()
.map(|count| count as usize)
.map_err(|(a, b)| Error::BadBlockGroupCount {
by_blocks: a,
by_inodes: b,
})
}
pub fn total_block_count(&self) -> usize {
self.superblock().blocks_count as _
}
pub fn free_block_count(&self) -> usize {
self.superblock().free_blocks_count as _
}
pub fn block_size(&self) -> usize {
self.superblock().block_size()
}
pub fn log_block_size(&self) -> u32 {
self.superblock().log_block_size + 10
}
pub fn sector_size(&self) -> usize {
S::SIZE
}
pub fn log_sector_size(&self) -> u32 {
S::LOG_SIZE
}
}
impl<S: SectorSize, V: Volume<u8, S>> Debug for Ext2<S, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Ext2<{}>", S::SIZE)
}
}
pub struct Inodes<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> {
fs: &'vol Ext2<S, V>,
block_groups: &'vol [BlockGroupDescriptor],
log_block_size: u32,
inode_size: usize,
inodes_per_group: usize,
inodes_count: usize,
index: usize,
}
impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
for Inodes<'vol, S, V>
{
type Item = (Inode<'vol, S, V>, Address<S>);
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.inodes_count {
let block_group = (self.index - 1) / self.inodes_per_group;
let index = (self.index - 1) % self.inodes_per_group;
self.index += 1;
let inodes_block = self.block_groups[block_group].inode_table_block;
let offset = Address::with_block_size(
inodes_block,
(index * self.inode_size) as i32,
self.log_block_size,
);
let raw = unsafe {
RawInode::find_inode(&self.fs.volume, offset, self.inode_size)
.ok()
};
raw.map(|(raw, offset)| (Inode::new(self.fs, raw), offset))
} else {
None
}
}
}
#[derive(Debug, Clone)]
pub struct Inode<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> {
fs: &'vol Ext2<S, V>,
inner: RawInode,
}
impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
pub fn new(fs: &'vol Ext2<S, V>, inner: RawInode) -> Inode<'vol, S, V> {
Inode { fs, inner }
}
pub fn blocks<'inode>(&'inode self) -> InodeBlocks<'vol, 'inode, S, V> {
InodeBlocks { InodeBlocks {
inode: self, inode: self.clone(),
index: 0, index: 0,
} }
} }
pub fn directory<'inode>( pub fn directory(&self) -> Option<Directory<S, V>> {
&'inode self,
) -> Option<Directory<'vol, 'inode, S, V>> {
use sys::inode::TypePerm; use sys::inode::TypePerm;
if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } { if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } {
Some(Directory { Some(Directory {
blocks: self.blocks(), blocks: self.blocks(),
offset: 0, offset: 0,
buffer: None, buffer: None,
block_size: self.fs.block_size(), block_size: {
let fs = self.fs.inner();
fs.block_size()
},
}) })
} else { } else {
None None
@ -334,8 +231,10 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
} }
} }
let bs4 = self.fs.block_size() / 4; let fs = self.fs.inner();
let log_block_size = self.fs.log_block_size();
let bs4 = fs.block_size() / 4;
let log_block_size = fs.log_block_size();
if index < 12 { if index < 12 {
return Ok(NonZero::new(self.inner.direct_pointer[index])); return Ok(NonZero::new(self.inner.direct_pointer[index]));
@ -345,7 +244,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
if index < bs4 { if index < bs4 {
let block = self.inner.indirect_pointer; let block = self.inner.indirect_pointer;
return block_index(&self.fs.volume, block, index, log_block_size); return block_index(&fs.volume, block, index, log_block_size);
} }
index -= bs4; index -= bs4;
@ -353,7 +252,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
if index < bs4 * bs4 { if index < bs4 * bs4 {
let indirect_index = index >> (log_block_size + 2); let indirect_index = index >> (log_block_size + 2);
let block = match block_index( let block = match block_index(
&self.fs.volume, &fs.volume,
self.inner.doubly_indirect, self.inner.doubly_indirect,
indirect_index, indirect_index,
log_block_size, log_block_size,
@ -363,7 +262,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
return block_index( return block_index(
&self.fs.volume, &fs.volume,
block, block,
index & (bs4 - 1), index & (bs4 - 1),
log_block_size, log_block_size,
@ -375,7 +274,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
if index < bs4 * bs4 * bs4 { if index < bs4 * bs4 * bs4 {
let doubly_index = index >> (2 * log_block_size + 4); let doubly_index = index >> (2 * log_block_size + 4);
let indirect = match block_index( let indirect = match block_index(
&self.fs.volume, &fs.volume,
self.inner.triply_indirect, self.inner.triply_indirect,
doubly_index, doubly_index,
log_block_size, log_block_size,
@ -386,7 +285,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
}; };
let indirect_index = (index >> (log_block_size + 2)) & (bs4 - 1); let indirect_index = (index >> (log_block_size + 2)) & (bs4 - 1);
let block = match block_index( let block = match block_index(
&self.fs.volume, &fs.volume,
indirect as u32, indirect as u32,
indirect_index, indirect_index,
log_block_size, log_block_size,
@ -396,7 +295,7 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
return block_index( return block_index(
&self.fs.volume, &fs.volume,
block, block,
index & (bs4 - 1), index & (bs4 - 1),
log_block_size, log_block_size,
@ -439,20 +338,14 @@ impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
} }
} }
pub struct InodeBlocks< #[derive(Debug, Clone)]
'vol: 'inode, pub struct InodeBlocks<S: SectorSize, V: Volume<u8, S>> {
'inode, inode: Inode<S, V>,
S: SectorSize,
V: 'vol + Volume<u8, S>,
> {
inode: &'inode Inode<'vol, S, V>,
index: usize, index: usize,
} }
impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator impl<S: SectorSize, V: Volume<u8, S>> Iterator for InodeBlocks<S, V> {
for InodeBlocks<'vol, 'inode, S, V> type Item = Result<(Vec<u8>, Address<S>), Error>;
{
type Item = Result<(VolumeSlice<'vol, u8, S>, Address<S>), Error>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let block = self.inode.try_block(self.index); let block = self.inode.try_block(self.index);
@ -463,38 +356,31 @@ impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
}; };
self.index += 1; self.index += 1;
let fs = self.inode.fs.inner();
let block = block.get(); let block = block.get();
let log_block_size = self.inode.fs.log_block_size(); let log_block_size = fs.log_block_size();
let offset = Address::with_block_size(block, 0, log_block_size); let offset = Address::with_block_size(block, 0, log_block_size);
let end = Address::with_block_size(block + 1, 0, log_block_size); let end = Address::with_block_size(block + 1, 0, log_block_size);
let slice = self.inode let slice = fs.volume
.fs
.volume
.slice(offset..end) .slice(offset..end)
.map(|slice| (slice, offset)) .map(|slice| (slice.to_vec(), offset))
.map_err(|err| err.into()); .map_err(|err| err.into());
Some(slice) Some(slice)
} }
} }
pub struct Directory< #[derive(Debug, Clone)]
'vol: 'inode, pub struct Directory<S: SectorSize, V: Volume<u8, S>> {
'inode, blocks: InodeBlocks<S, V>,
S: SectorSize,
V: 'vol + Volume<u8, S>,
> {
blocks: InodeBlocks<'vol, 'inode, S, V>,
offset: usize, offset: usize,
buffer: Option<VolumeSlice<'vol, u8, S>>, buffer: Option<Vec<u8>>,
block_size: usize, block_size: usize,
} }
impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator impl<S: SectorSize, V: Volume<u8, S>> Iterator for Directory<S, V> {
for Directory<'vol, 'inode, S, V> type Item = Result<DirectoryEntry, Error>;
{
type Item = Result<DirectoryEntry<'vol>, Error>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.buffer.is_none() || self.offset >= self.block_size { if self.buffer.is_none() || self.offset >= self.block_size {
@ -520,8 +406,7 @@ impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
let len = buffer[6]; let len = buffer[6];
let ty = buffer[7]; let ty = buffer[7];
let ptr = unsafe { buffer.as_ptr().add(8) }; let name = buffer[8..8 + len as usize].to_vec();
let name = unsafe { slice::from_raw_parts(ptr, len as usize) };
self.offset += size as usize; self.offset += size as usize;
@ -533,8 +418,9 @@ impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
} }
} }
pub struct DirectoryEntry<'a> { #[derive(Clone)]
pub name: &'a [u8], pub struct DirectoryEntry {
pub name: Vec<u8>,
pub inode: usize, pub inode: usize,
pub ty: u8, pub ty: u8,
} }
@ -544,34 +430,15 @@ mod tests {
use std::fs::File; use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use sector::{Address, SectorSize, Size512}; use sector::{SectorSize, Size512};
use volume::Volume; use volume::Volume;
use super::{Ext2, Inode}; use super::{Ext2, Inode, Synced};
#[test]
fn file_len() {
let file = RefCell::new(File::open("ext2.img").unwrap());
assert_eq!(
Address::<Size512>::from(2048_u64)
- Address::<Size512>::from(1024_u64),
Address::<Size512>::new(2, 0)
);
assert_eq!(
unsafe {
file.slice_unchecked(
Address::<Size512>::from(1024_u64)
..Address::<Size512>::from(2048_u64),
).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::<Size512, _>::new(file); let fs = Synced::<Ext2<Size512, _>>::new(file);
assert!( assert!(
fs.is_ok(), fs.is_ok(),
@ -580,16 +447,17 @@ mod tests {
); );
let fs = fs.unwrap(); let fs = fs.unwrap();
let inner = fs.inner();
let vers = fs.version(); let vers = inner.version();
println!("version: {}.{}", vers.0, vers.1); println!("version: {}.{}", vers.0, vers.1);
assert_eq!(128, fs.inode_size()); assert_eq!(128, inner.inode_size());
} }
#[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::<Size512, _>::new(file); let fs = Synced::<Ext2<Size512, _>>::new(file);
assert!( assert!(
fs.is_ok(), fs.is_ok(),
@ -609,7 +477,7 @@ mod tests {
fn inode_blocks() { fn inode_blocks() {
use std::str; 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 = Synced::<Ext2<Size512, _>>::new(file).unwrap();
let inodes = fs.inodes().filter(|inode| { let inodes = fs.inodes().filter(|inode| {
inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024
@ -619,7 +487,10 @@ mod tests {
let size = inode.0.size(); let size = inode.0.size();
for block in inode.0.blocks() { for block in inode.0.blocks() {
let (data, _) = block.unwrap(); let (data, _) = block.unwrap();
assert_eq!(data.len(), fs.block_size()); assert_eq!(data.len(), {
let fs = fs.inner();
fs.block_size()
});
println!("{:?}", &data[..size]); println!("{:?}", &data[..size]);
let _ = str::from_utf8(&data[..size]) let _ = str::from_utf8(&data[..size])
.map(|string| println!("{}", string)); .map(|string| println!("{}", string));
@ -630,7 +501,7 @@ mod tests {
#[test] #[test]
fn read_inode() { fn read_inode() {
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 = Synced::<Ext2<Size512, _>>::new(file).unwrap();
let inodes = fs.inodes().filter(|inode| { let inodes = fs.inodes().filter(|inode| {
inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024
@ -640,7 +511,7 @@ mod tests {
unsafe { unsafe {
buf.set_len(inode.size()); buf.set_len(inode.size());
} }
let size = fs.read_inode(&mut buf[..], &inode); let size = inode.read(&mut buf[..]);
assert!(size.is_ok()); assert!(size.is_ok());
let size = size.unwrap(); let size = size.unwrap();
assert_eq!(size, inode.size()); assert_eq!(size, inode.size());
@ -653,7 +524,7 @@ mod tests {
#[test] #[test]
fn read_big() { fn read_big() {
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 = Synced::<Ext2<Size512, _>>::new(file).unwrap();
let inodes = fs.inodes().filter(|inode| { let inodes = fs.inodes().filter(|inode| {
inode.0.in_use() && inode.0.uid() == 1000 inode.0.in_use() && inode.0.uid() == 1000
@ -664,7 +535,7 @@ mod tests {
unsafe { unsafe {
buf.set_len(inode.size()); buf.set_len(inode.size());
} }
let size = fs.read_inode(&mut buf[..], &inode); let size = inode.read(&mut buf[..]);
assert!(size.is_ok()); assert!(size.is_ok());
let size = size.unwrap(); let size = size.unwrap();
assert_eq!(size, inode.size()); assert_eq!(size, inode.size());
@ -687,15 +558,15 @@ mod tests {
use std::str; use std::str;
fn walk<'vol, S: SectorSize, V: Volume<u8, S>>( fn walk<'vol, S: SectorSize, V: Volume<u8, S>>(
fs: &'vol Ext2<S, V>, fs: &'vol Synced<Ext2<S, V>>,
inode: Inode<'vol, S, V>, inode: Inode<S, V>,
name: String, name: String,
) { ) {
inode.directory().map(|dir| { inode.directory().map(|dir| {
for entry in dir { for entry in dir {
assert!(entry.is_ok()); assert!(entry.is_ok());
let entry = entry.unwrap(); let entry = entry.unwrap();
let entry_name = str::from_utf8(entry.name).unwrap_or("?"); let entry_name = str::from_utf8(&entry.name).unwrap_or("?");
println!("{}/{} => {}", name, entry_name, entry.inode,); println!("{}/{} => {}", name, entry_name, entry.inode,);
if entry_name != "." && entry_name != ".." { if entry_name != "." && entry_name != ".." {
walk( walk(
@ -709,7 +580,7 @@ mod tests {
} }
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 = Synced::<Ext2<Size512, _>>::new(file).unwrap();
let (root, _) = fs.root_inode(); let (root, _) = fs.root_inode();
walk(&fs, root, String::new()); walk(&fs, root, String::new());

View file

@ -12,6 +12,7 @@
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate spin;
#[cfg(any(test, not(feature = "no_std")))] #[cfg(any(test, not(feature = "no_std")))]
extern crate core; extern crate core;

View file

@ -31,6 +31,7 @@ pub trait Volume<T: Clone, S: SectorSize> {
) -> Result<VolumeSlice<'a, T, S>, Self::Error>; ) -> Result<VolumeSlice<'a, T, S>, Self::Error>;
} }
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct VolumeSlice<'a, T: 'a + Clone, S: SectorSize> { pub struct VolumeSlice<'a, T: 'a + Clone, S: SectorSize> {
inner: Cow<'a, [T]>, inner: Cow<'a, [T]>,
index: Address<S>, index: Address<S>,