commit
f06ed46397
|
@ -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
171
src/fs/mod.rs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
pub fn root_inode(&self) -> (Inode<S, V>, Address<S>) {
|
||||||
superblock.inner.log_block_size + 10,
|
self.inode_nth(2).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inode_nth(&self, index: usize) -> Option<(Inode<S, V>, Address<S>)> {
|
||||||
|
self.inodes_nth(index).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 block_groups_count = superblock
|
let raw = unsafe {
|
||||||
.inner
|
RawInode::find_inode(&fs.volume, offset, self.inode_size).ok()
|
||||||
.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);
|
raw.map(|(raw, offset)| (Inode::new(self.fs.clone(), raw), offset))
|
||||||
Ok(Ext2 {
|
} else {
|
||||||
volume,
|
None
|
||||||
superblock,
|
}
|
||||||
block_groups,
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Inode<S: SectorSize, V: Volume<u8, S>> {
|
||||||
|
fs: Synced<Ext2<S, V>>,
|
||||||
|
inner: RawInode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: SectorSize, V: Volume<u8, S>> Clone for Inode<S, V> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Inode {
|
||||||
|
fs: self.fs.clone(),
|
||||||
|
inner: self.inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
fn update_global(&mut self) -> Result<(), Error> {
|
let total_size = self.size();
|
||||||
// superblock
|
let block_size = {
|
||||||
{
|
let fs = self.fs.inner();
|
||||||
let slice = VolumeSlice::from_cast(
|
fs.block_size()
|
||||||
&self.superblock.inner,
|
};
|
||||||
self.superblock.offset,
|
|
||||||
);
|
|
||||||
let commit = slice.commit();
|
|
||||||
self.volume.commit(commit).map_err(|err| err.into())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// block group descriptors
|
|
||||||
let mut offset = self.block_groups.offset;
|
|
||||||
for descr in &self.block_groups.inner {
|
|
||||||
let slice = VolumeSlice::from_cast(descr, offset);
|
|
||||||
let commit = slice.commit();
|
|
||||||
self.volume.commit(commit).map_err(|err| err.into())?;
|
|
||||||
offset =
|
|
||||||
offset + Address::from(mem::size_of::<BlockGroupDescriptor>());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_inode<'vol>(
|
|
||||||
&'vol self,
|
|
||||||
buf: &mut [u8],
|
|
||||||
inode: &Inode<'vol, S, V>,
|
|
||||||
) -> Result<usize, Error> {
|
|
||||||
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());
|
|
@ -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;
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
Reference in a new issue