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#[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}