1use crate::inode::InodeMode;
10
11#[derive(Clone, Debug, Eq, PartialEq)]
12pub(crate) struct FileTypeError;
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16pub enum FileType {
17 BlockDevice,
19
20 CharacterDevice,
22
23 Directory,
25
26 Fifo,
28
29 Regular,
31
32 Socket,
34
35 Symlink,
37}
38
39impl FileType {
40 pub(crate) fn from_dir_entry(val: u8) -> Result<Self, FileTypeError> {
41 match val {
42 1 => Ok(Self::Regular),
43 2 => Ok(Self::Directory),
44 3 => Ok(Self::CharacterDevice),
45 4 => Ok(Self::BlockDevice),
46 5 => Ok(Self::Fifo),
47 6 => Ok(Self::Socket),
48 7 => Ok(Self::Symlink),
49 _ => Err(FileTypeError),
50 }
51 }
52
53 #[must_use]
55 pub fn is_block_dev(self) -> bool {
56 self == Self::BlockDevice
57 }
58
59 #[must_use]
61 pub fn is_char_dev(self) -> bool {
62 self == Self::CharacterDevice
63 }
64
65 #[must_use]
67 pub fn is_dir(self) -> bool {
68 self == Self::Directory
69 }
70
71 #[must_use]
73 pub fn is_fifo(self) -> bool {
74 self == Self::Fifo
75 }
76
77 #[must_use]
79 pub fn is_regular_file(self) -> bool {
80 self == Self::Regular
81 }
82
83 #[must_use]
85 pub fn is_socket(self) -> bool {
86 self == Self::Socket
87 }
88
89 #[must_use]
91 pub fn is_symlink(self) -> bool {
92 self == Self::Symlink
93 }
94}
95
96impl TryFrom<InodeMode> for FileType {
97 type Error = FileTypeError;
98
99 fn try_from(mode: InodeMode) -> Result<Self, Self::Error> {
100 let mode = InodeMode::from_bits_retain(mode.bits() & 0xf000);
102
103 if mode == InodeMode::S_IFIFO {
104 Ok(Self::Fifo)
105 } else if mode == InodeMode::S_IFCHR {
106 Ok(Self::CharacterDevice)
107 } else if mode == InodeMode::S_IFDIR {
108 Ok(Self::Directory)
109 } else if mode == InodeMode::S_IFBLK {
110 Ok(Self::BlockDevice)
111 } else if mode == InodeMode::S_IFREG {
112 Ok(Self::Regular)
113 } else if mode == InodeMode::S_IFLNK {
114 Ok(Self::Symlink)
115 } else if mode == InodeMode::S_IFSOCK {
116 Ok(Self::Socket)
117 } else {
118 Err(FileTypeError)
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_file_type() {
129 assert!(FileType::try_from(InodeMode::S_IFIFO).unwrap().is_fifo());
131 assert!(
132 FileType::try_from(InodeMode::S_IFCHR)
133 .unwrap()
134 .is_char_dev()
135 );
136 assert!(
137 FileType::try_from(InodeMode::S_IFBLK)
138 .unwrap()
139 .is_block_dev()
140 );
141 assert!(
142 FileType::try_from(InodeMode::S_IFREG)
143 .unwrap()
144 .is_regular_file()
145 );
146 assert!(FileType::try_from(InodeMode::S_IFLNK).unwrap().is_symlink());
147 assert!(FileType::try_from(InodeMode::S_IFSOCK).unwrap().is_socket());
148
149 assert!(
152 FileType::try_from(InodeMode::S_IFREG | InodeMode::S_IXOTH)
153 .unwrap()
154 .is_regular_file()
155 );
156
157 assert_eq!(
159 FileType::try_from(InodeMode::empty()).unwrap_err(),
160 FileTypeError
161 );
162 }
163}