emerald_kernel_user_link/
file.rs1use core::{ffi::CStr, ops};
2
3#[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
52pub fn parse_flags(flags: u64) -> Option<BlockingMode> {
55 let blocking_mode = BlockingMode::from_flags(flags);
56 let flags = flags & !1;
57 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}