86 lines
2.5 KiB
Rust
86 lines
2.5 KiB
Rust
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|