ported to modern rust

This commit is contained in:
Able 2022-02-07 22:18:39 -06:00
parent abcf7c5c84
commit 1e537b063c
11 changed files with 210 additions and 172 deletions

View file

@ -1,12 +1,14 @@
[package] [package]
name = "ext2" name = "ext2"
version = "0.1.0" version = "0.1.1"
authors = ["Szymon Walter <walter.szymon.98@gmail.com>"] authors = ["Szymon Walter <walter.szymon.98@gmail.com>",
"able <abl3theabove@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" spin = "0.9.2"
genfs = "^0.1.4" genfs = "^0.1.4"
[features] [features]

View file

@ -1,5 +1,7 @@
use core::fmt::{self, Display}; use {
use alloc::String; alloc::string::String,
core::fmt::{self, Display},
};
#[cfg(any(test, not(feature = "no_std")))] #[cfg(any(test, not(feature = "no_std")))]
use std::io; use std::io;

View file

@ -1,16 +1,18 @@
use core::mem; use {
alloc::vec::Vec,
use alloc::Vec; core::mem,
error::Error,
use error::Error; sector::{Address, SectorSize},
use sector::{Address, SectorSize}; sys::{
use volume::Volume; block_group::BlockGroupDescriptor, inode::Inode as RawInode,
use sys::superblock::Superblock; superblock::Superblock,
use sys::block_group::BlockGroupDescriptor; },
use sys::inode::Inode as RawInode; volume::Volume,
};
pub mod sync; pub mod sync;
#[allow(dead_code)]
pub(crate) struct Struct<T, S: SectorSize> { pub(crate) struct Struct<T, S: SectorSize> {
pub inner: T, pub inner: T,
pub offset: Address<S>, pub offset: Address<S>,
@ -124,8 +126,8 @@ impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use std::fs::File;
use sector::{Address, Size512}; use sector::{Address, Size512};
use volume::Volume; use volume::Volume;
@ -145,7 +147,8 @@ mod tests {
file.slice_unchecked( file.slice_unchecked(
Address::<Size512>::from(1024_u64) Address::<Size512>::from(1024_u64)
..Address::<Size512>::from(2048_u64), ..Address::<Size512>::from(2048_u64),
).len() )
.len()
}, },
1024 1024
); );

View file

@ -1,19 +1,21 @@
use core::fmt::{self, Debug}; use {
use core::nonzero::NonZero; super::Ext2,
use core::iter::Iterator; alloc::{
sync::Arc,
use alloc::{String, Vec}; {string::String, vec::Vec},
use alloc::arc::Arc; },
core::{
use spin::{Mutex, MutexGuard}; fmt::{self, Debug},
use genfs::*; iter::Iterator,
num::NonZeroU32,
use error::Error; },
use sector::{Address, SectorSize}; error::Error,
use volume::Volume; genfs::*,
use sys::inode::Inode as RawInode; sector::{Address, SectorSize},
spin::{Mutex, MutexGuard},
use super::Ext2; sys::inode::Inode as RawInode,
volume::Volume,
};
pub struct Synced<T> { pub struct Synced<T> {
inner: Arc<Mutex<T>>, inner: Arc<Mutex<T>>,
@ -115,13 +117,16 @@ impl<S: SectorSize, V: Volume<u8, S>> Fs for Synced<Ext2<S, V>> {
name: String::from_utf8_lossy(abs_path).into_owned(), name: String::from_utf8_lossy(abs_path).into_owned(),
})?; })?;
let entry = dir.find(|entry| { let entry = dir
.find(|entry| {
entry.is_err() || entry.as_ref().unwrap().name == name entry.is_err() || entry.as_ref().unwrap().name == name
}).ok_or_else(|| Error::NotFound { })
.ok_or_else(|| Error::NotFound {
name: String::from_utf8_lossy(abs_path).into_owned(), name: String::from_utf8_lossy(abs_path).into_owned(),
})??; })??;
let inode = fs.inode_nth(entry.inode) let inode = fs
.inode_nth(entry.inode)
.ok_or(Error::InodeNotFound { inode: inode.num })?; .ok_or(Error::InodeNotFound { inode: inode.num })?;
inner(fs, inode, path, abs_path) inner(fs, inode, path, abs_path)
@ -345,7 +350,8 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
buf.set_len(size); buf.set_len(size);
} }
Ok(size) Ok(size)
}).or_else(|err| { })
.or_else(|err| {
unsafe { unsafe {
buf.set_len(0); buf.set_len(0);
} }
@ -381,14 +387,14 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) }
} }
pub fn block(&self, index: usize) -> Option<NonZero<u32>> { pub fn block(&self, index: usize) -> Option<NonZeroU32> {
self.try_block(index).ok().and_then(|block| block) self.try_block(index).ok().and_then(|block| block)
} }
pub fn try_block( pub fn try_block(
&self, &self,
mut index: usize, mut index: usize,
) -> Result<Option<NonZero<u32>>, Error> { ) -> Result<Option<NonZeroU32>, Error> {
// number of blocks in direct table: 12 // number of blocks in direct table: 12
// number of blocks in indirect table: block_size/4 // number of blocks in indirect table: block_size/4
// why? // why?
@ -408,7 +414,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
block: u32, block: u32,
index: usize, index: usize,
log_block_size: u32, log_block_size: u32,
) -> Result<Option<NonZero<u32>>, Error> { ) -> Result<Option<NonZeroU32>, Error> {
let offset = (index * 4) as i32; let offset = (index * 4) as i32;
let end = offset + 4; let end = offset + 4;
let addr = Address::with_block_size(block, offset, log_block_size); let addr = Address::with_block_size(block, offset, log_block_size);
@ -416,7 +422,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
let block = volume.slice(addr..end); let block = volume.slice(addr..end);
match block { match block {
Ok(block) => unsafe { Ok(block) => unsafe {
Ok(NonZero::new(block.dynamic_cast::<u32>().0)) Ok(NonZeroU32::new(block.dynamic_cast::<u32>().0))
}, },
Err(err) => Err(err.into()), Err(err) => Err(err.into()),
} }
@ -428,7 +434,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
let log_block_size = fs.log_block_size(); 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(NonZeroU32::new(self.inner.direct_pointer[index]));
} }
index -= 12; index -= 12;
@ -595,7 +601,8 @@ impl<S: SectorSize, V: Volume<u8, S>> Iterator for InodeBlocks<S, V> {
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 = fs.volume let slice = fs
.volume
.slice(offset..end) .slice(offset..end)
.map(|slice| (slice.to_vec(), offset)) .map(|slice| (slice.to_vec(), offset))
.map_err(|err| err.into()); .map_err(|err| err.into());
@ -632,7 +639,8 @@ impl<S: SectorSize, V: Volume<u8, S>> Iterator for Directory<S, V> {
let buffer = &self.buffer.as_ref().unwrap()[self.offset..]; let buffer = &self.buffer.as_ref().unwrap()[self.offset..];
let inode = buffer[0] as u32 | (buffer[1] as u32) << 8 let inode = buffer[0] as u32
| (buffer[1] as u32) << 8
| (buffer[2] as u32) << 16 | (buffer[2] as u32) << 16
| (buffer[3] as u32) << 24; | (buffer[3] as u32) << 24;
if inode == 0 { if inode == 0 {
@ -688,8 +696,8 @@ impl DirEntry for DirectoryEntry {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use std::fs::File;
use genfs::{File as GenFile, Fs, OpenOptions}; use genfs::{File as GenFile, Fs, OpenOptions};

View file

@ -1,11 +1,9 @@
#![feature(alloc)] #![feature(
#![feature(specialization)] min_specialization,
#![feature(swap_with_slice)] const_fn_trait_bound,
#![feature(macro_lifetime_matcher)] step_trait,
#![feature(const_fn)] associated_type_defaults
#![feature(step_trait)] )]
#![feature(nonzero)]
#![feature(associated_type_defaults)]
#![cfg_attr(all(not(test), feature = "no_std"), no_std)] #![cfg_attr(all(not(test), feature = "no_std"), no_std)]
#[macro_use] #[macro_use]
@ -19,16 +17,16 @@ extern crate spin;
extern crate core; extern crate core;
pub mod error; pub mod error;
pub mod sys;
pub mod sector;
pub mod volume;
pub mod fs; pub mod fs;
pub mod sector;
pub mod sys;
pub mod volume;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use sys::superblock::*;
use sys::block_group::*; use sys::block_group::*;
use sys::inode::*; use sys::inode::*;
use sys::superblock::*;
#[test] #[test]
fn sizes() { fn sizes() {

View file

@ -1,8 +1,9 @@
use core::mem; use core::{
use core::marker::PhantomData; fmt::{self, Debug, Display, LowerHex},
use core::ops::{Add, Sub}; iter::Step,
use core::fmt::{self, Debug, Display, LowerHex}; marker::PhantomData,
use core::iter::Step; ops::{Add, Sub},
};
pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd + 'static { pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd + 'static {
// log_sector_size = log_2(sector_size) // log_sector_size = log_2(sector_size)
@ -104,7 +105,7 @@ impl<S: SectorSize> Step for Address<S> {
None None
} }
} }
/*
fn replace_one(&mut self) -> Self { fn replace_one(&mut self) -> Self {
mem::replace(self, Address::new(1, 0)) mem::replace(self, Address::new(1, 0))
} }
@ -126,6 +127,15 @@ impl<S: SectorSize> Step for Address<S> {
.checked_add(n as u32) .checked_add(n as u32)
.map(|sector| Address::new(sector, 0)) .map(|sector| Address::new(sector, 0))
} }
*/
fn forward_checked(start: Self, count: usize) -> Option<Self> {
todo!("forward_checked")
}
fn backward_checked(start: Self, count: usize) -> Option<Self> {
todo!("backward_checked")
}
} }
impl<S: SectorSize> Debug for Address<S> { impl<S: SectorSize> Debug for Address<S> {

View file

@ -1,11 +1,13 @@
use core::mem; use {
use core::fmt::{self, Debug}; alloc::vec::Vec,
core::{
use alloc::Vec; fmt::{self, Debug},
mem,
use error::Error; },
use sector::{Address, SectorSize}; error::Error,
use volume::Volume; sector::{Address, SectorSize},
volume::Volume,
};
/// The Block Group Descriptor Table contains a descriptor for each block group /// The Block Group Descriptor Table contains a descriptor for each block group
/// within the file system. The number of block groups within the file system, /// within the file system. The number of block groups within the file system,
@ -41,12 +43,12 @@ pub struct BlockGroupDescriptor {
impl Debug for BlockGroupDescriptor { impl Debug for BlockGroupDescriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BlockGroupDescriptor") f.debug_struct("BlockGroupDescriptor")
.field("block_usage_addr", unsafe { &self.block_usage_addr }) .field("block_usage_addr", &self.block_usage_addr)
.field("inode_usage_addr", unsafe { &self.inode_usage_addr }) .field("inode_usage_addr", &self.inode_usage_addr)
.field("inode_table_block", unsafe { &self.inode_table_block }) .field("inode_table_block", &self.inode_table_block)
.field("free_blocks_count", unsafe { &self.free_blocks_count }) .field("free_blocks_count", &self.free_blocks_count)
.field("free_inodes_count", unsafe { &self.free_inodes_count }) .field("free_inodes_count", &self.free_inodes_count)
.field("dirs_count", unsafe { &self.dirs_count }) .field("dirs_count", &self.dirs_count)
.finish() .finish()
} }
} }
@ -103,8 +105,8 @@ impl BlockGroupDescriptor {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use sector::{Address, Size512};
use super::*; use super::*;
use sector::{Address, Size512};
#[test] #[test]
fn find() { fn find() {

View file

@ -1,9 +1,12 @@
use core::mem; use {
use core::fmt::{self, Debug}; core::{
fmt::{self, Debug},
use error::Error; mem,
use sector::{Address, SectorSize}; },
use volume::Volume; error::Error,
sector::{Address, SectorSize},
volume::Volume,
};
/// 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,
/// symbolic link, etc. Inodes do not contain the data of the file / directory / /// symbolic link, etc. Inodes do not contain the data of the file / directory /
@ -71,26 +74,26 @@ pub struct Inode {
impl Debug for Inode { impl Debug for Inode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Inode") f.debug_struct("Inode")
.field("type_perm", unsafe { &self.type_perm }) .field("type_perm", &self.type_perm)
.field("uid", unsafe { &self.uid }) .field("uid", &self.uid)
.field("size_low", unsafe { &self.size_low }) .field("size_low", &self.size_low)
.field("atime", unsafe { &self.atime }) .field("atime", &self.atime)
.field("ctime", unsafe { &self.ctime }) .field("ctime", &self.ctime)
.field("mtime", unsafe { &self.mtime }) .field("mtime", &self.mtime)
.field("dtime", unsafe { &self.dtime }) .field("dtime", &self.dtime)
.field("gid", unsafe { &self.gid }) .field("gid", &self.gid)
.field("hard_links", unsafe { &self.hard_links }) .field("hard_links", &self.hard_links)
.field("sectors_count", unsafe { &self.sectors_count }) .field("sectors_count", &self.sectors_count)
.field("flags", unsafe { &self.flags }) .field("flags", &self.flags)
.field("os_specific_1", &self._os_specific_1) .field("os_specific_1", &self._os_specific_1)
.field("direct_pointer", unsafe { &self.direct_pointer }) .field("direct_pointer", &self.direct_pointer)
.field("indirect_pointer", unsafe { &self.indirect_pointer }) .field("indirect_pointer", &self.indirect_pointer)
.field("doubly_indirect", unsafe { &self.doubly_indirect }) .field("doubly_indirect", &self.doubly_indirect)
.field("triply_indirect", unsafe { &self.triply_indirect }) .field("triply_indirect", &self.triply_indirect)
.field("gen_number", unsafe { &self.gen_number }) .field("gen_number", &self.gen_number)
.field("ext_attribute_block", unsafe { &self.ext_attribute_block }) .field("ext_attribute_block", &self.ext_attribute_block)
.field("size_high", unsafe { &self.size_high }) .field("size_high", &self.size_high)
.field("frag_block_addr", unsafe { &self.frag_block_addr }) .field("frag_block_addr", &self.frag_block_addr)
.field("os_specific_2", &self._os_specific_2) .field("os_specific_2", &self._os_specific_2)
.finish() .finish()
} }

View file

@ -1,9 +1,12 @@
use core::mem; use {
use core::fmt::{self, Debug}; core::{
fmt::{self, Debug},
use error::Error; mem,
use sector::{Address, SectorSize}; },
use volume::Volume; error::Error,
sector::{Address, SectorSize},
volume::Volume,
};
/// 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
/// volume /// volume
@ -149,47 +152,47 @@ pub struct Superblock {
impl Debug for Superblock { impl Debug for Superblock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Superblock") f.debug_struct("Superblock")
.field("inodes_count", unsafe { &self.inodes_count }) .field("inodes_count", &self.inodes_count)
.field("blocks_count", unsafe { &self.blocks_count }) .field("blocks_count", &self.blocks_count)
.field("r_blocks_count", unsafe { &self.r_blocks_count }) .field("r_blocks_count", &self.r_blocks_count)
.field("free_blocks_count", unsafe { &self.free_blocks_count }) .field("free_blocks_count", &self.free_blocks_count)
.field("free_inodes_count", unsafe { &self.free_inodes_count }) .field("free_inodes_count", &self.free_inodes_count)
.field("first_data_block", unsafe { &self.first_data_block }) .field("first_data_block", &self.first_data_block)
.field("log_block_size", unsafe { &self.log_block_size }) .field("log_block_size", &self.log_block_size)
.field("log_frag_size", unsafe { &self.log_frag_size }) .field("log_frag_size", &self.log_frag_size)
.field("blocks_per_group", unsafe { &self.blocks_per_group }) .field("blocks_per_group", &self.blocks_per_group)
.field("frags_per_group", unsafe { &self.frags_per_group }) .field("frags_per_group", &self.frags_per_group)
.field("inodes_per_group", unsafe { &self.inodes_per_group }) .field("inodes_per_group", &self.inodes_per_group)
.field("mtime", unsafe { &self.mtime }) .field("mtime", &self.mtime)
.field("wtime", unsafe { &self.wtime }) .field("wtime", &self.wtime)
.field("mnt_count", unsafe { &self.mnt_count }) .field("mnt_count", &self.mnt_count)
.field("max_mnt_count", unsafe { &self.max_mnt_count }) .field("max_mnt_count", &self.max_mnt_count)
.field("magic", unsafe { &self.magic }) .field("magic", &self.magic)
.field("state", unsafe { &self.state }) .field("state", &self.state)
.field("errors", unsafe { &self.errors }) .field("errors", &self.errors)
.field("rev_minor", unsafe { &self.rev_minor }) .field("rev_minor", &self.rev_minor)
.field("lastcheck", unsafe { &self.lastcheck }) .field("lastcheck", &self.lastcheck)
.field("checkinterval", unsafe { &self.checkinterval }) .field("checkinterval", &self.checkinterval)
.field("creator_os", unsafe { &self.creator_os }) .field("creator_os", &self.creator_os)
.field("rev_major", unsafe { &self.rev_major }) .field("rev_major", &self.rev_major)
.field("block_uid", unsafe { &self.block_uid }) .field("block_uid", &self.block_uid)
.field("block_gid", unsafe { &self.block_gid }) .field("block_gid", &self.block_gid)
.field("first_inode", unsafe { &self.first_inode }) .field("first_inode", &self.first_inode)
.field("inode_size", unsafe { &self.inode_size }) .field("inode_size", &self.inode_size)
.field("block_group", unsafe { &self.block_group }) .field("block_group", &self.block_group)
.field("features_opt", unsafe { &self.features_opt }) .field("features_opt", &self.features_opt)
.field("features_req", unsafe { &self.features_req }) .field("features_req", &self.features_req)
.field("features_ronly", unsafe { &self.features_ronly }) .field("features_ronly", &self.features_ronly)
.field("fs_id", &self.fs_id) .field("fs_id", &self.fs_id)
.field("volume_name", &self.volume_name) .field("volume_name", &self.volume_name)
.field("last_mnt_path", &self.last_mnt_path.as_ref()) .field("last_mnt_path", &self.last_mnt_path.as_ref())
.field("compression", unsafe { &self.compression }) .field("compression", &self.compression)
.field("prealloc_blocks_files", &self.prealloc_blocks_files) .field("prealloc_blocks_files", &self.prealloc_blocks_files)
.field("prealloc_blocks_dirs", &self.prealloc_blocks_dirs) .field("prealloc_blocks_dirs", &self.prealloc_blocks_dirs)
.field("journal_id", &self.journal_id) .field("journal_id", &self.journal_id)
.field("journal_inode", unsafe { &self.journal_inode }) .field("journal_inode", &self.journal_inode)
.field("journal_dev", unsafe { &self.journal_dev }) .field("journal_dev", &self.journal_dev)
.field("journal_orphan_head", unsafe { &self.journal_orphan_head }) .field("journal_orphan_head", &self.journal_orphan_head)
.finish() .finish()
} }
} }
@ -295,8 +298,8 @@ bitflags! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use sector::Size512;
use super::*; use super::*;
use sector::Size512;
#[test] #[test]
fn find() { fn find() {

View file

@ -1,13 +1,17 @@
use core::mem; use {
use core::slice; alloc::{
use core::ops::{Deref, DerefMut, Range}; borrow::{Cow, ToOwned},
boxed::Box,
use alloc::Vec; vec::Vec,
use alloc::boxed::Box; },
use alloc::borrow::{Cow, ToOwned}; core::{
mem,
use error::Error; ops::{Deref, DerefMut, Range},
use sector::{Address, SectorSize}; slice,
},
error::Error,
sector::{Address, SectorSize},
};
pub mod size; pub mod size;
use self::size::Size; use self::size::Size;
@ -257,15 +261,15 @@ impl_slice!(Box<[T]>);
#[cfg(any(test, not(feature = "no_std")))] #[cfg(any(test, not(feature = "no_std")))]
mod file { mod file {
use std::ops::Range;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::ops::Range;
use sector::{Address, SectorSize}; use sector::{Address, SectorSize};
use super::{Volume, VolumeCommit, VolumeSlice};
use super::size::Size; use super::size::Size;
use super::{Volume, VolumeCommit, VolumeSlice};
impl<S: SectorSize> Volume<u8, S> for RefCell<File> { impl<S: SectorSize> Volume<u8, S> for RefCell<File> {
type Error = io::Error; type Error = io::Error;
@ -318,9 +322,9 @@ mod file {
range: Range<Address<S>>, range: Range<Address<S>>,
) -> Result<VolumeSlice<'a, u8, S>, Self::Error> { ) -> Result<VolumeSlice<'a, u8, S>, Self::Error> {
let index = range.start; let index = range.start;
let mut vec = Vec::with_capacity((range.end - range.start) let mut vec = Vec::with_capacity(
.into_index() (range.end - range.start).into_index() as usize,
as usize); );
unsafe { unsafe {
vec.set_len((range.end - range.start).into_index() as usize); vec.set_len((range.end - range.start).into_index() as usize);
} }
@ -335,8 +339,8 @@ mod file {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use sector::{Address, Size512};
use super::*; use super::*;
use sector::{Address, Size512};
#[test] #[test]
fn volume() { fn volume() {

View file

@ -1,7 +1,10 @@
use core::fmt::{self, Display}; use {
use core::cmp::Ordering; core::{
cmp::Ordering,
use sector::{Address, SectorSize}; fmt::{self, Display},
},
sector::{Address, SectorSize},
};
#[derive(Clone, Copy, Debug, Hash)] #[derive(Clone, Copy, Debug, Hash)]
pub enum Size<S: SectorSize> { pub enum Size<S: SectorSize> {