fs/ext2: indirect block reading
This commit is contained in:
parent
6e07fa91db
commit
b4fbc5cd4c
218
kernel/driver/fs/ext2/src/data.rs
Normal file
218
kernel/driver/fs/ext2/src/data.rs
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, vec};
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use libk::vfs::Metadata;
|
||||||
|
use static_assertions::const_assert_eq;
|
||||||
|
use yggdrasil_abi::io::{FileMode, FileType, GroupId, UserId};
|
||||||
|
|
||||||
|
use crate::Ext2Fs;
|
||||||
|
|
||||||
|
pub const SUPERBLOCK_OFFSET: u64 = 1024;
|
||||||
|
pub const EXT2_SIGNATURE: u16 = 0xEF53;
|
||||||
|
pub const ROOT_INODE: u32 = 2;
|
||||||
|
|
||||||
|
pub const DIRECT_BLOCK_COUNT: usize = 12;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct InodeMode(u16);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Superblock {
|
||||||
|
pub total_inodes: u32,
|
||||||
|
pub total_blocks: u32,
|
||||||
|
pub root_reserved_blocks: u32,
|
||||||
|
pub total_unallocated_blocks: u32,
|
||||||
|
pub total_unallocated_inodes: u32,
|
||||||
|
pub superblock_number: u32,
|
||||||
|
pub block_size_log2: u32,
|
||||||
|
pub fragment_size_log2: u32,
|
||||||
|
pub block_group_block_count: u32,
|
||||||
|
pub block_group_fragment_count: u32,
|
||||||
|
pub block_group_inode_count: u32,
|
||||||
|
pub last_mount_time: u32,
|
||||||
|
pub last_written_time: u32,
|
||||||
|
pub mounts_since_fsck: u16,
|
||||||
|
pub mounts_allowed_between_fsck: u16,
|
||||||
|
pub signature: u16,
|
||||||
|
pub state: u16,
|
||||||
|
pub error_behavior: u16,
|
||||||
|
pub version_minor: u16,
|
||||||
|
pub last_fsck_time: u32,
|
||||||
|
pub fsck_interval: u32,
|
||||||
|
pub creator_os_id: u32,
|
||||||
|
pub version_major: u32,
|
||||||
|
pub root_user_id: u16,
|
||||||
|
pub root_group_id: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ExtendedSuperblock {
|
||||||
|
pub base: Superblock,
|
||||||
|
pub first_non_reserved_inode: u32,
|
||||||
|
pub inode_struct_size: u16,
|
||||||
|
pub superblock_block_group_number: u16,
|
||||||
|
pub optional_features: u32,
|
||||||
|
pub required_features: u32,
|
||||||
|
pub readonly_features: u32,
|
||||||
|
pub filesystem_id: [u8; 16],
|
||||||
|
pub volume_name: [u8; 16],
|
||||||
|
pub last_mount_path: [u8; 64],
|
||||||
|
pub compression_algorithms: u32,
|
||||||
|
pub file_prealloc_block_count: u8,
|
||||||
|
pub directory_prealloc_block_count: u8,
|
||||||
|
_0: u16,
|
||||||
|
pub journal_id: [u8; 16],
|
||||||
|
pub journal_inode: u32,
|
||||||
|
pub journal_device: u32,
|
||||||
|
pub orphan_inode_list_head: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct BlockGroupDescriptor {
|
||||||
|
pub block_usage_bitmap: u32,
|
||||||
|
pub inode_usage_bitmap: u32,
|
||||||
|
pub inode_table: u32,
|
||||||
|
pub unallocated_blocks: u16,
|
||||||
|
pub unallocated_inodes: u16,
|
||||||
|
pub unallocated_directories: u16,
|
||||||
|
_0: [u8; 14],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BlockGroupDescriptorTable {
|
||||||
|
pub(crate) data: Box<[u8]>,
|
||||||
|
pub(crate) len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Inode {
|
||||||
|
pub mode: InodeMode,
|
||||||
|
pub uid: u16,
|
||||||
|
pub size_lower: u32,
|
||||||
|
pub atime: u32,
|
||||||
|
pub ctime: u32,
|
||||||
|
pub mtime: u32,
|
||||||
|
pub dtime: u32,
|
||||||
|
pub gid: u16,
|
||||||
|
pub hard_links: u16,
|
||||||
|
pub sector_count: u32,
|
||||||
|
pub flags: u32,
|
||||||
|
pub os_val1: u32,
|
||||||
|
pub direct_blocks: [u32; DIRECT_BLOCK_COUNT],
|
||||||
|
pub indirect_block_l1: u32,
|
||||||
|
pub indirect_block_l2: u32,
|
||||||
|
pub indirect_block_l3: u32,
|
||||||
|
pub generation: u32,
|
||||||
|
pub facl: u32,
|
||||||
|
pub size_upper: u32,
|
||||||
|
pub frag_block_no: u32,
|
||||||
|
pub os_val2: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Dirent {
|
||||||
|
pub ino: u32,
|
||||||
|
pub ent_size: u16,
|
||||||
|
pub name_length_low: u8,
|
||||||
|
pub type_indicator: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockGroupDescriptorTable {
|
||||||
|
pub fn with_capacity(size: usize, len: usize) -> Self {
|
||||||
|
let data = vec![0; size].into_boxed_slice();
|
||||||
|
Self { data, len }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn descriptor(&self, index: u32) -> &BlockGroupDescriptor {
|
||||||
|
let index = index as usize;
|
||||||
|
if index >= self.len {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
bytemuck::from_bytes(
|
||||||
|
&self.data[index * size_of::<BlockGroupDescriptor>()
|
||||||
|
..(index + 1) * size_of::<BlockGroupDescriptor>()],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const_assert_eq!(size_of::<BlockGroupDescriptor>(), 32);
|
||||||
|
|
||||||
|
impl ExtendedSuperblock {
|
||||||
|
pub fn inode_size(&self) -> usize {
|
||||||
|
if self.base.version_major != 0 {
|
||||||
|
self.inode_struct_size as _
|
||||||
|
} else {
|
||||||
|
128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn required_features(&self) -> u32 {
|
||||||
|
if self.base.version_major != 0 {
|
||||||
|
self.required_features
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ExtendedSuperblock {
|
||||||
|
type Target = Superblock;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ExtendedSuperblock {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inode {
|
||||||
|
pub fn blocks(&self, fs: &Ext2Fs) -> usize {
|
||||||
|
(self.size_lower as usize + fs.block_size - 1) / fs.block_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_id(&self) -> UserId {
|
||||||
|
unsafe { UserId::from_raw(self.uid as _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn group_id(&self) -> GroupId {
|
||||||
|
unsafe { GroupId::from_raw(self.uid as _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn metadata(&self) -> Metadata {
|
||||||
|
Metadata {
|
||||||
|
uid: self.user_id(),
|
||||||
|
gid: self.group_id(),
|
||||||
|
mode: self.mode.permissions(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InodeMode {
|
||||||
|
pub fn node_type(&self) -> Option<FileType> {
|
||||||
|
match self.0 & 0xF000 {
|
||||||
|
0x4000 => Some(FileType::Directory),
|
||||||
|
0x8000 => Some(FileType::File),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn permissions(&self) -> FileMode {
|
||||||
|
unsafe { FileMode::from_raw(self.0 as u32 & 0o777) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<InodeMode> for u16 {
|
||||||
|
fn from(value: InodeMode) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ use libk::{
|
|||||||
vfs::{CommonImpl, DirectoryImpl, DirectoryOpenPosition, Metadata, Node, NodeFlags, NodeRef},
|
vfs::{CommonImpl, DirectoryImpl, DirectoryOpenPosition, Metadata, Node, NodeFlags, NodeRef},
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::{
|
use yggdrasil_abi::{
|
||||||
io::{DirectoryEntry, FileMode, FileType, GroupId, UserId},
|
io::{DirectoryEntry, FileType},
|
||||||
util::FixedString,
|
util::FixedString,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,11 +158,7 @@ impl CommonImpl for DirectoryNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
||||||
Ok(Metadata {
|
Ok(self.inode.metadata())
|
||||||
uid: unsafe { UserId::from_raw(self.inode.uid as _) },
|
|
||||||
gid: unsafe { GroupId::from_raw(self.inode.gid as _) },
|
|
||||||
mode: unsafe { FileMode::from_raw(self.inode.mode as u32 & 0o777) },
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use libk::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::io::{FileMode, GroupId, OpenOptions, UserId};
|
use yggdrasil_abi::io::OpenOptions;
|
||||||
|
|
||||||
use crate::{Ext2Fs, Inode};
|
use crate::{Ext2Fs, Inode};
|
||||||
|
|
||||||
@ -55,11 +55,7 @@ impl RegularNode {
|
|||||||
|
|
||||||
impl CommonImpl for RegularNode {
|
impl CommonImpl for RegularNode {
|
||||||
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
||||||
Ok(Metadata {
|
Ok(self.inode.metadata())
|
||||||
uid: unsafe { UserId::from_raw(self.inode.uid as _) },
|
|
||||||
gid: unsafe { GroupId::from_raw(self.inode.gid as _) },
|
|
||||||
mode: unsafe { FileMode::from_raw(self.inode.mode as u32 & 0o777) },
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use core::ops::{Deref, DerefMut};
|
use alloc::sync::Arc;
|
||||||
|
use bytemuck::Zeroable;
|
||||||
use alloc::{boxed::Box, sync::Arc, vec};
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
|
||||||
use dir::DirectoryNode;
|
use dir::DirectoryNode;
|
||||||
use file::RegularNode;
|
use file::RegularNode;
|
||||||
use libk::{
|
use libk::{
|
||||||
@ -19,14 +17,15 @@ use libk::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use libk_util::OneTimeInit;
|
use libk_util::OneTimeInit;
|
||||||
use static_assertions::const_assert_eq;
|
|
||||||
|
|
||||||
|
mod data;
|
||||||
pub mod dir;
|
pub mod dir;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
|
||||||
pub const SUPERBLOCK_OFFSET: u64 = 1024;
|
pub use data::{
|
||||||
pub const EXT2_SIGNATURE: u16 = 0xEF53;
|
BlockGroupDescriptor, BlockGroupDescriptorTable, Dirent, ExtendedSuperblock, Inode, Superblock,
|
||||||
pub const BGDT_BLOCK_NUMBER: u32 = 2;
|
};
|
||||||
|
use yggdrasil_abi::io::FileType;
|
||||||
|
|
||||||
pub struct Ext2Fs {
|
pub struct Ext2Fs {
|
||||||
cache: BlockCache,
|
cache: BlockCache,
|
||||||
@ -37,169 +36,11 @@ pub struct Ext2Fs {
|
|||||||
inode_size: usize,
|
inode_size: usize,
|
||||||
block_size: usize,
|
block_size: usize,
|
||||||
inodes_per_block: usize,
|
inodes_per_block: usize,
|
||||||
|
pointers_per_block: usize,
|
||||||
|
|
||||||
root: OneTimeInit<NodeRef>,
|
root: OneTimeInit<NodeRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Superblock {
|
|
||||||
total_inodes: u32,
|
|
||||||
total_blocks: u32,
|
|
||||||
root_reserved_blocks: u32,
|
|
||||||
total_unallocated_blocks: u32,
|
|
||||||
total_unallocated_inodes: u32,
|
|
||||||
superblock_number: u32,
|
|
||||||
block_size_log2: u32,
|
|
||||||
fragment_size_log2: u32,
|
|
||||||
block_group_block_count: u32,
|
|
||||||
block_group_fragment_count: u32,
|
|
||||||
block_group_inode_count: u32,
|
|
||||||
last_mount_time: u32,
|
|
||||||
last_written_time: u32,
|
|
||||||
mounts_since_fsck: u16,
|
|
||||||
mounts_allowed_between_fsck: u16,
|
|
||||||
signature: u16,
|
|
||||||
state: u16,
|
|
||||||
error_behavior: u16,
|
|
||||||
version_minor: u16,
|
|
||||||
last_fsck_time: u32,
|
|
||||||
fsck_interval: u32,
|
|
||||||
creator_os_id: u32,
|
|
||||||
version_major: u32,
|
|
||||||
root_user_id: u16,
|
|
||||||
root_group_id: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct ExtendedSuperblock {
|
|
||||||
base: Superblock,
|
|
||||||
first_non_reserved_inode: u32,
|
|
||||||
inode_struct_size: u16,
|
|
||||||
superblock_block_group_number: u16,
|
|
||||||
optional_features: u32,
|
|
||||||
required_features: u32,
|
|
||||||
readonly_features: u32,
|
|
||||||
filesystem_id: [u8; 16],
|
|
||||||
volume_name: [u8; 16],
|
|
||||||
last_mount_path: [u8; 64],
|
|
||||||
compression_algorithms: u32,
|
|
||||||
file_prealloc_block_count: u8,
|
|
||||||
directory_prealloc_block_count: u8,
|
|
||||||
_0: u16,
|
|
||||||
journal_id: [u8; 16],
|
|
||||||
journal_inode: u32,
|
|
||||||
journal_device: u32,
|
|
||||||
orphan_inode_list_head: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct BlockGroupDescriptor {
|
|
||||||
block_usage_bitmap: u32,
|
|
||||||
inode_usage_bitmap: u32,
|
|
||||||
inode_table: u32,
|
|
||||||
unallocated_blocks: u16,
|
|
||||||
unallocated_inodes: u16,
|
|
||||||
unallocated_directories: u16,
|
|
||||||
_0: [u8; 14],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BlockGroupDescriptorTable {
|
|
||||||
data: Box<[u8]>,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Inode {
|
|
||||||
mode: u16,
|
|
||||||
uid: u16,
|
|
||||||
size_lower: u32,
|
|
||||||
atime: u32,
|
|
||||||
ctime: u32,
|
|
||||||
mtime: u32,
|
|
||||||
dtime: u32,
|
|
||||||
gid: u16,
|
|
||||||
hard_links: u16,
|
|
||||||
sector_count: u32,
|
|
||||||
flags: u32,
|
|
||||||
os_val1: u32,
|
|
||||||
direct_blocks: [u32; 12],
|
|
||||||
indirect_block_l1: u32,
|
|
||||||
indirect_block_l2: u32,
|
|
||||||
indirect_block_l3: u32,
|
|
||||||
generation: u32,
|
|
||||||
facl: u32,
|
|
||||||
size_upper: u32,
|
|
||||||
frag_block_no: u32,
|
|
||||||
os_val2: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Dirent {
|
|
||||||
ino: u32,
|
|
||||||
ent_size: u16,
|
|
||||||
name_length_low: u8,
|
|
||||||
type_indicator: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BlockReader<'a> {
|
|
||||||
fs: &'a Ext2Fs,
|
|
||||||
inode: &'a Inode,
|
|
||||||
len: u32,
|
|
||||||
index: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> BlockReader<'a> {
|
|
||||||
pub fn new(fs: &'a Ext2Fs, inode: &'a Inode) -> Self {
|
|
||||||
let len = if inode.mode & 0xF000 == 0x4000 {
|
|
||||||
(inode.size_lower as u64 / fs.block_size as u64) as u32
|
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
fs,
|
|
||||||
inode,
|
|
||||||
len,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn next(&mut self) -> Option<Result<CachedBlockRef, Error>> {
|
|
||||||
if self.index >= self.len {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let block = self.fs.inode_block(self.inode, self.index).await;
|
|
||||||
if block.is_ok() {
|
|
||||||
self.index += 1;
|
|
||||||
}
|
|
||||||
Some(block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockGroupDescriptorTable {
|
|
||||||
pub fn with_capacity(size: usize, len: usize) -> Self {
|
|
||||||
let data = vec![0; size].into_boxed_slice();
|
|
||||||
Self { data, len }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn descriptor(&self, index: u32) -> &BlockGroupDescriptor {
|
|
||||||
let index = index as usize;
|
|
||||||
if index >= self.len {
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
bytemuck::from_bytes(
|
|
||||||
&self.data[index * size_of::<BlockGroupDescriptor>()
|
|
||||||
..(index + 1) * size_of::<BlockGroupDescriptor>()],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const_assert_eq!(size_of::<BlockGroupDescriptor>(), 32);
|
|
||||||
|
|
||||||
impl Ext2Fs {
|
impl Ext2Fs {
|
||||||
pub async fn create(device: &'static dyn BlockDevice) -> Result<NodeRef, Error> {
|
pub async fn create(device: &'static dyn BlockDevice) -> Result<NodeRef, Error> {
|
||||||
let fs = Self::create_fs(device).await.map_err(|e| {
|
let fs = Self::create_fs(device).await.map_err(|e| {
|
||||||
@ -207,7 +48,7 @@ impl Ext2Fs {
|
|||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
let fs = Arc::new(fs);
|
let fs = Arc::new(fs);
|
||||||
let root = fs.load_node(2).await?;
|
let root = fs.load_node(data::ROOT_INODE).await?;
|
||||||
|
|
||||||
fs.root.init(root.clone());
|
fs.root.init(root.clone());
|
||||||
|
|
||||||
@ -217,20 +58,23 @@ impl Ext2Fs {
|
|||||||
async fn create_fs(device: &'static dyn BlockDevice) -> Result<Self, Error> {
|
async fn create_fs(device: &'static dyn BlockDevice) -> Result<Self, Error> {
|
||||||
let mut superblock = ExtendedSuperblock::zeroed();
|
let mut superblock = ExtendedSuperblock::zeroed();
|
||||||
device
|
device
|
||||||
.read(SUPERBLOCK_OFFSET, bytemuck::bytes_of_mut(&mut superblock))
|
.read(
|
||||||
|
data::SUPERBLOCK_OFFSET,
|
||||||
|
bytemuck::bytes_of_mut(&mut superblock),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if superblock.signature != EXT2_SIGNATURE {
|
if superblock.signature != data::EXT2_SIGNATURE {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Invalid ext2 signature: expected {:#x}, got {:#x}",
|
"Invalid ext2 signature: expected {:#x}, got {:#x}",
|
||||||
EXT2_SIGNATURE,
|
data::EXT2_SIGNATURE,
|
||||||
superblock.signature
|
superblock.signature
|
||||||
);
|
);
|
||||||
return Err(Error::InvalidArgument);
|
return Err(Error::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bgdt_offset = 1;
|
|
||||||
let block_size = 1024usize << superblock.block_size_log2;
|
let block_size = 1024usize << superblock.block_size_log2;
|
||||||
|
let bgdt_block_index = (data::SUPERBLOCK_OFFSET as usize + block_size - 1) / block_size;
|
||||||
|
|
||||||
let bgdt_entry_count = ((superblock.total_blocks + superblock.block_group_block_count - 1)
|
let bgdt_entry_count = ((superblock.total_blocks + superblock.block_group_block_count - 1)
|
||||||
/ superblock.block_group_block_count) as usize;
|
/ superblock.block_group_block_count) as usize;
|
||||||
@ -254,7 +98,7 @@ impl Ext2Fs {
|
|||||||
bgdt_entry_count,
|
bgdt_entry_count,
|
||||||
);
|
);
|
||||||
for i in 0..bgdt_block_count {
|
for i in 0..bgdt_block_count {
|
||||||
let disk_offset = (i as u64 + bgdt_offset) * block_size as u64;
|
let disk_offset = (i + bgdt_block_index) as u64 * block_size as u64;
|
||||||
device
|
device
|
||||||
.read_exact(
|
.read_exact(
|
||||||
disk_offset,
|
disk_offset,
|
||||||
@ -269,9 +113,10 @@ impl Ext2Fs {
|
|||||||
block_size,
|
block_size,
|
||||||
inode_size: superblock.inode_size(),
|
inode_size: superblock.inode_size(),
|
||||||
inodes_per_block: block_size / superblock.inode_size(),
|
inodes_per_block: block_size / superblock.inode_size(),
|
||||||
|
pointers_per_block: block_size / size_of::<u32>(),
|
||||||
|
|
||||||
// 128 × 8 cache
|
// 128 × 8 cache
|
||||||
cache: BlockCache::with_capacity(device, block_size, 128),
|
cache: BlockCache::with_capacity(device, block_size, 512),
|
||||||
superblock,
|
superblock,
|
||||||
bgdt,
|
bgdt,
|
||||||
|
|
||||||
@ -280,12 +125,10 @@ impl Ext2Fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_node(self: &Arc<Self>, inode: Inode, ino: u32) -> Result<NodeRef, Error> {
|
fn create_node(self: &Arc<Self>, inode: Inode, ino: u32) -> Result<NodeRef, Error> {
|
||||||
match inode.mode & 0xF000 {
|
match inode.mode.node_type() {
|
||||||
// Directory
|
Some(FileType::Directory) => Ok(DirectoryNode::new(self.clone(), inode, ino)),
|
||||||
0x4000 => Ok(DirectoryNode::new(self.clone(), inode, ino)),
|
Some(FileType::File) => Ok(RegularNode::new(self.clone(), inode, ino)),
|
||||||
// Regular file
|
e => todo!("Unhandled inode type: {:?} ({:#x?})", e, inode.mode),
|
||||||
0x8000 => Ok(RegularNode::new(self.clone(), inode, ino)),
|
|
||||||
_ => todo!("Unknown file type: {:#x}", inode.mode),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,49 +168,58 @@ impl Ext2Fs {
|
|||||||
self.block(block_index).await
|
self.block(block_index).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn read_index(&self, block_index: u32, index: usize) -> Result<u32, Error> {
|
||||||
|
let block = self.block(block_index).await?;
|
||||||
|
let indirect: &[u32] = unsafe {
|
||||||
|
core::slice::from_raw_parts(&block[0] as *const _ as *const _, self.pointers_per_block)
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(indirect[index]);
|
||||||
|
}
|
||||||
|
|
||||||
async fn inode_block_index(&self, inode: &Inode, index: u32) -> Result<u32, Error> {
|
async fn inode_block_index(&self, inode: &Inode, index: u32) -> Result<u32, Error> {
|
||||||
if index < 12 {
|
let mut index = index as usize;
|
||||||
Ok(inode.direct_blocks[index as usize])
|
// L0
|
||||||
} else {
|
if index < inode.direct_blocks.len() {
|
||||||
todo!()
|
return Ok(inode.direct_blocks[index]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExtendedSuperblock {
|
// L1
|
||||||
pub fn inode_size(&self) -> usize {
|
index -= inode.direct_blocks.len();
|
||||||
if self.base.version_major != 0 {
|
if index < self.pointers_per_block {
|
||||||
self.inode_struct_size as _
|
return self.read_index(inode.indirect_block_l1, index).await;
|
||||||
} else {
|
|
||||||
128
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn required_features(&self) -> u32 {
|
// L2
|
||||||
if self.base.version_major != 0 {
|
index -= self.pointers_per_block;
|
||||||
self.required_features
|
if index < self.pointers_per_block * self.pointers_per_block {
|
||||||
} else {
|
let l1_index = self
|
||||||
todo!()
|
.read_index(inode.indirect_block_l2, index / self.pointers_per_block)
|
||||||
|
.await?;
|
||||||
|
return self
|
||||||
|
.read_index(l1_index, index % self.pointers_per_block)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
// L3
|
||||||
|
index -= self.pointers_per_block * self.pointers_per_block;
|
||||||
impl Deref for ExtendedSuperblock {
|
if index < self.pointers_per_block * self.pointers_per_block * self.pointers_per_block {
|
||||||
type Target = Superblock;
|
let l2_pointer_index = index / self.pointers_per_block;
|
||||||
|
let l2_index = self
|
||||||
fn deref(&self) -> &Self::Target {
|
.read_index(
|
||||||
&self.base
|
inode.indirect_block_l3,
|
||||||
}
|
l2_pointer_index / self.pointers_per_block,
|
||||||
}
|
)
|
||||||
|
.await?;
|
||||||
impl DerefMut for ExtendedSuperblock {
|
let l1_index = self
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
.read_index(l2_index, l2_pointer_index % self.pointers_per_block)
|
||||||
&mut self.base
|
.await?;
|
||||||
}
|
return self
|
||||||
}
|
.read_index(l1_index, index % self.pointers_per_block)
|
||||||
|
.await;
|
||||||
impl Inode {
|
}
|
||||||
pub fn blocks(&self, fs: &Ext2Fs) -> usize {
|
|
||||||
(self.size_lower as usize + fs.block_size - 1) / fs.block_size
|
log::error!("Invalid inode block index (over L3 indirect)");
|
||||||
|
Err(Error::InvalidFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,8 @@ impl BlockCache {
|
|||||||
.try_get_or_insert_with_async(address, || self.fetch_block(address))
|
.try_get_or_insert_with_async(address, || self.fetch_block(address))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if evicted.is_some() {
|
if let Some((address, block)) = evicted {
|
||||||
todo!()
|
self.evict_block(address, block).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user