105 lines
2.9 KiB
Rust
105 lines
2.9 KiB
Rust
//! File structs
|
|
|
|
use crate::{
|
|
event,
|
|
scheme::{self, SchemeId},
|
|
sync::{CleanLockToken, RwLock, L6},
|
|
syscall::error::Result,
|
|
};
|
|
use alloc::sync::Arc;
|
|
use syscall::{schemev2::NewFdFlags, RwFlags, O_APPEND, O_NONBLOCK};
|
|
|
|
pub type LockedFileDescription = RwLock<L6, FileDescription>;
|
|
|
|
/// A file description
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct FileDescription {
|
|
/// The current file offset (seek)
|
|
pub offset: u64,
|
|
/// The scheme that this file refers to
|
|
pub scheme: SchemeId,
|
|
/// The number the scheme uses to refer to this file
|
|
pub number: usize,
|
|
/// The flags passed to open or fcntl(SETFL)
|
|
pub flags: u32,
|
|
pub internal_flags: InternalFlags,
|
|
}
|
|
bitflags! {
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct InternalFlags: u32 {
|
|
const POSITIONED = 1 << 0;
|
|
const NOTIFY_ON_NEXT_DETACH = 1 << 1;
|
|
}
|
|
}
|
|
impl FileDescription {
|
|
pub fn rw_flags(&self, rw: RwFlags) -> u32 {
|
|
let mut ret = self.flags & !(O_NONBLOCK | O_APPEND) as u32;
|
|
if rw.contains(RwFlags::APPEND) {
|
|
ret |= O_APPEND as u32;
|
|
}
|
|
if rw.contains(RwFlags::NONBLOCK) {
|
|
ret |= O_NONBLOCK as u32;
|
|
}
|
|
ret
|
|
}
|
|
}
|
|
impl InternalFlags {
|
|
pub fn from_extra0(fl: u8) -> Option<Self> {
|
|
Some(
|
|
NewFdFlags::from_bits(fl)?
|
|
.iter()
|
|
.map(|fd| {
|
|
if fd == NewFdFlags::POSITIONED {
|
|
Self::POSITIONED
|
|
} else {
|
|
Self::empty()
|
|
}
|
|
})
|
|
.collect(),
|
|
)
|
|
}
|
|
}
|
|
|
|
/// A file descriptor
|
|
#[derive(Clone, Debug)]
|
|
#[must_use = "File descriptors must be closed"]
|
|
pub struct FileDescriptor {
|
|
/// Corresponding file description
|
|
pub description: Arc<LockedFileDescription>,
|
|
/// Cloexec flag
|
|
pub cloexec: bool,
|
|
}
|
|
|
|
impl FileDescription {
|
|
/// Try closing a file, although at this point the description will be destroyed anyway, if
|
|
/// doing so fails.
|
|
pub fn try_close(self, token: &mut CleanLockToken) -> Result<()> {
|
|
event::unregister_file(self.scheme, self.number, token);
|
|
|
|
let scheme = scheme::get_scheme(token.token(), self.scheme)?;
|
|
|
|
scheme.close(self.number, token)
|
|
}
|
|
}
|
|
|
|
impl FileDescriptor {
|
|
pub fn close(self, token: &mut CleanLockToken) -> Result<()> {
|
|
{
|
|
let (scheme_id, number, internal_flags) = {
|
|
let desc = self.description.read(token.token());
|
|
(desc.scheme, desc.number, desc.internal_flags)
|
|
};
|
|
if internal_flags.contains(InternalFlags::NOTIFY_ON_NEXT_DETACH) {
|
|
let scheme = scheme::get_scheme(token.token(), scheme_id)?;
|
|
scheme.detach(number, token)?;
|
|
}
|
|
}
|
|
|
|
if let Ok(file) = Arc::try_unwrap(self.description).map(RwLock::into_inner) {
|
|
file.try_close(token)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|