emerald_kernel_user_link/
file.rs

1use core::{ffi::CStr, ops};
2
3/// A blocking flag when dealing with files
4/// When using [`crate::syscalls::SYS_OPEN`], Bit 0 of `flags` argument can be:
5/// 0 - non-blocking
6/// 1 - line buffered
7///
8/// In order to use `Block` mode, you need to issue `syscall_blocking_mode`
9///  with the whole range of blocking modes available for usage
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
11pub enum BlockingMode {
12    #[default]
13    None,
14    Line,
15    Block(u32),
16}
17
18impl BlockingMode {
19    pub fn from_flags(flags: u64) -> Self {
20        match flags & 1 {
21            0 => BlockingMode::None,
22            1 => BlockingMode::Line,
23            _ => unreachable!(),
24        }
25    }
26
27    pub fn to_u64(&self) -> u64 {
28        match self {
29            BlockingMode::None => 0,
30            BlockingMode::Line => 1,
31            BlockingMode::Block(num) => (*num as u64) << 2 | 3,
32        }
33    }
34}
35
36impl TryFrom<u64> for BlockingMode {
37    type Error = ();
38
39    fn try_from(value: u64) -> Result<Self, Self::Error> {
40        let mode = value & 3;
41        let rest = value >> 2;
42
43        match mode {
44            0 if rest == 0 => Ok(BlockingMode::None),
45            1 if rest == 0 => Ok(BlockingMode::Line),
46            3 if rest != 0 && rest <= 0xFFFF_FFFF => Ok(BlockingMode::Block(rest as u32)),
47            _ => Err(()),
48        }
49    }
50}
51
52/// Will extract all the information from the flags, will return `None` if the argument
53/// is invalid
54pub fn parse_flags(flags: u64) -> Option<BlockingMode> {
55    let blocking_mode = BlockingMode::from_flags(flags);
56    let flags = flags & !1;
57    // must be 0 at the end
58    if flags == 0 {
59        Some(blocking_mode)
60    } else {
61        None
62    }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
66#[repr(C)]
67pub enum FileType {
68    #[default]
69    File,
70    Directory,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
74#[repr(C)]
75pub struct FileStat {
76    pub size: u64,
77    pub file_type: FileType,
78}
79
80pub const MAX_FILENAME_LEN: usize = 255;
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub struct DirFilename([u8; MAX_FILENAME_LEN + 1]);
84
85impl Default for DirFilename {
86    fn default() -> Self {
87        Self([0; MAX_FILENAME_LEN + 1])
88    }
89}
90
91impl DirFilename {
92    pub fn as_cstr(&self) -> &CStr {
93        CStr::from_bytes_until_nul(&self.0).unwrap()
94    }
95}
96
97impl From<&str> for DirFilename {
98    fn from(s: &str) -> Self {
99        let mut name = [0; MAX_FILENAME_LEN + 1];
100        let bytes = s.as_bytes();
101        assert!(bytes.len() < MAX_FILENAME_LEN);
102        name[..bytes.len()].copy_from_slice(bytes);
103        Self(name)
104    }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
108#[repr(C)]
109pub struct DirEntry {
110    pub stat: FileStat,
111    pub name: DirFilename,
112}
113
114impl DirEntry {
115    pub fn filename_cstr(&self) -> &CStr {
116        self.name.as_cstr()
117    }
118}
119
120#[repr(u8)]
121#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
122#[non_exhaustive]
123pub enum FileMeta {
124    BlockingMode(BlockingMode) = 0,
125    IsTerminal(bool) = 1,
126}
127
128impl FileMeta {
129    pub fn to_u64_meta_id(&self) -> u64 {
130        match self {
131            FileMeta::BlockingMode(_) => 0,
132            FileMeta::IsTerminal(_) => 1,
133        }
134    }
135
136    pub fn inner_u64(&self) -> u64 {
137        match self {
138            FileMeta::BlockingMode(mode) => mode.to_u64(),
139            FileMeta::IsTerminal(is_terminal) => *is_terminal as u64,
140        }
141    }
142}
143
144impl TryFrom<(u64, u64)> for FileMeta {
145    type Error = ();
146
147    fn try_from(value: (u64, u64)) -> Result<Self, Self::Error> {
148        match value.0 {
149            0 => Ok(FileMeta::BlockingMode(BlockingMode::try_from(value.1)?)),
150            1 => Ok(FileMeta::IsTerminal(value.1 != 0)),
151            _ => Err(()),
152        }
153    }
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157#[repr(u8)]
158pub enum SeekWhence {
159    Start = 0,
160    Current = 1,
161    End = 2,
162}
163
164impl TryFrom<u64> for SeekWhence {
165    type Error = ();
166
167    fn try_from(value: u64) -> Result<Self, Self::Error> {
168        match value {
169            0 => Ok(SeekWhence::Start),
170            1 => Ok(SeekWhence::Current),
171            2 => Ok(SeekWhence::End),
172            _ => Err(()),
173        }
174    }
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
178pub struct SeekFrom {
179    pub offset: i64,
180    pub whence: SeekWhence,
181}
182
183impl SeekFrom {
184    pub fn new(offset: i64, whence: SeekWhence) -> Self {
185        Self { offset, whence }
186    }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
190pub struct OpenOptions(u8);
191
192#[allow(dead_code)]
193impl OpenOptions {
194    pub const READ: Self = Self(1 << 0);
195    pub const WRITE: Self = Self(1 << 1);
196    pub const CREATE: Self = Self(1 << 2);
197    pub const CREATE_NEW: Self = Self(1 << 3);
198    pub const TRUNCATE: Self = Self(1 << 4);
199    pub const APPEND: Self = Self(1 << 5);
200
201    pub fn new() -> Self {
202        Self(0)
203    }
204
205    pub fn read(&mut self, read: bool) -> &mut Self {
206        if read {
207            self.0 |= Self::READ.0;
208        } else {
209            self.0 &= !Self::READ.0;
210        }
211        self
212    }
213
214    pub fn write(&mut self, write: bool) -> &mut Self {
215        if write {
216            self.0 |= Self::WRITE.0;
217        } else {
218            self.0 &= !Self::WRITE.0;
219        }
220        self
221    }
222
223    pub fn create(&mut self, create: bool) -> &mut Self {
224        if create {
225            self.0 |= Self::CREATE.0;
226        } else {
227            self.0 &= !Self::CREATE.0;
228        }
229        self
230    }
231
232    pub fn create_new(&mut self, create_new: bool) -> &mut Self {
233        if create_new {
234            self.0 |= Self::CREATE_NEW.0;
235        } else {
236            self.0 &= !Self::CREATE_NEW.0;
237        }
238        self
239    }
240
241    pub fn truncate(&mut self, truncate: bool) -> &mut Self {
242        if truncate {
243            self.0 |= Self::TRUNCATE.0;
244        } else {
245            self.0 &= !Self::TRUNCATE.0;
246        }
247        self
248    }
249
250    pub fn append(&mut self, append: bool) -> &mut Self {
251        if append {
252            self.0 |= Self::APPEND.0;
253        } else {
254            self.0 &= !Self::APPEND.0;
255        }
256        self
257    }
258
259    pub fn is_read(&self) -> bool {
260        self.0 & Self::READ.0 != 0
261    }
262
263    pub fn is_write(&self) -> bool {
264        (self.0 & Self::WRITE.0 != 0) || self.is_append()
265    }
266
267    pub fn is_create(&self) -> bool {
268        self.0 & Self::CREATE.0 != 0
269    }
270
271    pub fn is_create_new(&self) -> bool {
272        self.0 & Self::CREATE_NEW.0 != 0
273    }
274
275    pub fn is_truncate(&self) -> bool {
276        self.0 & Self::TRUNCATE.0 != 0
277    }
278
279    pub fn is_append(&self) -> bool {
280        self.0 & Self::APPEND.0 != 0
281    }
282
283    pub fn from_u64(flags: u64) -> Option<Self> {
284        let all = (Self::READ.0
285            | Self::WRITE.0
286            | Self::CREATE.0
287            | Self::CREATE_NEW.0
288            | Self::TRUNCATE.0
289            | Self::APPEND.0) as u64;
290
291        if flags & !all != 0 {
292            return None;
293        }
294
295        Some(Self(flags as u8))
296    }
297
298    pub fn to_u64(&self) -> u64 {
299        self.0 as u64
300    }
301}
302
303impl Default for OpenOptions {
304    fn default() -> Self {
305        Self::READ
306    }
307}
308
309impl ops::BitOr for OpenOptions {
310    type Output = Self;
311
312    fn bitor(self, rhs: Self) -> Self::Output {
313        Self(self.0 | rhs.0)
314    }
315}
316
317impl ops::BitOrAssign for OpenOptions {
318    fn bitor_assign(&mut self, rhs: Self) {
319        *self = *self | rhs;
320    }
321}
322
323impl ops::BitAnd for OpenOptions {
324    type Output = Self;
325
326    fn bitand(self, rhs: Self) -> Self::Output {
327        Self(self.0 & rhs.0)
328    }
329}
330
331impl ops::BitAndAssign for OpenOptions {
332    fn bitand_assign(&mut self, rhs: Self) {
333        *self = *self & rhs;
334    }
335}