file_system/fundamentals/
permission.rs

1use core::fmt::{self, Display};
2
3use shared::flags;
4
5use crate::Kind;
6
7flags! {
8    /// The permissions of a file or directory.
9    pub enum Permission: u8 {
10        Execute,
11        Write,
12        Read,
13    }
14}
15
16impl Permission {
17    pub const READ_WRITE: Self = Permission::None
18        .insert(Permission::Read)
19        .insert(Permission::Write);
20    pub const READ_EXECUTE: Self = Permission::None
21        .insert(Permission::Read)
22        .insert(Permission::Execute);
23    pub const WRITE_EXECUTE: Self = Permission::None
24        .insert(Permission::Write)
25        .insert(Permission::Execute);
26
27    pub const fn from_unix(unix: u8) -> Option<Self> {
28        if unix > 0b111 {
29            return None;
30        }
31
32        Some(Self(unix))
33    }
34
35    pub const fn to_unix(&self) -> u8 {
36        self.0
37    }
38}
39
40impl Display for Permission {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        let read = if self.contains(Permission::Read) {
43            "r"
44        } else {
45            "-"
46        };
47        let write = if self.contains(Permission::Write) {
48            "w"
49        } else {
50            "-"
51        };
52        let execute = if self.contains(Permission::Execute) {
53            "x"
54        } else {
55            "-"
56        };
57
58        write!(f, "{read}{write}{execute}")
59    }
60}
61
62flags! {
63    /// The special permissions of a file or directory.
64    pub enum Special: u8 {
65        /// Sticky bit.
66        Sticky,
67        /// Set user identifier.
68        SetUserIdentifier,
69        /// Set group identifier.
70        SetGroupIdentifier,
71    }
72}
73
74impl fmt::Display for Special {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        let sticky = if self.contains(Special::Sticky) {
77            "t"
78        } else {
79            "-"
80        };
81        let set_gid = if self.contains(Special::SetGroupIdentifier) {
82            "u"
83        } else {
84            "-"
85        };
86        let set_uid = if self.contains(Special::SetUserIdentifier) {
87            "g"
88        } else {
89            "-"
90        };
91
92        write!(f, "{sticky}{set_gid}{set_uid}")
93    }
94}
95
96/// Represents the permissions of a file or directory.
97///
98/// The permissions are divided into three groups: user, group, and others.
99/// Each group has three permissions: read, write, and execute.
100///
101/// # Examples
102///
103/// ```rust
104/// use file_system::{Permissions, Permission, Special};
105///
106/// let user = Permission::Read; // Read only
107/// let group = Permission::Write; // Write only
108/// let others = Permission::Execute; // Execute only
109/// let special = Special::None;
110///
111/// let permissions = Permissions::new(user, group, others, special);
112///
113/// assert_eq!(permissions.get_user(), user);
114/// assert_eq!(permissions.get_group(), group);
115/// assert_eq!(permissions.get_others(), others);
116/// assert_eq!(permissions.get_special(), special);
117/// ```
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119#[repr(transparent)]
120pub struct Permissions(u16);
121
122impl fmt::Display for Permissions {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        let user = self.get_user();
125        let group = self.get_group();
126        let others = self.get_others();
127
128        write!(f, "{user}{group}{others}")
129    }
130}
131
132impl From<(Permission, Permission, Permission)> for Permissions {
133    fn from(value: (Permission, Permission, Permission)) -> Self {
134        Self::new(value.0, value.1, value.2, Special::NONE)
135    }
136}
137
138impl From<(Permission, Permission, Permission, Special)> for Permissions {
139    fn from(value: (Permission, Permission, Permission, Special)) -> Self {
140        Self::new(value.0, value.1, value.2, value.3)
141    }
142}
143
144impl Permissions {
145    pub const NONE: Self = Self::new(
146        Permission::None,
147        Permission::None,
148        Permission::None,
149        Special::NONE,
150    );
151    pub const ALL_FULL: Self = Self::new(
152        Permission::All,
153        Permission::All,
154        Permission::All,
155        Special::NONE,
156    );
157    pub const ALL_READ_WRITE: Self = Self::new(
158        Permission::READ_WRITE,
159        Permission::READ_WRITE,
160        Permission::READ_WRITE,
161        Special::NONE,
162    );
163    pub const USER_FULL: Self = Self::new(
164        Permission::All,
165        Permission::None,
166        Permission::None,
167        Special::NONE,
168    );
169    pub const USER_READ_WRITE: Self = Self::new(
170        Permission::READ_WRITE,
171        Permission::None,
172        Permission::None,
173        Special::NONE,
174    );
175    pub const EXECUTABLE: Self = Self::new(
176        Permission::All,
177        Permission::READ_EXECUTE,
178        Permission::READ_EXECUTE,
179        Special::NONE,
180    );
181    pub const FILE_DEFAULT: Self = Self::new(
182        Permission::READ_WRITE,
183        Permission::READ_WRITE,
184        Permission::Read,
185        Special::NONE,
186    );
187    pub const DIRECTORY_DEFAULT: Self = Self::new(
188        Permission::All,
189        Permission::All,
190        Permission::READ_EXECUTE,
191        Special::NONE,
192    );
193    pub const DEVICE_DEFAULT: Self = Self::new(
194        Permission::All,
195        Permission::READ_WRITE,
196        Permission::READ_WRITE,
197        Special::NONE,
198    );
199
200    /// Creates a new permission.
201    pub const fn new(
202        user: Permission,
203        group: Permission,
204        others: Permission,
205        special: Special,
206    ) -> Self {
207        Self(
208            (special.to_unix() as u16) << 9
209                | (user.to_unix() as u16) << 6
210                | (group.to_unix() as u16) << 3
211                | others.to_unix() as u16,
212        )
213    }
214
215    /// Creates a new permission with read access for user. No access for group and others.
216    pub const fn new_default(r#type: Kind) -> Self {
217        match r#type {
218            Kind::Directory => Self::new(
219                Permission::All,
220                Permission::READ_EXECUTE,
221                Permission::READ_EXECUTE,
222                Special::NONE,
223            ),
224            Kind::File => Self::new(
225                Permission::READ_WRITE,
226                Permission::Read,
227                Permission::Read,
228                Special::NONE,
229            ),
230            Kind::Pipe => Self::new(
231                Permission::READ_WRITE,
232                Permission::None,
233                Permission::None,
234                Special::NONE,
235            ),
236            Kind::BlockDevice => Self::new(
237                Permission::All,
238                Permission::READ_WRITE,
239                Permission::READ_WRITE,
240                Special::NONE,
241            ),
242            Kind::CharacterDevice => Self::new(
243                Permission::READ_WRITE,
244                Permission::READ_WRITE,
245                Permission::None,
246                Special::NONE,
247            ),
248            Kind::Socket => Self::ALL_READ_WRITE,
249            Kind::SymbolicLink => Self::ALL_FULL,
250        }
251    }
252
253    /// Sets the permission for the user.
254    pub fn set_user(mut self, user: Permission) -> Self {
255        self.0 = (self.0 & 0o7077) | (user.to_unix() as u16) << 6;
256        self
257    }
258
259    /// Sets the permission for the group.
260    pub fn set_group(mut self, group: Permission) -> Self {
261        self.0 = (self.0 & 0o7707) | (group.to_unix() as u16) << 3;
262        self
263    }
264
265    /// Sets the permission for others.
266    pub fn set_others(mut self, others: Permission) -> Self {
267        self.0 = (self.0 & 0o7770) | others.to_unix() as u16;
268        self
269    }
270
271    /// Sets the special permissions.
272    pub fn set_special(mut self, special: Special) -> Self {
273        self.0 = (self.0 & 0o0777) | (special.to_unix() as u16) << 9;
274        self
275    }
276
277    /// Gets the permission for the user.
278    pub fn get_user(&self) -> Permission {
279        Permission::from_unix(((self.0 >> 6) & 0b111) as u8).unwrap()
280    }
281
282    /// Gets the permission for the group.
283    pub fn get_group(&self) -> Permission {
284        Permission::from_unix(((self.0 >> 3) & 0b111) as u8).unwrap()
285    }
286
287    /// Gets the permission for others.
288    pub fn get_others(&self) -> Permission {
289        Permission::from_unix((self.0 & 0b111) as u8).unwrap()
290    }
291
292    /// Gets the special permissions.
293    pub fn get_special(&self) -> Special {
294        Special::from_unix((self.0 >> 9) as u8).unwrap()
295    }
296
297    /// Converts the permission to a Unix permission.
298    pub const fn from_octal(unix: u16) -> Option<Self> {
299        if unix > 0o777 {
300            return None;
301        }
302
303        Some(Self(unix))
304    }
305
306    /// Converts the permission to a Unix permission.
307    pub const fn as_u16(&self) -> u16 {
308        self.0
309    }
310}
311
312impl Special {
313    pub const NONE: Self = Self(0);
314    pub const STICKY: Self = Self(1);
315    pub const SET_USER_IDENTIFIER: Self = Self(2);
316    pub const SET_GROUP_IDENTIFIER: Self = Self(4);
317
318    pub fn new(sticky: bool, set_gid: bool, set_uid: bool) -> Self {
319        Self((sticky as u8) | (set_gid as u8) << 1 | (set_uid as u8) << 2)
320    }
321
322    pub fn set_sticky(mut self, sticky: bool) -> Self {
323        self.0 = (self.0 & 0b110) | sticky as u8;
324        self
325    }
326
327    pub fn set_set_group_identifier(mut self, set_gid: bool) -> Self {
328        self.0 = (self.0 & 0b101) | (set_gid as u8) << 1;
329        self
330    }
331
332    pub fn set_set_user_identifier(mut self, set_uid: bool) -> Self {
333        self.0 = (self.0 & 0b011) | (set_uid as u8) << 2;
334        self
335    }
336
337    pub const fn get_sticky(&self) -> bool {
338        self.0 & 0b001 != 0
339    }
340
341    pub const fn get_set_group_identifier(&self) -> bool {
342        self.0 & 0b010 != 0
343    }
344
345    pub const fn get_set_user_identifier(&self) -> bool {
346        self.0 & 0b100 != 0
347    }
348
349    pub const fn to_unix(&self) -> u8 {
350        self.0
351    }
352
353    pub fn from_unix(unix: u8) -> Option<Self> {
354        if unix > 0b111 {
355            return None;
356        }
357
358        Some(Self(unix))
359    }
360}
361
362#[cfg(test)]
363mod tests {
364    use super::*;
365
366    #[test]
367    fn test_new_permissions() {
368        let user = Permission::Read; // Read only
369        let group = Permission::Write; // Write only
370        let others = Permission::Execute; // Execute only
371        let special = Special::new(true, false, true); // Sticky and set user identifier
372        let permissions = Permissions::new(user, group, others, special);
373        assert_eq!(permissions.0, 0b101_100_010_001);
374    }
375
376    #[test]
377    fn test_new_permission() {
378        assert_eq!(Permission::Read.0, 0b100);
379        assert_eq!(Permission::Write.0, 0b010);
380        assert_eq!(Permission::Execute.0, 0b001);
381        assert_eq!(Permission::READ_WRITE.0, 0b110);
382        assert_eq!(Permission::WRITE_EXECUTE.0, 0b011);
383        assert_eq!(Permission::READ_EXECUTE.0, 0b101);
384        assert_eq!(Permission::None.0, 0b000);
385        assert_eq!(Permission::All.0, 0b111);
386    }
387
388    #[test]
389    fn test_permission_type_to_unix() {
390        let read = Permission::Read;
391        assert_eq!(read.to_unix(), 4);
392        let write = Permission::Write;
393        assert_eq!(write.to_unix(), 2);
394        let execute = Permission::Execute;
395        assert_eq!(execute.to_unix(), 1);
396        let full = Permission::All;
397        assert_eq!(full.to_unix(), 7);
398        let none = Permission::None;
399        assert_eq!(none.to_unix(), 0);
400    }
401
402    #[test]
403    fn test_permission_type_from_unix() {
404        let read = Permission::from_unix(4).unwrap();
405        assert_eq!(read, Permission::Read);
406        let write = Permission::from_unix(2).unwrap();
407        assert_eq!(write, Permission::Write);
408        let execute = Permission::from_unix(1).unwrap();
409        assert_eq!(execute, Permission::Execute);
410        let full = Permission::from_unix(7).unwrap();
411        assert_eq!(full, Permission::All);
412        let no = Permission::from_unix(0).unwrap();
413        assert_eq!(no, Permission::None);
414    }
415
416    #[test]
417    fn test_permissions_type_from_unix() {
418        let permissions = Permissions::from_octal(0b101_101_101).unwrap();
419        assert_eq!(permissions.get_user().to_unix(), 5);
420        assert_eq!(permissions.get_group().to_unix(), 5);
421        assert_eq!(permissions.get_others().to_unix(), 5);
422    }
423
424    #[test]
425    fn test_permissions_type_to_unix() {
426        let user = Permission::Read | Permission::Execute; // Read and execute
427        let group = Permission::Read | Permission::Write; // Read and write
428        let others = Permission::Write | Permission::Execute; // Write and execute
429        let special = Special::new(true, false, true); // Sticky and set user identifier
430        let permissions = Permissions::new(user, group, others, special);
431        assert_eq!(permissions.as_u16(), 0b101_101_110_011);
432    }
433
434    #[test]
435    fn test_permission_type_contains() {
436        let read = Permission::Read;
437        let write = Permission::Write;
438        let read_write = Permission::READ_WRITE;
439        let read_execute = Permission::READ_EXECUTE;
440        let write_execute = Permission::WRITE_EXECUTE;
441        let execute = Permission::Execute;
442        let full = Permission::All;
443        let no = Permission::None;
444
445        assert!(full.contains(read));
446        assert!(full.contains(write));
447        assert!(full.contains(execute));
448        assert!(full.contains(read_write));
449        assert!(full.contains(read_execute));
450        assert!(full.contains(write_execute));
451        assert!(full.contains(full));
452        assert!(full.contains(no));
453
454        assert!(read.contains(read));
455        assert!(!read.contains(write));
456        assert!(!read.contains(execute));
457        assert!(!read.contains(read_write));
458        assert!(!read.contains(read_execute));
459        assert!(!read.contains(write_execute));
460        assert!(!read.contains(full));
461        assert!(read.contains(no));
462
463        assert!(!write.contains(read));
464        assert!(write.contains(write));
465        assert!(!write.contains(execute));
466        assert!(!write.contains(read_write));
467        assert!(!write.contains(read_execute));
468        assert!(!write.contains(write_execute));
469        assert!(!write.contains(full));
470        assert!(write.contains(no));
471
472        assert!(!execute.contains(read));
473        assert!(!execute.contains(write));
474        assert!(execute.contains(execute));
475        assert!(!execute.contains(read_write));
476        assert!(!execute.contains(read_execute));
477        assert!(!execute.contains(write_execute));
478        assert!(!execute.contains(full));
479        assert!(execute.contains(no));
480
481        assert!(read_write.contains(read));
482        assert!(read_write.contains(write));
483        assert!(!read_write.contains(execute));
484        assert!(read_write.contains(read_write));
485        assert!(!read_write.contains(read_execute));
486        assert!(!read_write.contains(write_execute));
487        assert!(!read_write.contains(full));
488        assert!(read_write.contains(no));
489
490        assert!(read_execute.contains(read));
491        assert!(!read_execute.contains(write));
492        assert!(read_execute.contains(execute));
493        assert!(!read_execute.contains(read_write));
494        assert!(read_execute.contains(read_execute));
495        assert!(!read_execute.contains(write_execute));
496        assert!(!read_execute.contains(full));
497        assert!(read_execute.contains(no));
498
499        assert!(!write_execute.contains(read));
500        assert!(write_execute.contains(write));
501        assert!(write_execute.contains(execute));
502        assert!(!write_execute.contains(read_write));
503        assert!(!write_execute.contains(read_execute));
504        assert!(write_execute.contains(write_execute));
505        assert!(!write_execute.contains(full));
506        assert!(write_execute.contains(no));
507
508        assert!(!no.contains(read));
509        assert!(!no.contains(write));
510        assert!(!no.contains(execute));
511        assert!(!no.contains(read_write));
512        assert!(!no.contains(read_execute));
513        assert!(!no.contains(write_execute));
514        assert!(!no.contains(full));
515        assert!(no.contains(no));
516    }
517}