Skip to main content

ex_cli/cli/
file.rs

1use crate::error::{MyError, MyResult};
2use crate::fs::entry::Entry;
3use crate::fs::flags::FileFlags;
4use crate::fs::system::{System, EXEC_MASK};
5use std::collections::HashSet;
6
7#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
8pub enum ExecKind {
9    None,
10    User,
11    Other,
12}
13
14#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
15pub enum FileKind {
16    File(ExecKind),
17    Dir,
18    Link(bool), // (true for resolved link)
19    Other,
20}
21
22impl FileKind {
23    fn from_char(ch: char) -> Option<Vec<Self>> {
24        match ch {
25            'f' => Some(vec![
26                Self::File(ExecKind::None),
27                Self::File(ExecKind::User),
28                Self::File(ExecKind::Other),
29            ]),
30            'e' => Some(vec![
31                Self::File(ExecKind::User),
32                Self::File(ExecKind::Other),
33            ]),
34            'd' => Some(vec![
35                Self::Dir,
36            ]),
37            'l' => Some(vec![
38                Self::Link(false),
39                Self::Link(true),
40            ]),
41            _ => None,
42        }
43    }
44
45    pub fn from_entry<S: System>(system: &S, entry: &dyn Entry) -> Self {
46        match entry.file_flags() {
47            FileFlags::File => Self::parse_file(system, entry),
48            FileFlags::Dir => Self::Dir,
49            FileFlags::Link => Self::Link(true),
50            FileFlags::Other => Self::Other,
51        }
52    }
53
54    #[cfg(unix)]
55    fn parse_file<S: System>(system: &S, entry: &dyn Entry) -> Self {
56        if (entry.file_mode() & system.get_mask(entry.owner_uid(), entry.owner_gid())) != 0 {
57            Self::File(ExecKind::User)
58        } else if (entry.file_mode() & EXEC_MASK) != 0 {
59            Self::File(ExecKind::Other)
60        } else {
61            Self::File(ExecKind::None)
62        }
63    }
64
65    #[cfg(not(unix))]
66    fn parse_file<S: System>(_system: &S, entry: &dyn Entry) -> Self {
67        if (entry.file_mode() & EXEC_MASK) != 0 {
68            Self::File(ExecKind::User)
69        } else {
70            Self::File(ExecKind::None)
71        }
72    }
73
74    pub fn dir_offset(&self) -> usize {
75        if *self == Self::Dir { 1 } else { 0 }
76    }
77}
78
79#[derive(Clone)]
80pub struct FileSet {
81    pub inner: HashSet<FileKind>,
82}
83
84impl FileSet {
85    pub fn from_str(value: &str) -> MyResult<Self> {
86        let mut inner = HashSet::new();
87        for ch in value.chars() {
88            if let Some(items) = FileKind::from_char(ch) {
89                inner.extend(items);
90            } else {
91                return Err(MyError::create_clap("type", ch));
92            }
93        }
94        let results = Self { inner };
95        Ok(results)
96    }
97}