nuts_archive/entry/
mode.rs

1// MIT License
2//
3// Copyright (c) 2023 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23use nuts_bytes::{FromBytes, ToBytes};
24
25#[cfg(test)]
26mod tests;
27
28const MASK_TYPE: u16 = 0x0600;
29const TYPE_FILE: u16 = 0x0000;
30const TYPE_DIR: u16 = 0x0200;
31const TYPE_SYMLINK: u16 = 0x0400;
32
33const MASK_USR_R: u16 = 0x0001;
34const MASK_USR_W: u16 = 0x0002;
35const MASK_USR_X: u16 = 0x0004;
36const MASK_GRP_R: u16 = 0x0008;
37const MASK_GRP_W: u16 = 0x0010;
38const MASK_GRP_X: u16 = 0x0020;
39const MASK_OTH_R: u16 = 0x0040;
40const MASK_OTH_W: u16 = 0x0080;
41const MASK_OTH_X: u16 = 0x0100;
42
43const DEFAULT_ACCESS_RIGHTS: u16 =
44    MASK_USR_R | MASK_USR_W | MASK_USR_X | MASK_GRP_R | MASK_GRP_X | MASK_OTH_R | MASK_OTH_X;
45
46#[derive(Clone, Copy, PartialEq)]
47pub enum Group {
48    User,
49    Group,
50    Other,
51}
52
53/// Bitmask encoding entry type & access rights.
54#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
55pub(crate) struct Mode(u16);
56
57impl Mode {
58    pub fn file() -> Mode {
59        Mode(TYPE_FILE | DEFAULT_ACCESS_RIGHTS)
60    }
61
62    pub fn directory() -> Mode {
63        Mode(TYPE_DIR | DEFAULT_ACCESS_RIGHTS)
64    }
65
66    pub fn symlink() -> Mode {
67        Mode(TYPE_SYMLINK | DEFAULT_ACCESS_RIGHTS)
68    }
69
70    /// Tests whether this `Mode` instance represents a file.
71    pub fn is_file(&self) -> bool {
72        self.0 & MASK_TYPE == TYPE_FILE
73    }
74
75    /// Tests whether this `Mode` instance represents a directory.
76    pub fn is_directory(&self) -> bool {
77        self.0 & MASK_TYPE == TYPE_DIR
78    }
79
80    /// Tests whether this `Mode` instance represents a symlink.
81    pub fn is_symlink(&self) -> bool {
82        self.0 & MASK_TYPE == TYPE_SYMLINK
83    }
84
85    /// Tests whether a member of the given `group` has read access.
86    pub fn can_read(&self, group: Group) -> bool {
87        self.0 & Self::read_mask(group) > 0
88    }
89
90    /// Updates the read access attribute.
91    ///
92    /// If `readable` is set to `true`, a member of the given `group` becomes
93    /// read access. If set to `false`, the read access is revoked.
94    pub fn set_readable(&mut self, group: Group, readable: bool) {
95        self.update_mask(readable, Self::read_mask(group));
96    }
97
98    /// Tests whether a member of the given `group` has write access.
99    pub fn can_write(&self, group: Group) -> bool {
100        self.0 & Self::write_mask(group) > 0
101    }
102
103    /// Updates the write access attribute.
104    ///
105    /// If `writable` is set to `true`, a member of the given `group` becomes
106    /// write access. If set to `false`, the write access is revoked.
107    pub fn set_writable(&mut self, group: Group, writable: bool) {
108        self.update_mask(writable, Self::write_mask(group));
109    }
110
111    /// Tests whether a member of the given `group` has execute access.
112    pub fn can_execute(&self, group: Group) -> bool {
113        self.0 & Self::execute_mask(group) > 0
114    }
115
116    /// Updates the execute access attribute.
117    ///
118    /// If `executable` is set to `true`, a member of the given `group` becomes
119    /// execute access. If set to `false`, the execute access is revoked.
120    pub fn set_executable(&mut self, group: Group, executable: bool) {
121        self.update_mask(executable, Self::execute_mask(group));
122    }
123
124    fn read_mask(group: Group) -> u16 {
125        match group {
126            Group::User => MASK_USR_R,
127            Group::Group => MASK_GRP_R,
128            Group::Other => MASK_OTH_R,
129        }
130    }
131
132    fn write_mask(group: Group) -> u16 {
133        match group {
134            Group::User => MASK_USR_W,
135            Group::Group => MASK_GRP_W,
136            Group::Other => MASK_OTH_W,
137        }
138    }
139
140    fn execute_mask(group: Group) -> u16 {
141        match group {
142            Group::User => MASK_USR_X,
143            Group::Group => MASK_GRP_X,
144            Group::Other => MASK_OTH_X,
145        }
146    }
147
148    fn update_mask(&mut self, enable: bool, mask: u16) {
149        if enable {
150            self.0 |= mask;
151        } else {
152            self.0 &= !mask;
153        }
154    }
155}