dia_files/
permissions.rs

1/*
2==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
3
4Dia-Files
5
6Copyright (C) 2019-2024  Anonymous
7
8There are several releases over multiple years,
9they are listed as ranges, such as: "2019-2024".
10
11This program is free software: you can redistribute it and/or modify
12it under the terms of the GNU Lesser General Public License as published by
13the Free Software Foundation, either version 3 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public License
22along with this program.  If not, see <https://www.gnu.org/licenses/>.
23
24::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
25*/
26
27//! # Permissions
28
29#[cfg(unix)]
30use {
31    core::cmp::Ordering,
32    std::{
33        fs::{self, Metadata},
34        io::Error,
35        os::unix::fs::PermissionsExt,
36        path::{Path, PathBuf},
37    },
38    crate::Result,
39};
40
41mod impls;
42
43#[cfg(test)]
44mod tests;
45
46/// # Raw Permission
47#[cfg(unix)]
48#[doc(cfg(unix))]
49pub type RawPermission = u32;
50
51/// # Permissions
52///
53/// You can cast this enum to [`RawPermission`][type:RawPermission] directly via `as`.
54///
55/// [type:RawPermission]: type.RawPermission.html
56#[cfg(unix)]
57#[doc(cfg(unix))]
58#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd)]
59pub enum Permissions {
60
61    /// # No permissions
62    None = 0,
63
64    /// # Read
65    Read = 4,
66
67    /// # Write
68    Write = 2,
69
70    /// # Execute
71    Execute = 1,
72
73    /// # Read/Write
74    ReadWrite = Self::Read as isize | Self::Write as isize,
75
76    /// # Read/Execute
77    ReadExecute = Self::Read as isize | Self::Execute as isize,
78
79    /// # Write/Execute
80    WriteExecute = Self::Write as isize | Self::Execute as isize,
81
82    /// # Read/Write/Execute
83    ReadWriteExecute = Self::Read as isize | Self::Write as isize | Self::Execute as isize,
84
85}
86
87#[cfg(unix)]
88#[doc(cfg(unix))]
89impl Ord for Permissions {
90
91    fn cmp(&self, other: &Self) -> Ordering {
92        (*self as RawPermission).cmp(&(*other as RawPermission))
93    }
94
95}
96
97/// # File Permissions
98///
99/// ## Notes
100///
101/// Currently, only Unix is supported.
102///
103/// ## Examples
104///
105/// ```
106/// use dia_files::{FilePermissions, Permissions};
107///
108/// assert!(
109///     FilePermissions::new(Permissions::Read, Permissions::None, Permissions::None)
110///     < FilePermissions::new(Permissions::Read, Permissions::Read, Permissions::Read)
111/// );
112/// ```
113#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd)]
114pub struct FilePermissions {
115
116    #[cfg(unix)]
117    user: Permissions,
118    #[cfg(unix)]
119    group: Permissions,
120    #[cfg(unix)]
121    others: Permissions,
122
123    #[cfg(not(unix))]
124    lock: (),
125
126}
127
128impl FilePermissions {
129
130    /// # Makes new instance
131    #[cfg(unix)]
132    #[doc(cfg(unix))]
133    pub const fn new(user: Permissions, group: Permissions, others: Permissions) -> Self {
134        Self {
135            user,
136            group,
137            others,
138        }
139    }
140
141    /// # Makes new instance
142    #[cfg(not(unix))]
143    #[doc(cfg(not(unix)))]
144    pub const fn new() -> Self {
145        Self {
146            lock: (),
147        }
148    }
149
150    /// # User's permissions
151    #[cfg(unix)]
152    #[doc(cfg(unix))]
153    pub const fn user(&self) -> &Permissions {
154        &self.user
155    }
156
157    /// # Group's permissions
158    #[cfg(unix)]
159    #[doc(cfg(unix))]
160    pub const fn group(&self) -> &Permissions {
161        &self.group
162    }
163
164    /// # Others' permissions
165    #[cfg(unix)]
166    #[doc(cfg(unix))]
167    pub const fn others(&self) -> &Permissions {
168        &self.others
169    }
170
171    /// # Sets these permissions to a file
172    #[cfg(all(not(feature="async-std"), unix))]
173    #[doc(cfg(all(not(feature="async-std"), unix)))]
174    pub fn set<P>(&self, file: P) -> Result<()> where P: AsRef<Path> {
175        fs::set_permissions(file, self.into())
176    }
177
178    /// # Sets these permissions to a file
179    #[cfg(all(feature="async-std", unix))]
180    #[doc(cfg(all(feature="async-std", unix)))]
181    pub async fn set<P>(&self, file: P) -> Result<()> where P: AsRef<async_std::path::Path> {
182        async_std::fs::set_permissions(file, self.into()).await
183    }
184
185}
186
187#[cfg(unix)]
188#[doc(cfg(unix))]
189impl Ord for FilePermissions {
190
191    fn cmp(&self, other: &Self) -> Ordering {
192        RawPermission::from(self).cmp(&other.into())
193    }
194
195}
196
197#[cfg(unix)]
198macro_rules! impl_from_file_permissions_for_fs_permissions { ($($file_permissions: ty,)+) => {
199    $(
200        #[cfg(unix)]
201        #[doc(cfg(unix))]
202        impl From<$file_permissions> for fs::Permissions {
203
204            fn from(file_permissions: $file_permissions) -> Self {
205                Self::from_mode(file_permissions.into())
206            }
207
208        }
209    )+
210}}
211
212#[cfg(unix)]
213impl_from_file_permissions_for_fs_permissions! { &FilePermissions, FilePermissions, }
214
215#[cfg(unix)]
216#[doc(cfg(unix))]
217impl TryFrom<&fs::Permissions> for FilePermissions {
218
219    type Error = Error;
220
221    fn try_from(permissions: &fs::Permissions) -> Result<Self> {
222        let mode = permissions.mode();
223        Ok(Self::new(
224            Permissions::try_from(mode << 23 >> 29)?,
225            Permissions::try_from(mode << 26 >> 29)?,
226            Permissions::try_from(mode << 29 >> 29)?,
227        ))
228    }
229
230}
231
232#[cfg(unix)]
233#[doc(cfg(unix))]
234impl TryFrom<fs::Permissions> for FilePermissions {
235
236    type Error = Error;
237
238    fn try_from(permissions: fs::Permissions) -> Result<Self> {
239        Self::try_from(&permissions)
240    }
241
242}
243
244#[cfg(unix)]
245macro_rules! impl_try_from_metadata_for_file_permissions { ($($metadata: ty,)+) => {
246    $(
247        #[cfg(unix)]
248        #[doc(cfg(unix))]
249        impl TryFrom<$metadata> for FilePermissions {
250
251            type Error = Error;
252
253            fn try_from(metadata: $metadata) -> Result<Self> {
254                Self::try_from(&metadata.permissions())
255            }
256
257        }
258    )+
259}}
260
261#[cfg(unix)]
262impl_try_from_metadata_for_file_permissions! { &Metadata, Metadata, }
263
264#[cfg(unix)]
265macro_rules! impl_try_from_paths_for_file_permissions { ($($path: ty,)+) => {
266    $(
267        #[cfg(unix)]
268        #[doc(cfg(unix))]
269        impl TryFrom<$path> for FilePermissions {
270
271            type Error = Error;
272
273            fn try_from(path: $path) -> Result<Self> {
274                Self::try_from(&path.metadata()?.permissions())
275            }
276
277        }
278    )+
279}}
280
281#[cfg(unix)]
282impl_try_from_paths_for_file_permissions! { &Path, &PathBuf, PathBuf, }