asterinas/kernel/src/fs/procfs/template/file.rs

122 lines
3.1 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
use core::time::Duration;
use inherit_methods_macro::inherit_methods;
use super::{Common, ProcFs};
use crate::{
fs::{
notify::FsEventPublisher,
utils::{
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
},
},
prelude::*,
process::{Gid, Uid},
};
pub struct ProcFile<F: FileOps> {
inner: F,
common: Common,
}
impl<F: FileOps> ProcFile<F> {
pub(super) fn new(
file: F,
fs: Weak<dyn FileSystem>,
is_volatile: bool,
mode: InodeMode,
) -> Arc<Self> {
let common = {
let arc_fs = fs.upgrade().unwrap();
let procfs = arc_fs.downcast_ref::<ProcFs>().unwrap();
let metadata = Metadata::new_file(procfs.alloc_id(), mode, super::BLOCK_SIZE);
Common::new(metadata, fs, is_volatile)
};
Arc::new(Self {
inner: file,
common,
})
}
pub fn inner(&self) -> &F {
&self.inner
}
}
impl<F: FileOps + 'static> InodeIo for ProcFile<F> {
fn read_at(
&self,
offset: usize,
writer: &mut VmWriter,
_status_flags: StatusFlags,
) -> Result<usize> {
self.inner.read_at(offset, writer)
}
fn write_at(
&self,
offset: usize,
reader: &mut VmReader,
_status_flags: StatusFlags,
) -> Result<usize> {
self.inner.write_at(offset, reader)
}
}
#[inherit_methods(from = "self.common")]
impl<F: FileOps + 'static> Inode for ProcFile<F> {
fn size(&self) -> usize;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn ino(&self) -> u64;
fn mode(&self) -> Result<InodeMode>;
fn set_mode(&self, mode: InodeMode) -> Result<()>;
fn owner(&self) -> Result<Uid>;
fn set_owner(&self, uid: Uid) -> Result<()>;
fn group(&self) -> Result<Gid>;
fn set_group(&self, gid: Gid) -> Result<()>;
fn atime(&self) -> Duration;
fn set_atime(&self, time: Duration);
fn mtime(&self) -> Duration;
fn set_mtime(&self, time: Duration);
fn ctime(&self) -> Duration;
fn set_ctime(&self, time: Duration);
fn fs(&self) -> Arc<dyn FileSystem>;
fn resize(&self, _new_size: usize) -> Result<()> {
// Resizing files under `/proc` will succeed, but will do nothing.
Ok(())
}
fn type_(&self) -> InodeType {
InodeType::File
}
fn read_link(&self) -> Result<SymbolicLink> {
Err(Error::new(Errno::EINVAL))
}
fn write_link(&self, _target: &str) -> Result<()> {
Err(Error::new(Errno::EINVAL))
}
fn is_dentry_cacheable(&self) -> bool {
!self.common.is_volatile()
}
fn seek_end(&self) -> Option<usize> {
// Seeking regular files under `/proc` with `SEEK_END` will fail.
None
}
}
pub trait FileOps: Sync + Send {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize>;
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EPERM, "the file is not writable");
}
}