This repository has been archived on 2022-02-08. You can view files and clone it, but cannot push or open issues or pull requests.
ext2-rs/src/fs.rs

256 lines
6.6 KiB
Rust
Raw Normal View History

use core::mem;
use alloc::Vec;
2018-03-19 02:39:46 -05:00
use error::Error;
2018-03-19 12:38:33 -05:00
use buffer::{Buffer, BufferSlice};
2018-03-19 02:39:46 -05:00
use sys::superblock::Superblock;
use sys::block_group::BlockGroupDescriptor;
2018-03-19 13:55:22 -05:00
use sys::inode::Inode;
2018-03-19 02:39:46 -05:00
2018-03-19 12:38:33 -05:00
struct Struct<T> {
pub inner: T,
pub offset: usize,
}
impl<T> From<(T, usize)> for Struct<T> {
#[inline]
fn from((inner, offset): (T, usize)) -> Struct<T> {
Struct { inner, offset }
}
}
2018-03-19 02:39:46 -05:00
/// Safe wrapper for raw sys structs
pub struct Ext2<B: Buffer<u8>> {
buffer: B,
2018-03-19 12:38:33 -05:00
superblock: Struct<Superblock>,
block_groups: Struct<Vec<BlockGroupDescriptor>>,
2018-03-19 02:39:46 -05:00
}
impl<B: Buffer<u8>> Ext2<B>
where
Error: From<B::Error>,
{
2018-03-19 12:38:33 -05:00
pub fn new(buffer: B) -> Result<Ext2<B>, Error> {
2018-03-19 13:36:30 -05:00
let superblock = unsafe { Struct::from(Superblock::find(&buffer)?) };
let block_size = superblock.inner.block_size();
let block_groups_offset =
(superblock.inner.first_data_block as usize + 1) * block_size;
let block_groups_count = superblock
.inner
.block_group_count()
.map(|count| count as usize)
.map_err(|(a, b)| Error::BadBlockGroupCount(a, b))?;
2018-03-19 13:36:30 -05:00
let block_groups = unsafe {
BlockGroupDescriptor::find_descriptor_table(
&buffer,
block_groups_offset,
block_groups_count,
)?
};
let block_groups = Struct::from(block_groups);
Ok(Ext2 {
buffer,
superblock,
block_groups,
})
2018-03-19 12:38:33 -05:00
}
#[allow(dead_code)]
fn update_global(&mut self) -> Result<(), Error> {
// superblock
{
let slice = BufferSlice::from_cast(
&self.superblock.inner,
self.superblock.offset,
);
let commit = slice.commit();
self.buffer.commit(commit).map_err(|err| Error::from(err))?;
}
// block group descriptors
let mut offset = self.block_groups.offset;
for descr in &self.block_groups.inner {
let slice = BufferSlice::from_cast(descr, offset);
let commit = slice.commit();
self.buffer.commit(commit).map_err(|err| Error::from(err))?;
offset += mem::size_of::<BlockGroupDescriptor>();
}
Ok(())
2018-03-19 12:38:33 -05:00
}
#[allow(dead_code)]
fn update_inode(
&mut self,
&(ref inode, offset): &(Inode, usize),
) -> Result<(), Error> {
let slice = BufferSlice::from_cast(inode, offset);
let commit = slice.commit();
self.buffer.commit(commit).map_err(|err| Error::from(err))
}
pub fn inode_nth(
&self,
block_group: usize,
index: usize,
) -> Option<(Inode, usize)> {
self.inodes_nth(block_group, index)
.and_then(|mut inodes| inodes.next())
}
pub fn inodes<'a>(&'a self, block_group: usize) -> Inodes<'a, B> {
self.inodes_nth(block_group, 1).unwrap()
}
pub fn inodes_nth<'a>(
&'a self,
block_group: usize,
index: usize,
) -> Option<Inodes<'a, B>> {
assert!(index > 0, "inodes are 1-indexed");
if index > self.inodes_count() {
None
} else {
Some(Inodes {
buffer: &self.buffer,
block_size: self.block_size(),
inode_size: self.inode_size(),
inodes_block: self.inodes_block(block_group),
inodes_count: self.inodes_count(),
index,
})
}
}
2018-03-19 12:38:33 -05:00
fn superblock(&self) -> &Superblock {
&self.superblock.inner
}
#[allow(dead_code)]
2018-03-19 12:38:33 -05:00
fn superblock_mut(&mut self) -> &mut Superblock {
&mut self.superblock.inner
}
2018-03-19 13:55:22 -05:00
pub fn version(&self) -> (u32, u16) {
(self.superblock().rev_major, self.superblock().rev_minor)
}
pub fn inode_size(&self) -> usize {
if self.version().0 == 0 {
mem::size_of::<Inode>()
} else {
// note: inodes bigger than 128 are not supported
self.superblock().inode_size as usize
}
}
pub fn inodes_block(&self, block_group: usize) -> usize {
self.block_groups.inner[block_group].inode_table_block as _
}
pub fn inodes_count(&self) -> usize {
self.superblock().inodes_per_group 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(a, b))
}
2018-03-19 12:38:33 -05:00
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 _
2018-03-19 02:39:46 -05:00
}
2018-03-19 12:38:33 -05:00
pub fn block_size(&self) -> usize {
self.superblock().block_size()
2018-03-19 02:39:46 -05:00
}
}
2018-03-19 07:35:00 -05:00
pub struct Inodes<'a, B: 'a + Buffer<u8>> {
buffer: &'a B,
block_size: usize,
inode_size: usize,
inodes_block: usize,
inodes_count: usize,
index: usize,
}
impl<'a, B: 'a + Buffer<u8>> Iterator for Inodes<'a, B>
where
Error: From<B::Error>,
{
type Item = (Inode, usize);
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.inodes_count {
let offset = self.inodes_block * self.block_size
+ (self.index - 1) * self.inode_size;
self.index += 1;
unsafe {
Inode::find_inode(self.buffer, offset, self.inode_size).ok()
}
} else {
None
}
}
}
2018-03-19 07:35:00 -05:00
#[cfg(test)]
mod tests {
use std::fs::File;
use std::cell::RefCell;
use buffer::Buffer;
2018-03-19 07:35:00 -05:00
use super::Ext2;
#[test]
fn file_len() {
let file = RefCell::new(File::open("ext2.bin").unwrap());
assert_eq!(unsafe { file.slice_unchecked(1024..2048).len() }, 1024);
}
2018-03-19 07:35:00 -05:00
#[test]
fn file() {
let file = RefCell::new(File::open("ext2.bin").unwrap());
2018-03-19 12:38:33 -05:00
let fs = Ext2::new(file);
2018-03-19 13:55:22 -05:00
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());
2018-03-19 07:35:00 -05:00
}
#[test]
fn inodes() {
let file = RefCell::new(File::open("ext2.bin").unwrap());
let fs = Ext2::new(file);
assert!(
fs.is_ok(),
"Err({:?})",
fs.err().unwrap_or_else(|| unreachable!()),
);
let fs = fs.unwrap();
let inodes = fs.inodes(0).filter(|inode| inode.0.in_use());
for inode in inodes {
println!("{:?}", inode);
}
}
2018-03-19 07:35:00 -05:00
}