use std::{cmp, io::Read};
use bytes::Bytes;
use crate::{EroFS, types::Inode};
#[derive(Debug)]
pub struct File {
inode: Inode,
erofs: EroFS,
offset: usize,
buf: Option<Bytes>,
}
impl File {
pub(crate) fn new(inode: Inode, erofs: EroFS) -> Self {
Self {
inode,
erofs,
offset: 0,
buf: None,
}
}
pub fn size(&self) -> usize {
self.inode.data_size()
}
}
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.offset >= self.inode.data_size() {
return Ok(0);
}
if let Some(ref data) = self.buf {
let offset = self.offset % self.erofs.block_size();
let n = cmp::min(buf.len(), data.len().saturating_sub(offset));
buf[..n].copy_from_slice(&data[offset..offset + n]);
self.offset += n;
return Ok(n);
}
let block_size = self.erofs.block_size();
let cur_offset = self.offset;
let block = self
.erofs
.get_inode_block(&self.inode, cur_offset)
.map_err(|e| std::io::Error::other(format!("read block failed: {}", e)))?;
if buf.len() >= block.len() {
let n = block.len();
buf[..n].copy_from_slice(block);
self.offset += n;
Ok(n)
} else {
let offset = cur_offset % block_size;
let n = cmp::min(buf.len(), block.len().saturating_sub(offset));
buf[..n].copy_from_slice(&block[offset..offset + n]);
self.buf = Some(Bytes::copy_from_slice(block));
self.offset += n;
Ok(n)
}
}
}