1use std::fmt::{self, Write};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Mode(pub u32);
10
11impl Mode {
12 pub const DIR: Self = Self(1 << 31);
14 pub const APPEND: Self = Self(1 << 30);
16 pub const EXCLUSIVE: Self = Self(1 << 29);
18 pub const TEMPORARY: Self = Self(1 << 28);
20 pub const SYMLINK: Self = Self(1 << 27);
22 pub const DEVICE: Self = Self(1 << 26);
24 pub const NAMED_PIPE: Self = Self(1 << 25);
26 pub const SOCKET: Self = Self(1 << 24);
28 pub const SETUID: Self = Self(1 << 23);
30 pub const SETGID: Self = Self(1 << 22);
32 pub const CHAR_DEVICE: Self = Self(1 << 21);
34 pub const STICKY: Self = Self(1 << 20);
36 pub const IRREGULAR: Self = Self(1 << 19);
38}
39
40impl fmt::Display for Mode {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 let mut empty = true;
43 let pairs = [
44 (Self::DIR, 'd'),
45 (Self::APPEND, 'a'),
46 (Self::EXCLUSIVE, 'l'),
47 (Self::TEMPORARY, 'T'),
48 (Self::SYMLINK, 'L'),
49 (Self::DEVICE, 'D'),
50 (Self::NAMED_PIPE, 'p'),
51 (Self::SOCKET, 'S'),
52 (Self::SETUID, 'u'),
53 (Self::SETGID, 'g'),
54 (Self::CHAR_DEVICE, 'c'),
55 (Self::STICKY, 't'),
56 (Self::IRREGULAR, '?'),
57 ];
58 for (flag, flag_char) in pairs {
59 if self.has(flag) {
60 f.write_char(flag_char)?;
61 empty = false;
62 }
63 }
64 if empty {
65 write!(f, "-")?;
66 }
67
68 let rwx = "rwxrwxrwx";
69 for (i, c) in rwx.char_indices() {
70 if self.has(Mode(1 << (9 - 1 - i))) {
71 write!(f, "{}", c)?;
72 } else {
73 write!(f, "-")?;
74 }
75 }
76
77 Ok(())
78 }
79}
80
81impl From<UnixMode> for Mode {
82 fn from(m: UnixMode) -> Self {
83 let mut mode = Mode(m.0 & 0o777);
84
85 match m & UnixMode::IFMT {
86 UnixMode::IFBLK => mode |= Mode::DEVICE,
87 UnixMode::IFCHR => mode |= Mode::DEVICE & Mode::CHAR_DEVICE,
88 UnixMode::IFDIR => mode |= Mode::DIR,
89 UnixMode::IFIFO => mode |= Mode::NAMED_PIPE,
90 UnixMode::IFLNK => mode |= Mode::SYMLINK,
91 UnixMode::IFREG => { }
92 UnixMode::IFSOCK => mode |= Mode::SOCKET,
93 _ => {}
94 }
95
96 if m.has(UnixMode::ISGID) {
97 mode |= Mode::SETGID
98 }
99 if m.has(UnixMode::ISUID) {
100 mode |= Mode::SETUID
101 }
102 if m.has(UnixMode::ISVTX) {
103 mode |= Mode::STICKY
104 }
105
106 mode
107 }
108}
109
110impl From<MsdosMode> for Mode {
111 fn from(m: MsdosMode) -> Self {
112 let mut mode = if m.has(MsdosMode::DIR) {
113 Mode::DIR | Mode(0o777)
114 } else {
115 Mode(0o666)
116 };
117 if m.has(MsdosMode::READ_ONLY) {
118 mode &= Mode(0o222);
119 }
120
121 mode
122 }
123}
124
125impl From<u32> for Mode {
126 fn from(u: u32) -> Self {
127 Mode(u)
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
133pub struct UnixMode(pub u32);
134
135impl UnixMode {
136 pub const IFMT: Self = Self(0xf000);
138
139 pub const IFSOCK: Self = Self(0xc000);
141
142 pub const IFLNK: Self = Self(0xa000);
144
145 pub const IFREG: Self = Self(0x8000);
147
148 pub const IFBLK: Self = Self(0x6000);
150
151 pub const IFDIR: Self = Self(0x4000);
153
154 pub const IFCHR: Self = Self(0x2000);
156
157 pub const IFIFO: Self = Self(0x1000);
159
160 pub const ISUID: Self = Self(0x800);
162
163 pub const ISGID: Self = Self(0x400);
165
166 pub const ISVTX: Self = Self(0x200);
168}
169
170impl From<u32> for UnixMode {
171 fn from(u: u32) -> Self {
172 UnixMode(u)
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
178pub struct MsdosMode(pub u32);
179
180impl MsdosMode {
181 pub const DIR: Self = Self(0x10);
183
184 pub const READ_ONLY: Self = Self(0x01);
186}
187
188impl From<u32> for MsdosMode {
189 fn from(u: u32) -> Self {
190 MsdosMode(u)
191 }
192}
193
194macro_rules! derive_bitops {
195 ($T: ty) => {
196 impl std::ops::BitOr for $T {
197 type Output = Self;
198
199 fn bitor(self, rhs: Self) -> Self {
200 Self(self.0 | rhs.0)
201 }
202 }
203
204 impl std::ops::BitOrAssign for $T {
205 fn bitor_assign(&mut self, rhs: Self) {
206 self.0 |= rhs.0;
207 }
208 }
209
210 impl std::ops::BitAnd for $T {
211 type Output = Self;
212
213 fn bitand(self, rhs: Self) -> Self {
214 Self(self.0 & rhs.0)
215 }
216 }
217
218 impl std::ops::BitAndAssign for $T {
219 fn bitand_assign(&mut self, rhs: Self) {
220 self.0 &= rhs.0;
221 }
222 }
223
224 impl $T {
225 pub fn has(&self, rhs: Self) -> bool {
227 self.0 & rhs.0 != 0
228 }
229 }
230 };
231}
232
233derive_bitops!(Mode);
234derive_bitops!(UnixMode);
235derive_bitops!(MsdosMode);