1use std::fmt;
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 w = 0;
43 if self.has(Self::DIR) {
44 write!(f, "d")?;
45 w += 1;
46 }
47 if self.has(Self::APPEND) {
48 write!(f, "a")?;
49 w += 1;
50 }
51 if self.has(Self::EXCLUSIVE) {
52 write!(f, "l")?;
53 w += 1;
54 }
55 if self.has(Self::TEMPORARY) {
56 write!(f, "T")?;
57 w += 1;
58 }
59 if self.has(Self::SYMLINK) {
60 write!(f, "L")?;
61 w += 1;
62 }
63 if self.has(Self::DEVICE) {
64 write!(f, "D")?;
65 w += 1;
66 }
67 if self.has(Self::NAMED_PIPE) {
68 write!(f, "p")?;
69 w += 1;
70 }
71 if self.has(Self::SOCKET) {
72 write!(f, "S")?;
73 w += 1;
74 }
75 if self.has(Self::SETUID) {
76 write!(f, "u")?;
77 w += 1;
78 }
79 if self.has(Self::SETGID) {
80 write!(f, "g")?;
81 w += 1;
82 }
83 if self.has(Self::CHAR_DEVICE) {
84 write!(f, "c")?;
85 w += 1;
86 }
87 if self.has(Self::STICKY) {
88 write!(f, "t")?;
89 w += 1;
90 }
91 if self.has(Self::IRREGULAR) {
92 write!(f, "?")?;
93 w += 1;
94 }
95 if w == 0 {
96 write!(f, "-")?;
97 }
98
99 let rwx = "rwxrwxrwx";
100 for (i, c) in rwx.char_indices() {
101 if self.has(Mode(1 << (9 - 1 - i))) {
102 write!(f, "{}", c)?;
103 } else {
104 write!(f, "-")?;
105 }
106 }
107
108 Ok(())
109 }
110}
111
112impl From<UnixMode> for Mode {
113 fn from(m: UnixMode) -> Self {
114 let mut mode = Mode(m.0 & 0o777);
115
116 match m & UnixMode::IFMT {
117 UnixMode::IFBLK => mode |= Mode::DEVICE,
118 UnixMode::IFCHR => mode |= Mode::DEVICE & Mode::CHAR_DEVICE,
119 UnixMode::IFDIR => mode |= Mode::DIR,
120 UnixMode::IFIFO => mode |= Mode::NAMED_PIPE,
121 UnixMode::IFLNK => mode |= Mode::SYMLINK,
122 UnixMode::IFREG => { }
123 UnixMode::IFSOCK => mode |= Mode::SOCKET,
124 _ => {}
125 }
126
127 if m.has(UnixMode::ISGID) {
128 mode |= Mode::SETGID
129 }
130 if m.has(UnixMode::ISUID) {
131 mode |= Mode::SETUID
132 }
133 if m.has(UnixMode::ISVTX) {
134 mode |= Mode::STICKY
135 }
136
137 mode
138 }
139}
140
141impl From<MsdosMode> for Mode {
142 fn from(m: MsdosMode) -> Self {
143 let mut mode = if m.has(MsdosMode::DIR) {
144 Mode::DIR | Mode(0o777)
145 } else {
146 Mode(0o666)
147 };
148 if m.has(MsdosMode::READ_ONLY) {
149 mode &= Mode(0o222);
150 }
151
152 mode
153 }
154}
155
156impl From<u32> for Mode {
157 fn from(u: u32) -> Self {
158 Mode(u)
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub struct UnixMode(pub u32);
165
166impl UnixMode {
167 pub const IFMT: Self = Self(0xf000);
169
170 pub const IFSOCK: Self = Self(0xc000);
172
173 pub const IFLNK: Self = Self(0xa000);
175
176 pub const IFREG: Self = Self(0x8000);
178
179 pub const IFBLK: Self = Self(0x6000);
181
182 pub const IFDIR: Self = Self(0x4000);
184
185 pub const IFCHR: Self = Self(0x2000);
187
188 pub const IFIFO: Self = Self(0x1000);
190
191 pub const ISUID: Self = Self(0x800);
193
194 pub const ISGID: Self = Self(0x400);
196
197 pub const ISVTX: Self = Self(0x200);
199}
200
201impl From<u32> for UnixMode {
202 fn from(u: u32) -> Self {
203 UnixMode(u)
204 }
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub struct MsdosMode(pub u32);
210
211impl MsdosMode {
212 pub const DIR: Self = Self(0x10);
214
215 pub const READ_ONLY: Self = Self(0x01);
217}
218
219impl From<u32> for MsdosMode {
220 fn from(u: u32) -> Self {
221 MsdosMode(u)
222 }
223}
224
225macro_rules! derive_bitops {
226 ($T: ty) => {
227 impl std::ops::BitOr for $T {
228 type Output = Self;
229
230 fn bitor(self, rhs: Self) -> Self {
231 Self(self.0 | rhs.0)
232 }
233 }
234
235 impl std::ops::BitOrAssign for $T {
236 fn bitor_assign(&mut self, rhs: Self) {
237 self.0 |= rhs.0;
238 }
239 }
240
241 impl std::ops::BitAnd for $T {
242 type Output = Self;
243
244 fn bitand(self, rhs: Self) -> Self {
245 Self(self.0 & rhs.0)
246 }
247 }
248
249 impl std::ops::BitAndAssign for $T {
250 fn bitand_assign(&mut self, rhs: Self) {
251 self.0 &= rhs.0;
252 }
253 }
254
255 impl $T {
256 pub fn has(&self, rhs: Self) -> bool {
258 self.0 & rhs.0 != 0
259 }
260 }
261 };
262}
263
264derive_bitops!(Mode);
265derive_bitops!(UnixMode);
266derive_bitops!(MsdosMode);