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},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
io::{DirectoryEntry, FileMode, FileType, GroupId, UserId},
|
||||
io::{DirectoryEntry, FileType},
|
||||
util::FixedString,
|
||||
};
|
||||
|
||||
@ -158,11 +158,7 @@ impl CommonImpl for DirectoryNode {
|
||||
}
|
||||
|
||||
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
||||
Ok(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) },
|
||||
})
|
||||
Ok(self.inode.metadata())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use libk::{
|
||||
error::Error,
|
||||
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};
|
||||
|
||||
@ -55,11 +55,7 @@ impl RegularNode {
|
||||
|
||||
impl CommonImpl for RegularNode {
|
||||
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
||||
Ok(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) },
|
||||
})
|
||||
Ok(self.inode.metadata())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
|
@ -2,10 +2,8 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc, vec};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use alloc::sync::Arc;
|
||||
use bytemuck::Zeroable;
|
||||
use dir::DirectoryNode;
|
||||
use file::RegularNode;
|
||||
use libk::{
|
||||
@ -19,14 +17,15 @@ use libk::{
|
||||
},
|
||||
};
|
||||
use libk_util::OneTimeInit;
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
mod data;
|
||||
pub mod dir;
|
||||
pub mod file;
|
||||
|
||||
pub const SUPERBLOCK_OFFSET: u64 = 1024;
|
||||
pub const EXT2_SIGNATURE: u16 = 0xEF53;
|
||||
pub const BGDT_BLOCK_NUMBER: u32 = 2;
|
||||
pub use data::{
|
||||
BlockGroupDescriptor, BlockGroupDescriptorTable, Dirent, ExtendedSuperblock, Inode, Superblock,
|
||||
};
|
||||
use yggdrasil_abi::io::FileType;
|
||||
|
||||
pub struct Ext2Fs {
|
||||
cache: BlockCache,
|
||||
@ -37,169 +36,11 @@ pub struct Ext2Fs {
|
||||
inode_size: usize,
|
||||
block_size: usize,
|
||||
inodes_per_block: usize,
|
||||
pointers_per_block: usize,
|
||||
|
||||
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 {
|
||||
pub async fn create(device: &'static dyn BlockDevice) -> Result<NodeRef, Error> {
|
||||
let fs = Self::create_fs(device).await.map_err(|e| {
|
||||
@ -207,7 +48,7 @@ impl Ext2Fs {
|
||||
e
|
||||
})?;
|
||||
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());
|
||||
|
||||
@ -217,20 +58,23 @@ impl Ext2Fs {
|
||||
async fn create_fs(device: &'static dyn BlockDevice) -> Result<Self, Error> {
|
||||
let mut superblock = ExtendedSuperblock::zeroed();
|
||||
device
|
||||
.read(SUPERBLOCK_OFFSET, bytemuck::bytes_of_mut(&mut superblock))
|
||||
.read(
|
||||
data::SUPERBLOCK_OFFSET,
|
||||
bytemuck::bytes_of_mut(&mut superblock),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if superblock.signature != EXT2_SIGNATURE {
|
||||
if superblock.signature != data::EXT2_SIGNATURE {
|
||||
log::warn!(
|
||||
"Invalid ext2 signature: expected {:#x}, got {:#x}",
|
||||
EXT2_SIGNATURE,
|
||||
data::EXT2_SIGNATURE,
|
||||
superblock.signature
|
||||
);
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let bgdt_offset = 1;
|
||||
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)
|
||||
/ superblock.block_group_block_count) as usize;
|
||||
@ -254,7 +98,7 @@ impl Ext2Fs {
|
||||
bgdt_entry_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
|
||||
.read_exact(
|
||||
disk_offset,
|
||||
@ -269,9 +113,10 @@ impl Ext2Fs {
|
||||
block_size,
|
||||
inode_size: superblock.inode_size(),
|
||||
inodes_per_block: block_size / superblock.inode_size(),
|
||||
pointers_per_block: block_size / size_of::<u32>(),
|
||||
|
||||
// 128 × 8 cache
|
||||
cache: BlockCache::with_capacity(device, block_size, 128),
|
||||
cache: BlockCache::with_capacity(device, block_size, 512),
|
||||
superblock,
|
||||
bgdt,
|
||||
|
||||
@ -280,12 +125,10 @@ impl Ext2Fs {
|
||||
}
|
||||
|
||||
fn create_node(self: &Arc<Self>, inode: Inode, ino: u32) -> Result<NodeRef, Error> {
|
||||
match inode.mode & 0xF000 {
|
||||
// Directory
|
||||
0x4000 => Ok(DirectoryNode::new(self.clone(), inode, ino)),
|
||||
// Regular file
|
||||
0x8000 => Ok(RegularNode::new(self.clone(), inode, ino)),
|
||||
_ => todo!("Unknown file type: {:#x}", inode.mode),
|
||||
match inode.mode.node_type() {
|
||||
Some(FileType::Directory) => Ok(DirectoryNode::new(self.clone(), inode, ino)),
|
||||
Some(FileType::File) => Ok(RegularNode::new(self.clone(), inode, ino)),
|
||||
e => todo!("Unhandled inode type: {:?} ({:#x?})", e, inode.mode),
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,49 +168,58 @@ impl Ext2Fs {
|
||||
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> {
|
||||
if index < 12 {
|
||||
Ok(inode.direct_blocks[index as usize])
|
||||
} else {
|
||||
todo!()
|
||||
let mut index = index as usize;
|
||||
// L0
|
||||
if index < inode.direct_blocks.len() {
|
||||
return Ok(inode.direct_blocks[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendedSuperblock {
|
||||
pub fn inode_size(&self) -> usize {
|
||||
if self.base.version_major != 0 {
|
||||
self.inode_struct_size as _
|
||||
} else {
|
||||
128
|
||||
// L1
|
||||
index -= inode.direct_blocks.len();
|
||||
if index < self.pointers_per_block {
|
||||
return self.read_index(inode.indirect_block_l1, index).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn required_features(&self) -> u32 {
|
||||
if self.base.version_major != 0 {
|
||||
self.required_features
|
||||
} else {
|
||||
todo!()
|
||||
// L2
|
||||
index -= self.pointers_per_block;
|
||||
if index < self.pointers_per_block * self.pointers_per_block {
|
||||
let l1_index = self
|
||||
.read_index(inode.indirect_block_l2, index / self.pointers_per_block)
|
||||
.await?;
|
||||
return self
|
||||
.read_index(l1_index, index % self.pointers_per_block)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// L3
|
||||
index -= self.pointers_per_block * self.pointers_per_block;
|
||||
if index < self.pointers_per_block * self.pointers_per_block * self.pointers_per_block {
|
||||
let l2_pointer_index = index / self.pointers_per_block;
|
||||
let l2_index = self
|
||||
.read_index(
|
||||
inode.indirect_block_l3,
|
||||
l2_pointer_index / self.pointers_per_block,
|
||||
)
|
||||
.await?;
|
||||
let l1_index = self
|
||||
.read_index(l2_index, l2_pointer_index % self.pointers_per_block)
|
||||
.await?;
|
||||
return self
|
||||
.read_index(l1_index, index % self.pointers_per_block)
|
||||
.await;
|
||||
}
|
||||
|
||||
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))
|
||||
.await?;
|
||||
|
||||
if evicted.is_some() {
|
||||
todo!()
|
||||
if let Some((address, block)) = evicted {
|
||||
self.evict_block(address, block).await;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
|
Loading…
x
Reference in New Issue
Block a user