yggdrasil/lib/vfs/src/file/regular.rs

86 lines
2.5 KiB
Rust
Raw Normal View History

2023-12-02 20:28:43 +02:00
use alloc::boxed::Box;
use core::{any::Any, cell::Cell};
use yggdrasil_abi::{error::Error, io::SeekFrom};
use crate::node::NodeRef;
pub struct RegularFile {
pub(super) node: NodeRef,
pub(super) read: bool,
pub(super) write: bool,
pub(super) instance_data: Option<Box<dyn Any>>,
pub(super) position: Cell<u64>,
}
impl RegularFile {
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if !self.read {
return Err(Error::InvalidFile);
}
let reg = self.node.as_regular()?;
let pos = self.position.get();
let count = reg.read(&self.node, self.instance_data.as_ref(), pos, buf)?;
self.position.set(pos + count as u64);
Ok(count)
}
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
if !self.write {
return Err(Error::InvalidFile);
}
let reg = self.node.as_regular()?;
let pos = self.position.get();
let count = reg.write(&self.node, self.instance_data.as_ref(), pos, buf)?;
self.position.set(pos + count as u64);
Ok(count)
}
// TODO should seek beyond the end of a read-only file be allowed?
pub fn seek(&self, from: SeekFrom) -> Result<u64, Error> {
let pos = self.position.get();
let newpos = match from {
SeekFrom::Current(off) => {
let newpos = i64::try_from(pos).unwrap() + off;
if newpos < 0 {
return Err(Error::InvalidArgument);
}
newpos as u64
}
SeekFrom::Start(pos) => pos,
SeekFrom::End(off) => {
let reg = self.node.as_regular()?;
let size = i64::try_from(reg.size(&self.node)?).unwrap();
let newpos = size + off;
if newpos < 0 {
return Err(Error::InvalidArgument);
}
newpos as u64
}
};
self.position.set(newpos);
Ok(newpos)
}
}
impl Drop for RegularFile {
fn drop(&mut self) {
let reg = match self.node.as_regular() {
Ok(reg) => reg,
Err(err) => {
log::warn!(
"RegularFile::Drop: self.node.as_regular() failed: {:?}",
err
);
return;
}
};
if let Err(err) = reg.close(&self.node, self.instance_data.as_ref()) {
log::warn!("RegularFile::Drop: close() failed: {:?}", err);
}
}
}