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};
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<T, F: FnOnce(&[u8]) -> Result<T, Error>>(
&self,
@ -47,14 +63,19 @@ impl Ext2Fs {
.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,
inode: &Inode,
block: u32,
mapper: F,
) -> Result<T, Error> {
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>>(

View File

@ -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<Target = [u8]> + '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 {

View File

@ -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<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,
mapper: F,
) -> Result<Option<T>, Error> {

View File

@ -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| {
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;

View File

@ -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?;