Skip to main content

dope_core/io/fs/
open.rs

1use dope_sys::io::file::{Mode, Open};
2use o3::alloc;
3
4use crate::io::fs::{File, path};
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum Error {
8    Path(path::Error),
9    Allocation(alloc::Error),
10    System(crate::Errno),
11    Directory(crate::Errno),
12}
13
14impl From<path::CopyError> for Error {
15    fn from(error: path::CopyError) -> Self {
16        match error {
17            path::CopyError::Nul { position } => Self::Path(path::Error::Nul { position }),
18            path::CopyError::Allocation(error) => Self::Allocation(error),
19        }
20    }
21}
22
23const _: () = assert!(size_of::<Error>() == 4 * size_of::<usize>());
24
25/// Opening policy independent of the selected asynchronous backend.
26#[derive(Clone, Copy, Debug)]
27pub struct Options {
28    flags: Open,
29    mode: Mode,
30}
31
32#[derive(Clone, Copy, Debug)]
33pub enum Access {
34    Read,
35    Write,
36    ReadWrite,
37    Directory,
38}
39
40#[derive(Clone, Copy, Debug)]
41pub enum Creation {
42    Existing,
43    Create,
44    Exclusive,
45}
46
47impl Options {
48    pub const fn new(access: Access) -> Self {
49        let flags = match access {
50            Access::Read => Open::READ,
51            Access::Write => Open::WRITE,
52            Access::ReadWrite => Open::READ_WRITE,
53            Access::Directory => Open::DIRECTORY,
54        };
55        Self {
56            flags: flags.union(Open::CLOSE_ON_EXEC),
57            mode: Mode::new(0o666),
58        }
59    }
60
61    pub const fn creation(mut self, creation: Creation) -> Self {
62        let flags = match creation {
63            Creation::Existing => Open::NONE,
64            Creation::Create => Open::CREATE,
65            Creation::Exclusive => Open::CREATE.union(Open::EXCLUSIVE),
66        };
67        self.flags = self
68            .flags
69            .difference(Open::CREATE.union(Open::EXCLUSIVE))
70            .union(flags);
71        self
72    }
73
74    pub const fn nofollow(mut self) -> Self {
75        self.flags = self.flags.union(Open::NO_FOLLOW);
76        self
77    }
78
79    pub const fn nonblock(mut self) -> Self {
80        self.flags = self.flags.union(Open::NONBLOCK);
81        self
82    }
83
84    pub const fn truncate(mut self) -> Self {
85        self.flags = self.flags.union(Open::TRUNCATE);
86        self
87    }
88
89    pub const fn mode(mut self, mode: Mode) -> Self {
90        self.mode = mode;
91        self
92    }
93
94    pub(super) const fn lower(self) -> (Open, Mode) {
95        let mode = if self.flags.contains(Open::CREATE) {
96            self.mode
97        } else {
98            Mode::new(0)
99        };
100        (self.flags, mode)
101    }
102
103    pub fn open(self, path: &std::ffi::CStr) -> Result<File, crate::Errno> {
104        use dope_sys::io::file::File as _;
105
106        let (flags, mode) = self.lower();
107        crate::Backend::open::<dope_sys::Errno>(path, flags, mode).map(File::from)
108    }
109}