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), 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}