rc_zip/parse/
mode.rs

1use std::fmt;
2
3/// Mode represents a file's mode and permission bits.
4/// The bits have the same definition on all systems,
5/// but not all bits apply to all systems.
6///
7/// It is modelled after Go's `os.FileMode`.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Mode(pub u32);
10
11impl Mode {
12    /// d: is a directory
13    pub const DIR: Self = Self(1 << 31);
14    /// a: append-only
15    pub const APPEND: Self = Self(1 << 30);
16    /// l: exclusive use
17    pub const EXCLUSIVE: Self = Self(1 << 29);
18    /// T: temporary file; Plan 9 only
19    pub const TEMPORARY: Self = Self(1 << 28);
20    /// L: symbolic link
21    pub const SYMLINK: Self = Self(1 << 27);
22    /// D: device file
23    pub const DEVICE: Self = Self(1 << 26);
24    /// p: named pipe (FIFO)
25    pub const NAMED_PIPE: Self = Self(1 << 25);
26    /// S: Unix domain socket
27    pub const SOCKET: Self = Self(1 << 24);
28    /// u: setuid
29    pub const SETUID: Self = Self(1 << 23);
30    /// g: setgid
31    pub const SETGID: Self = Self(1 << 22);
32    /// c: Unix character device, when DEVICE is set
33    pub const CHAR_DEVICE: Self = Self(1 << 21);
34    /// t: sticky
35    pub const STICKY: Self = Self(1 << 20);
36    /// ?: non-regular file; nothing else is known
37    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 => { /* nothing to do */ }
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/// UnixMode represents the file mode and permission bits for Unix systems.
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub struct UnixMode(pub u32);
165
166impl UnixMode {
167    /// bit mask for the file type bit fields
168    pub const IFMT: Self = Self(0xf000);
169
170    /// the file is a socket
171    pub const IFSOCK: Self = Self(0xc000);
172
173    /// the file is a symbolic link
174    pub const IFLNK: Self = Self(0xa000);
175
176    /// the file is a regular file
177    pub const IFREG: Self = Self(0x8000);
178
179    /// the file is a block device
180    pub const IFBLK: Self = Self(0x6000);
181
182    /// the file is a directory
183    pub const IFDIR: Self = Self(0x4000);
184
185    /// the file is a character device
186    pub const IFCHR: Self = Self(0x2000);
187
188    /// the file is a FIFO
189    pub const IFIFO: Self = Self(0x1000);
190
191    /// the file is set-user-ID
192    pub const ISUID: Self = Self(0x800);
193
194    /// the file is set-group-ID
195    pub const ISGID: Self = Self(0x400);
196
197    /// the file is sticky
198    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/// MsdosMode represents the file mode and permission bits for MS-DOS
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub struct MsdosMode(pub u32);
210
211impl MsdosMode {
212    /// the file is a directory
213    pub const DIR: Self = Self(0x10);
214
215    /// the file is read-only
216    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            /// Check if the mode has the given bits set.
257            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);