compio-fs 0.12.0-rc.1

Filesystem IO for compio
Documentation
use std::{io, os::fd::AsFd, path::Path};

use compio_buf::{IntoInner, buf_try};
#[cfg(dirfd)]
use compio_driver::ToSharedFd;
use compio_driver::op::{CurrentDir, Mode, OFlags, OpenFile};
use rustix::io::{Errno, Result};

use crate::{File, path_string};

#[derive(Clone, Debug)]
pub struct OpenOptions {
    read: bool,
    write: bool,
    truncate: bool,
    create: bool,
    create_new: bool,
    custom_flags: OFlags,
    mode: Mode,
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            read: false,
            write: false,
            truncate: false,
            create: false,
            create_new: false,
            custom_flags: OFlags::empty(),
            mode: Mode::from_bits_retain(0o666),
        }
    }

    pub fn read(&mut self, read: bool) {
        self.read = read;
    }

    pub fn write(&mut self, write: bool) {
        self.write = write;
    }

    pub fn truncate(&mut self, truncate: bool) {
        self.truncate = truncate;
    }

    pub fn create(&mut self, create: bool) {
        self.create = create;
    }

    pub fn create_new(&mut self, create_new: bool) {
        self.create_new = create_new;
    }

    pub fn custom_flags(&mut self, flags: i32) {
        self.custom_flags = OFlags::from_bits_retain(flags as _).difference(OFlags::ACCMODE);
    }

    pub fn mode(&mut self, mode: u32) {
        self.mode = Mode::from_bits_retain(mode as _);
    }

    fn get_access_mode(&self) -> Result<OFlags> {
        match (self.read, self.write) {
            (true, false) => Ok(OFlags::RDONLY),
            (false, true) => Ok(OFlags::WRONLY),
            (true, true) => Ok(OFlags::RDWR),
            (false, false) => Err(Errno::INVAL),
        }
    }

    fn get_creation_mode(&self) -> Result<OFlags> {
        if !self.write && (self.truncate || self.create || self.create_new) {
            return Err(Errno::INVAL);
        }

        Ok(match (self.create, self.truncate, self.create_new) {
            (false, false, false) => OFlags::empty(),
            (true, false, false) => OFlags::CREATE,
            (false, true, false) => OFlags::TRUNC,
            (true, true, false) => OFlags::CREATE | OFlags::TRUNC,
            (_, _, true) => OFlags::CREATE | OFlags::EXCL,
        })
    }

    async fn open_impl(&self, dir: impl AsFd + 'static, p: impl AsRef<Path>) -> io::Result<File> {
        let flags = OFlags::CLOEXEC
            | self.get_access_mode()?
            | self.get_creation_mode()?
            | self.custom_flags;
        let p = path_string(p)?;
        let op = OpenFile::new(dir, p, flags, self.mode);
        let (_, op) = buf_try!(@try compio_runtime::submit(op).await);
        File::from_std(op.into_inner().into())
    }

    pub async fn open(&self, p: impl AsRef<Path>) -> io::Result<File> {
        self.open_impl(CurrentDir, p).await
    }

    #[cfg(dirfd)]
    pub async fn open_at(&self, dir: &File, path: impl AsRef<Path>) -> io::Result<File> {
        self.open_impl(dir.to_shared_fd(), path).await
    }
}