1#[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#[cfg(unix)]
48#[doc(cfg(unix))]
49pub type RawPermission = u32;
50
51#[cfg(unix)]
57#[doc(cfg(unix))]
58#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd)]
59pub enum Permissions {
60
61    None = 0,
63
64    Read = 4,
66
67    Write = 2,
69
70    Execute = 1,
72
73    ReadWrite = Self::Read as isize | Self::Write as isize,
75
76    ReadExecute = Self::Read as isize | Self::Execute as isize,
78
79    WriteExecute = Self::Write as isize | Self::Execute as isize,
81
82    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#[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    #[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    #[cfg(not(unix))]
143    #[doc(cfg(not(unix)))]
144    pub const fn new() -> Self {
145        Self {
146            lock: (),
147        }
148    }
149
150    #[cfg(unix)]
152    #[doc(cfg(unix))]
153    pub const fn user(&self) -> &Permissions {
154        &self.user
155    }
156
157    #[cfg(unix)]
159    #[doc(cfg(unix))]
160    pub const fn group(&self) -> &Permissions {
161        &self.group
162    }
163
164    #[cfg(unix)]
166    #[doc(cfg(unix))]
167    pub const fn others(&self) -> &Permissions {
168        &self.others
169    }
170
171    #[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    #[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, }