diff --git a/kernel/driver/fs/ext2/src/access.rs b/kernel/driver/fs/ext2/src/access.rs index e07dbd56..e606d857 100644 --- a/kernel/driver/fs/ext2/src/access.rs +++ b/kernel/driver/fs/ext2/src/access.rs @@ -2,6 +2,22 @@ use libk::error::Error; use crate::{BlockGroupDescriptor, Ext2Fs, ExtendedSuperblock, Inode}; +pub enum InodeBlock<'a> { + Hole, + Data(&'a [u8]), +} + +impl InodeBlock<'_> { + pub fn copy_to(&self, offset: usize, destination: &mut [u8]) { + match self { + Self::Hole => destination.fill(0), + Self::Data(data) => { + destination.copy_from_slice(&data[offset..offset + destination.len()]) + } + } + } +} + impl Ext2Fs { pub async fn with_block Result>( &self, @@ -47,14 +63,19 @@ impl Ext2Fs { .await } - pub async fn with_inode_block Result>( + pub async fn with_inode_block Result>( &self, inode: &Inode, block: u32, mapper: F, ) -> Result { let block_index = self.inode_block_index(inode, block).await?; - self.with_block(block_index, mapper).await + if block_index == 0 { + mapper(InodeBlock::Hole) + } else { + self.with_block(block_index, |block| mapper(InodeBlock::Data(block))) + .await + } } pub async fn with_inode_block_mut Result>( diff --git a/kernel/driver/fs/ext2/src/dir/walk.rs b/kernel/driver/fs/ext2/src/dir/walk.rs index 0a94cc4f..1dd5c646 100644 --- a/kernel/driver/fs/ext2/src/dir/walk.rs +++ b/kernel/driver/fs/ext2/src/dir/walk.rs @@ -9,7 +9,7 @@ use yggdrasil_abi::{ util::FixedString, }; -use crate::{data::FsRequiredFeatures, Dirent, Ext2Fs}; +use crate::{access::InodeBlock, data::FsRequiredFeatures, Dirent, Ext2Fs}; use super::DirentName; @@ -110,8 +110,17 @@ impl<'a, D: DerefMut + 'a> Record<'a, D> { } impl<'a> DirentIter<'a> { - pub fn new(fs: &'a Ext2Fs, block: &'a [u8], offset: usize) -> Self { - Self { fs, block, offset } + pub fn new(fs: &'a Ext2Fs, block: InodeBlock<'a>, offset: usize) -> Self { + let data = if let InodeBlock::Data(data) = block { + data + } else { + &[] + }; + Self { + fs, + block: data, + offset, + } } pub fn offset(&self) -> usize { diff --git a/kernel/driver/fs/ext2/src/inode/cache.rs b/kernel/driver/fs/ext2/src/inode/cache.rs index 58a290f5..6a048a32 100644 --- a/kernel/driver/fs/ext2/src/inode/cache.rs +++ b/kernel/driver/fs/ext2/src/inode/cache.rs @@ -15,7 +15,8 @@ use yggdrasil_abi::{ }; use crate::{ - data::InodeMode, dir::DirectoryNode, file::RegularNode, symlink::SymlinkNode, Ext2Fs, Inode, + access::InodeBlock, data::InodeMode, dir::DirectoryNode, file::RegularNode, + symlink::SymlinkNode, Ext2Fs, Inode, }; pub struct InodeHolder { @@ -103,7 +104,7 @@ impl InodeAccess { result } - pub async fn map_blocks Result, Error>>( + pub async fn map_blocks Result, Error>>( &self, mapper: F, ) -> Result, Error> { diff --git a/kernel/driver/fs/ext2/src/lib.rs b/kernel/driver/fs/ext2/src/lib.rs index d7b2e239..ac838f90 100644 --- a/kernel/driver/fs/ext2/src/lib.rs +++ b/kernel/driver/fs/ext2/src/lib.rs @@ -390,12 +390,17 @@ impl Ext2Fs { let block_offset = (pos % self.block_size as u64) as usize; let amount = remaining.min(self.block_size - block_offset); - self.with_inode_block(inode, block_index as u32, |block| { - buffer[offset..offset + amount] - .copy_from_slice(&block[block_offset..block_offset + amount]); - Ok(()) - }) - .await?; + let block = self.inode_block_index(inode, block_index as u32).await?; + if block == 0 { + buffer[offset..offset + amount].fill(0); + } else { + self.with_block(block, |block| { + buffer[offset..offset + amount] + .copy_from_slice(&block[block_offset..block_offset + amount]); + Ok(()) + }) + .await?; + } pos += amount as u64; offset += amount; diff --git a/kernel/driver/fs/ext2/src/symlink.rs b/kernel/driver/fs/ext2/src/symlink.rs index a7bc5c60..c50510b2 100644 --- a/kernel/driver/fs/ext2/src/symlink.rs +++ b/kernel/driver/fs/ext2/src/symlink.rs @@ -54,8 +54,9 @@ impl SymlinkNode { } else { self.fs .with_inode_block(inode, 0, |block| { - write.extend_from_slice(&block[..len]); - buf[..len].copy_from_slice(&block[..len]); + write.resize(len, 0); + block.copy_to(0, &mut write[..]); + block.copy_to(0, &mut buf[..len]); Ok(()) }) .await?;