documentation

This commit is contained in:
Able 2022-02-07 23:23:44 -06:00
parent 1e537b063c
commit 8f7155dcff
11 changed files with 142 additions and 122 deletions

View file

@ -1,3 +1,4 @@
//! Errors
use {
alloc::string::String,
core::fmt::{self, Display},
@ -9,39 +10,60 @@ use std::io;
/// The set of all possible errors
#[derive(Debug)]
pub enum Error {
/// Generic error
Other(String),
/// Bad magic number
BadMagic {
/// The magic number
magic: u16,
},
/// Out of bounds error
OutOfBounds {
/// index
index: usize,
},
/// Address out of bounds
AddressOutOfBounds {
///
sector: u32,
///
offset: u32,
///
size: usize,
},
/// Bad block group count
BadBlockGroupCount {
///
by_blocks: u32,
///
by_inodes: u32,
},
/// Inode Not Found
InodeNotFound {
/// inode number
inode: u32,
},
/// Inode is not a directory
NotADirectory {
/// inode number
inode: u32,
/// inode name
name: String,
},
/// Not Absolute Path
NotAbsolute {
/// path name
name: String,
},
/// Not Found
NotFound {
/// inode name
name: String,
},
#[cfg(any(test, not(feature = "no_std")))]
Io {
inner: io::Error,
},
Io { inner: io::Error },
}
impl Display for Error {
@ -98,4 +120,5 @@ impl From<io::Error> for Error {
}
}
/// Infalliable
pub enum Infallible {}

View file

@ -1,3 +1,5 @@
//!
use {
alloc::vec::Vec,
core::mem,
@ -34,6 +36,7 @@ pub struct Ext2<S: SectorSize, V: Volume<u8, 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(
@ -63,14 +66,14 @@ impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
block_groups,
})
}
/// Return the version of the filesystem
pub fn version(&self) -> (u32, u16) {
(
self.superblock.inner.rev_major,
self.superblock.inner.rev_minor,
)
}
/// Return inode size
pub fn inode_size(&self) -> usize {
if self.version().0 == 0 {
mem::size_of::<RawInode>()
@ -79,15 +82,15 @@ impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
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
@ -98,27 +101,27 @@ impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
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
}

View file

@ -1,3 +1,5 @@
//!
use {
super::Ext2,
alloc::{
@ -16,18 +18,20 @@ use {
sys::inode::Inode as RawInode,
volume::Volume,
};
/// DOCME: what is this?
pub struct Synced<T> {
inner: Arc<Mutex<T>>,
}
impl<T> Synced<T> {
/// DOCME: what is this?
pub fn with_inner(inner: T) -> Synced<T> {
Synced {
inner: Arc::new(Mutex::new(inner)),
}
}
/// DOCME: what is this?
pub fn inner<'a>(&'a self) -> MutexGuard<'a, T> {
self.inner.lock()
}
@ -42,22 +46,23 @@ impl<T> Clone for Synced<T> {
}
impl<S: SectorSize, V: Volume<u8, S>> Synced<Ext2<S, V>> {
/// DOCME: what is this?
pub fn new(volume: V) -> Result<Synced<Ext2<S, V>>, Error> {
Ext2::new(volume).map(|inner| Synced::with_inner(inner))
}
/// Get the root inode.
pub fn root_inode(&self) -> Inode<S, V> {
self.inode_nth(2).unwrap()
}
/// Get the inode at the given index.
pub fn inode_nth(&self, index: usize) -> Option<Inode<S, V>> {
self.inodes_nth(index).next()
}
/// DOCME: what is this?
pub fn inodes(&self) -> Inodes<S, V> {
self.inodes_nth(1)
}
/// DOCME: what is this?
pub fn inodes_nth(&self, index: usize) -> Inodes<S, V> {
assert!(index > 0, "inodes are 1-indexed");
let inner = self.inner();
@ -70,11 +75,11 @@ impl<S: SectorSize, V: Volume<u8, S>> Synced<Ext2<S, V>> {
index,
}
}
/// DOCME: what is this?
pub fn sector_size(&self) -> usize {
S::SIZE
}
/// DOCME: what is this?
pub fn log_sector_size(&self) -> u32 {
S::LOG_SIZE
}
@ -256,6 +261,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Debug for Synced<Ext2<S, V>> {
}
#[derive(Debug, Clone)]
/// A collection of inodes.
pub struct Inodes<S: SectorSize, V: Volume<u8, S>> {
fs: Synced<Ext2<S, V>>,
log_block_size: u32,
@ -302,6 +308,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Iterator for Inodes<S, V> {
}
#[derive(Debug)]
/// A single inode in an ext2 filesystem.
pub struct Inode<S: SectorSize, V: Volume<u8, S>> {
fs: Synced<Ext2<S, V>>,
inner: RawInode,
@ -321,6 +328,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Clone for Inode<S, V> {
}
impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
///
pub fn new(
fs: Synced<Ext2<S, V>>,
inner: RawInode,
@ -334,7 +342,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
num,
}
}
/// Read to the end of a buffer.
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize, Error> {
let total_size = self.size();
let capacity = buf.capacity();
@ -358,14 +366,14 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
Err(err)
})
}
/// Return blocks on a sector
pub fn blocks(&self) -> InodeBlocks<S, V> {
InodeBlocks {
inode: self.clone(),
index: 0,
}
}
/// return a directory iterator
pub fn directory(&self) -> Option<Directory<S, V>> {
if self.is_dir() {
Some(Directory {
@ -381,16 +389,16 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
None
}
}
/// Determine if an inode is a directory
pub fn is_dir(&self) -> bool {
use sys::inode::TypePerm;
unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) }
self.inner.type_perm.contains(TypePerm::DIRECTORY)
}
///
pub fn block(&self, index: usize) -> Option<NonZeroU32> {
self.try_block(index).ok().and_then(|block| block)
}
/// Try to get a block
pub fn try_block(
&self,
mut index: usize,
@ -501,27 +509,27 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
Ok(None)
}
///
pub fn in_use(&self) -> bool {
self.inner.hard_links > 0
}
/// return the uid
pub fn uid(&self) -> u16 {
self.inner.uid
}
///
pub fn sectors(&self) -> usize {
self.inner.sectors_count as usize
}
///
pub fn size32(&self) -> u32 {
self.inner.size_low
}
///
pub fn size64(&self) -> u64 {
self.inner.size_low as u64 | (self.inner.size_high as u64) << 32
}
///
#[cfg(target_pointer_width = "64")]
#[inline]
pub fn size(&self) -> usize {
@ -576,6 +584,7 @@ impl<S: SectorSize, V: Volume<u8, S>> File for Inode<S, V> {
}
}
///
#[derive(Debug, Clone)]
pub struct InodeBlocks<S: SectorSize, V: Volume<u8, S>> {
inode: Inode<S, V>,
@ -611,6 +620,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Iterator for InodeBlocks<S, V> {
}
#[derive(Debug, Clone)]
/// A directory structure
pub struct Directory<S: SectorSize, V: Volume<u8, S>> {
blocks: InodeBlocks<S, V>,
offset: usize,
@ -664,9 +674,13 @@ impl<S: SectorSize, V: Volume<u8, S>> Iterator for Directory<S, V> {
}
#[derive(Clone)]
/// A directory entry
pub struct DirectoryEntry {
/// The name of the entry
pub name: Vec<u8>,
/// The inode of the entry
pub inode: usize,
///
pub ty: u8,
}

View file

@ -1,3 +1,6 @@
//! Ext2 crate for ableOS
#![deny(missing_docs)]
#![feature(
min_specialization,
const_fn_trait_bound,
@ -6,8 +9,8 @@
)]
#![cfg_attr(all(not(test), feature = "no_std"), no_std)]
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate bitflags;
extern crate genfs;

View file

@ -1,29 +1,35 @@
//! Sector data.
use core::{
fmt::{self, Debug, Display, LowerHex},
iter::Step,
marker::PhantomData,
ops::{Add, Sub},
};
/// Size of a sector in bytes
pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd + 'static {
// log_sector_size = log_2(sector_size)
/// DOCME: What is this?
const LOG_SIZE: u32;
/// DOCME: What is this?
const SIZE: usize = 1 << Self::LOG_SIZE;
/// DOCME: What is this?
const OFFSET_MASK: u32 = (Self::SIZE - 1) as u32;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
/// DOCME: What is this?
pub struct Size512;
impl SectorSize for Size512 {
const LOG_SIZE: u32 = 9;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
/// DOCME: What is this?
pub struct Size1024;
impl SectorSize for Size1024 {
const LOG_SIZE: u32 = 10;
}
/// DOCME: What is this?
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size2048;
impl SectorSize for Size2048 {
@ -31,13 +37,14 @@ impl SectorSize for Size2048 {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
/// DOCME: What is this?
pub struct Size4096;
impl SectorSize for Size4096 {
const LOG_SIZE: u32 = 12;
}
/// Address in a physical sector
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Address<S: SectorSize> {
sector: u32,
offset: u32,
@ -45,6 +52,7 @@ pub struct Address<S: SectorSize> {
}
impl<S: SectorSize> Address<S> {
///
pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address<S> {
assert!((offset as usize) < S::SIZE, "offset out of sector bounds");
let _phantom = PhantomData;
@ -54,13 +62,13 @@ impl<S: SectorSize> Address<S> {
_phantom,
}
}
///
pub fn new(sector: u32, offset: i32) -> Address<S> {
let sector = (sector as i32 + (offset >> S::LOG_SIZE)) as u32;
let offset = offset.abs() as u32 & S::OFFSET_MASK;
unsafe { Address::new_unchecked(sector, offset) }
}
///
pub fn with_block_size(
block: u32,
offset: i32,
@ -75,23 +83,23 @@ impl<S: SectorSize> Address<S> {
let sector = block << log_diff | top_offset;
unsafe { Address::new_unchecked(sector, offset) }
}
///
pub fn into_index(&self) -> u64 {
((self.sector as u64) << S::LOG_SIZE) + self.offset as u64
}
/// Get the size of the sector
pub const fn sector_size(&self) -> usize {
S::SIZE
}
/// DOCME: What is this?
pub const fn log_sector_size(&self) -> u32 {
S::LOG_SIZE
}
/// Return the sector number
pub fn sector(&self) -> u32 {
self.sector
}
/// Return the offset in the sector
pub fn offset(&self) -> u32 {
self.offset
}
@ -105,6 +113,7 @@ impl<S: SectorSize> Step for Address<S> {
None
}
}
/*
fn replace_one(&mut self) -> Self {
mem::replace(self, Address::new(1, 0))
@ -129,22 +138,12 @@ impl<S: SectorSize> Step for Address<S> {
}
*/
fn forward_checked(start: Self, count: usize) -> Option<Self> {
todo!("forward_checked")
fn forward_checked(_start: Self, count: usize) -> Option<Self> {
todo!("forward_checked: count: {}", count);
}
fn backward_checked(start: Self, count: usize) -> Option<Self> {
todo!("backward_checked")
}
}
impl<S: SectorSize> Debug for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let name = format!("Address<{}>", S::SIZE);
f.debug_struct(&name)
.field("sector", &self.sector)
.field("offset", &self.offset)
.finish()
fn backward_checked(_start: Self, count: usize) -> Option<Self> {
todo!("backward_checked count: {}", count);
}
}

View file

@ -1,9 +1,8 @@
//!
use {
alloc::vec::Vec,
core::{
fmt::{self, Debug},
mem,
},
core::{fmt::Debug, mem},
error::Error,
sector::{Address, SectorSize},
volume::Volume,
@ -22,7 +21,7 @@ use {
/// Remember that blocks are numbered starting at 0, and that block numbers
/// don't usually correspond to physical block addresses.
#[repr(C, packed)]
#[derive(Clone, Copy)]
#[derive(Clone, Debug, Copy)]
pub struct BlockGroupDescriptor {
/// Block address of block usage bitmap
pub block_usage_addr: u32,
@ -40,20 +39,8 @@ pub struct BlockGroupDescriptor {
_reserved: [u8; 14],
}
impl Debug for BlockGroupDescriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BlockGroupDescriptor")
.field("block_usage_addr", &self.block_usage_addr)
.field("inode_usage_addr", &self.inode_usage_addr)
.field("inode_table_block", &self.inode_table_block)
.field("free_blocks_count", &self.free_blocks_count)
.field("free_inodes_count", &self.free_inodes_count)
.field("dirs_count", &self.dirs_count)
.finish()
}
}
impl BlockGroupDescriptor {
/// Find a descriptor in a descriptor table
pub unsafe fn find_descriptor<S: SectorSize, V: Volume<u8, S>>(
haystack: &V,
offset: Address<S>,
@ -74,7 +61,7 @@ impl BlockGroupDescriptor {
Ok(descr)
}
/// find a descriptor table
pub unsafe fn find_descriptor_table<S: SectorSize, V: Volume<u8, S>>(
haystack: &V,
offset: Address<S>,

View file

@ -1,8 +1,7 @@
//!
use {
core::{
fmt::{self, Debug},
mem,
},
core::{fmt::Debug, mem},
error::Error,
sector::{Address, SectorSize},
volume::Volume,
@ -16,7 +15,7 @@ use {
/// array of inodes it is responsible for, and conversely every inode within a
/// file system belongs to one of such tables (and one of such block groups).
#[repr(C, packed)]
#[derive(Clone, Copy)]
#[derive(Clone, Debug, Copy)]
pub struct Inode {
/// Type and Permissions (see below)
pub type_perm: TypePerm,
@ -71,35 +70,8 @@ pub struct Inode {
pub _os_specific_2: [u8; 12],
}
impl Debug for Inode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Inode")
.field("type_perm", &self.type_perm)
.field("uid", &self.uid)
.field("size_low", &self.size_low)
.field("atime", &self.atime)
.field("ctime", &self.ctime)
.field("mtime", &self.mtime)
.field("dtime", &self.dtime)
.field("gid", &self.gid)
.field("hard_links", &self.hard_links)
.field("sectors_count", &self.sectors_count)
.field("flags", &self.flags)
.field("os_specific_1", &self._os_specific_1)
.field("direct_pointer", &self.direct_pointer)
.field("indirect_pointer", &self.indirect_pointer)
.field("doubly_indirect", &self.doubly_indirect)
.field("triply_indirect", &self.triply_indirect)
.field("gen_number", &self.gen_number)
.field("ext_attribute_block", &self.ext_attribute_block)
.field("size_high", &self.size_high)
.field("frag_block_addr", &self.frag_block_addr)
.field("os_specific_2", &self._os_specific_2)
.finish()
}
}
impl Inode {
/// Discover the inode location on the disk.
pub unsafe fn find_inode<S: SectorSize, V: Volume<u8, S>>(
haystack: &V,
offset: Address<S>,
@ -127,6 +99,7 @@ impl Inode {
}
bitflags! {
///
pub struct TypePerm: u16 {
/// FIFO
const FIFO = 0x1000;
@ -170,6 +143,7 @@ bitflags! {
}
bitflags! {
/// Flags
pub struct Flags: u32 {
/// Secure deletion (not used)
const SECURE_DEL = 0x00000001;

View file

@ -1,3 +1,5 @@
pub mod superblock;
//!
pub mod block_group;
pub mod inode;
pub mod superblock;

View file

@ -1,8 +1,7 @@
//! Superblock information
use {
core::{
fmt::{self, Debug},
mem,
},
core::{fmt::Debug, mem},
error::Error,
sector::{Address, SectorSize},
volume::Volume,
@ -44,7 +43,7 @@ pub const OS_LITE: u32 = 4;
/// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of
/// sector 2 and 3.
#[repr(C, packed)]
#[derive(Clone, Copy)]
#[derive(Clone, Debug, Copy)]
pub struct Superblock {
// taken from https://wiki.osdev.org/Ext2
/// Total number of inodes in file system
@ -148,7 +147,7 @@ pub struct Superblock {
#[doc(hidden)]
_reserved: [u8; 788],
}
/*
impl Debug for Superblock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Superblock")
@ -196,8 +195,9 @@ impl Debug for Superblock {
.finish()
}
}
*/
impl Superblock {
/// Discover the location of the superblock in the given block device.
pub unsafe fn find<S: SectorSize, V: Volume<u8, S>>(
haystack: &V,
) -> Result<(Superblock, Address<S>), Error> {
@ -227,15 +227,17 @@ impl Superblock {
}
#[inline]
/// Return the block size
pub fn block_size(&self) -> usize {
1024 << self.log_block_size
}
#[inline]
/// Return the fragment size
pub fn frag_size(&self) -> usize {
1024 << self.log_frag_size
}
/// Return the number of blocks per group
pub fn block_group_count(&self) -> Result<u32, (u32, u32)> {
let blocks_mod = self.blocks_count % self.blocks_per_group;
let inodes_mod = self.inodes_count % self.inodes_per_group;

View file

@ -1,3 +1,4 @@
#![allow(missing_docs)]
use {
alloc::{
borrow::{Cow, ToOwned},

View file

@ -1,3 +1,5 @@
//!
use {
core::{
cmp::Ordering,
@ -7,19 +9,28 @@ use {
};
#[derive(Clone, Copy, Debug, Hash)]
/// A size
pub enum Size<S: SectorSize> {
/// An unbounded size
Unbounded,
/// A bounded size
Bounded(Address<S>),
}
impl<S: SectorSize> Size<S> {
/// Try to get the length of the sector
pub fn try_len(&self) -> Option<Address<S>> {
match *self {
Size::Unbounded => None,
Size::Bounded(n) => Some(n),
}
}
/// Get the length of the sector unsafely
///
/// # Safety
///
/// This function is unsafe because it does not check that the size is
/// bounded.
pub unsafe fn len(&self) -> Address<S> {
match *self {
Size::Unbounded => panic!(
@ -31,6 +42,7 @@ impl<S: SectorSize> Size<S> {
}
impl<S: SectorSize> Size<S> {
/// Check if the size is unbounded
pub fn is_bounded(&self) -> bool {
match *self {
Size::Unbounded => false,