use alloc::vec::Vec;
use crate::{
block_read::BlockRead,
bmbt::{self, Extent},
error::{Error, Result},
inode::Dinode,
superblock::Superblock,
};
pub(crate) fn read_into<R: BlockRead>(
reader: &mut R,
sb: &Superblock,
inode: &Dinode,
offset: u64,
buf: &mut [u8],
) -> Result<usize> {
let extents = bmbt::read_extents(reader, sb, inode)?;
read_into_with_extents(reader, sb, &extents, inode.size, offset, buf)
}
pub(crate) fn read_into_with_extents<R: BlockRead>(
reader: &mut R,
sb: &Superblock,
extents: &[Extent],
file_size: u64,
offset: u64,
buf: &mut [u8],
) -> Result<usize> {
let end = offset.saturating_add(buf.len() as u64).min(file_size);
if offset >= end {
return Ok(0);
}
let want = (end - offset) as usize;
let out = &mut buf[..want];
out.fill(0);
let bs = u64::from(sb.blocksize);
for ext in extents {
if ext.unwritten {
continue;
}
let ext_start = ext.startoff.saturating_mul(bs);
let ext_end = ext_start.saturating_add(ext.blockcount.saturating_mul(bs));
let lo = offset.max(ext_start);
let hi = end.min(ext_end);
if lo >= hi {
continue;
}
let phys = sb
.fsblock_byte_offset(ext.startblock)
.saturating_add(lo - ext_start);
let dst_lo = (lo - offset) as usize;
let dst_hi = (hi - offset) as usize;
reader
.read_at(phys, &mut out[dst_lo..dst_hi])
.map_err(|_| Error::Io {
token: "io_file",
offset: phys,
})?;
}
Ok(want)
}
pub(crate) fn extents_of<R: BlockRead>(
reader: &mut R,
sb: &Superblock,
inode: &Dinode,
) -> Result<Vec<Extent>> {
bmbt::read_extents(reader, sb, inode)
}