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    Block,
20    Char,
21    Pipe,
22    Socket,
23    Other,
24}
25
26impl FileKind {
27    fn from_char(ch: char) -> Option<Vec<Self>> {
28        match ch {
29            'f' => Some(vec![
30                Self::File(ExecKind::None),
31                Self::File(ExecKind::User),
32                Self::File(ExecKind::Other),
33            ]),
34            'e' => Some(vec![
35                Self::File(ExecKind::User),
36                Self::File(ExecKind::Other),
37            ]),
38            'd' => Some(vec![
39                Self::Dir,
40            ]),
41            'l' => Some(vec![
42                Self::Link(false),
43                Self::Link(true),
44            ]),
45            'b' => Some(vec![
46                Self::Block,
47            ]),
48            'c' => Some(vec![
49                Self::Char,
50            ]),
51            'p' => Some(vec![
52                Self::Pipe,
53            ]),
54            's' => Some(vec![
55                Self::Socket,
56            ]),
57            _ => None,
58        }
59    }
60
61    pub fn from_entry<S: System>(system: &S, entry: &dyn Entry) -> Self {
62        match entry.file_flags() {
63            FileFlags::File => Self::parse_file(system, entry),
64            FileFlags::Dir => Self::Dir,
65            FileFlags::Link => Self::Link(true),
66            FileFlags::Block => Self::Block,
67            FileFlags::Char => Self::Char,
68            FileFlags::Pipe => Self::Pipe,
69            FileFlags::Socket => Self::Socket,
70            FileFlags::Other => Self::Other,
71        }
72    }
73
74    #[cfg(unix)]
75    fn parse_file<S: System>(system: &S, entry: &dyn Entry) -> Self {
76        if (entry.file_mode() & system.get_mask(entry.owner_uid(), entry.owner_gid())) != 0 {
77            Self::File(ExecKind::User)
78        } else if (entry.file_mode() & EXEC_MASK) != 0 {
79            Self::File(ExecKind::Other)
80        } else {
81            Self::File(ExecKind::None)
82        }
83    }
84
85    #[cfg(not(unix))]
86    fn parse_file<S: System>(_system: &S, entry: &dyn Entry) -> Self {
87        if (entry.file_mode() & EXEC_MASK) != 0 {
88            Self::File(ExecKind::User)
89        } else {
90            Self::File(ExecKind::None)
91        }
92    }
93
94    pub fn dir_offset(&self) -> usize {
95        if *self == Self::Dir { 1 } else { 0 }
96    }
97}
98
99#[derive(Clone, Debug)]
100pub struct FileSet {
101    pub inner: HashSet<FileKind>,
102}
103
104impl FileSet {
105    pub fn from_str(value: &str) -> MyResult<Self> {
106        let mut inner = HashSet::new();
107        for ch in value.chars() {
108            if let Some(items) = FileKind::from_char(ch) {
109                inner.extend(items);
110            } else {
111                return Err(MyError::create_clap("type", ch));
112            }
113        }
114        let results = Self { inner };
115        Ok(results)
116    }
117}