ext2: support reading from files with holes

This commit is contained in:
Mark Poliakov 2025-02-24 10:58:44 +02:00
parent dcc5d56750
commit a1ccdf7e76
5 changed files with 52 additions and 15 deletions

View File

@ -2,6 +2,22 @@ use libk::error::Error;
use crate::{BlockGroupDescriptor, Ext2Fs, ExtendedSuperblock, Inode}; 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 { impl Ext2Fs {
pub async fn with_block<T, F: FnOnce(&[u8]) -> Result<T, Error>>( pub async fn with_block<T, F: FnOnce(&[u8]) -> Result<T, Error>>(
&self, &self,
@ -47,14 +63,19 @@ impl Ext2Fs {
.await .await
} }
pub async fn with_inode_block<T, F: FnOnce(&[u8]) -> Result<T, Error>>( pub async fn with_inode_block<T, F: FnOnce(InodeBlock) -> Result<T, Error>>(
&self, &self,
inode: &Inode, inode: &Inode,
block: u32, block: u32,
mapper: F, mapper: F,
) -> Result<T, Error> { ) -> Result<T, Error> {
let block_index = self.inode_block_index(inode, block).await?; 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<T, F: FnOnce(&mut [u8]) -> Result<T, Error>>( pub async fn with_inode_block_mut<T, F: FnOnce(&mut [u8]) -> Result<T, Error>>(

View File

@ -9,7 +9,7 @@ use yggdrasil_abi::{
util::FixedString, util::FixedString,
}; };
use crate::{data::FsRequiredFeatures, Dirent, Ext2Fs}; use crate::{access::InodeBlock, data::FsRequiredFeatures, Dirent, Ext2Fs};
use super::DirentName; use super::DirentName;
@ -110,8 +110,17 @@ impl<'a, D: DerefMut<Target = [u8]> + 'a> Record<'a, D> {
} }
impl<'a> DirentIter<'a> { impl<'a> DirentIter<'a> {
pub fn new(fs: &'a Ext2Fs, block: &'a [u8], offset: usize) -> Self { pub fn new(fs: &'a Ext2Fs, block: InodeBlock<'a>, offset: usize) -> Self {
Self { fs, block, offset } let data = if let InodeBlock::Data(data) = block {
data
} else {
&[]
};
Self {
fs,
block: data,
offset,
}
} }
pub fn offset(&self) -> usize { pub fn offset(&self) -> usize {

View File

@ -15,7 +15,8 @@ use yggdrasil_abi::{
}; };
use crate::{ 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 { pub struct InodeHolder {
@ -103,7 +104,7 @@ impl InodeAccess {
result result
} }
pub async fn map_blocks<T, F: Fn(&Inode, usize, &[u8]) -> Result<Option<T>, Error>>( pub async fn map_blocks<T, F: Fn(&Inode, usize, InodeBlock) -> Result<Option<T>, Error>>(
&self, &self,
mapper: F, mapper: F,
) -> Result<Option<T>, Error> { ) -> Result<Option<T>, Error> {

View File

@ -390,12 +390,17 @@ impl Ext2Fs {
let block_offset = (pos % self.block_size as u64) as usize; let block_offset = (pos % self.block_size as u64) as usize;
let amount = remaining.min(self.block_size - block_offset); let amount = remaining.min(self.block_size - block_offset);
self.with_inode_block(inode, block_index as u32, |block| { let block = self.inode_block_index(inode, block_index as u32).await?;
buffer[offset..offset + amount] if block == 0 {
.copy_from_slice(&block[block_offset..block_offset + amount]); buffer[offset..offset + amount].fill(0);
Ok(()) } else {
}) self.with_block(block, |block| {
.await?; buffer[offset..offset + amount]
.copy_from_slice(&block[block_offset..block_offset + amount]);
Ok(())
})
.await?;
}
pos += amount as u64; pos += amount as u64;
offset += amount; offset += amount;

View File

@ -54,8 +54,9 @@ impl SymlinkNode {
} else { } else {
self.fs self.fs
.with_inode_block(inode, 0, |block| { .with_inode_block(inode, 0, |block| {
write.extend_from_slice(&block[..len]); write.resize(len, 0);
buf[..len].copy_from_slice(&block[..len]); block.copy_to(0, &mut write[..]);
block.copy_to(0, &mut buf[..len]);
Ok(()) Ok(())
}) })
.await?; .await?;