cap_primitives/fs/
permissions.rs

1#[cfg(not(windows))]
2use crate::fs::ImplPermissionsExt;
3#[cfg(unix)]
4use rustix::fs::RawMode;
5use std::{fs, io};
6
7/// Representation of the various permissions on a file.
8///
9/// This corresponds to [`std::fs::Permissions`].
10///
11/// <details>
12/// We need to define our own version because the libstd `Permissions` doesn't
13/// have a public constructor that we can use.
14/// </details>
15#[derive(Debug, Clone, Eq, PartialEq)]
16pub struct Permissions {
17    pub(crate) readonly: bool,
18
19    #[cfg(any(unix, target_os = "vxworks"))]
20    pub(crate) ext: ImplPermissionsExt,
21}
22
23impl Permissions {
24    /// Constructs a new instance of `Self` from the given
25    /// `std::fs::Permissions`.
26    #[inline]
27    pub fn from_std(std: fs::Permissions) -> Self {
28        Self {
29            readonly: std.readonly(),
30
31            #[cfg(any(unix, target_os = "vxworks"))]
32            ext: ImplPermissionsExt::from_std(std),
33        }
34    }
35
36    /// Consumes `self` and produces a new instance of `std::fs::Permissions`.
37    ///
38    /// <details>
39    /// The `file` parameter works around the fact that we can't construct a
40    /// `Permissions` object ourselves on Windows.
41    /// </details>
42    #[inline]
43    pub fn into_std(self, file: &fs::File) -> io::Result<fs::Permissions> {
44        self._into_std(file)
45    }
46
47    #[cfg(unix)]
48    #[inline]
49    #[allow(clippy::unnecessary_wraps)]
50    fn _into_std(self, _file: &fs::File) -> io::Result<fs::Permissions> {
51        use std::os::unix::fs::PermissionsExt;
52        Ok(fs::Permissions::from_mode(crate::fs::PermissionsExt::mode(
53            &self.ext,
54        )))
55    }
56
57    #[cfg(target_os = "wasi")]
58    #[inline]
59    #[allow(clippy::unnecessary_wraps)]
60    fn _into_std(self, file: &fs::File) -> io::Result<fs::Permissions> {
61        let mut permissions = file.metadata()?.permissions();
62        permissions.set_readonly(self.readonly());
63        Ok(permissions)
64    }
65
66    #[cfg(windows)]
67    #[inline]
68    fn _into_std(self, file: &fs::File) -> io::Result<fs::Permissions> {
69        let mut permissions = file.metadata()?.permissions();
70        permissions.set_readonly(self.readonly());
71        Ok(permissions)
72    }
73
74    /// Returns `true` if these permissions describe a readonly (unwritable)
75    /// file.
76    ///
77    /// This corresponds to [`std::fs::Permissions::readonly`].
78    #[inline]
79    pub const fn readonly(&self) -> bool {
80        self.readonly
81    }
82
83    /// Modifies the readonly flag for this set of permissions.
84    ///
85    /// This corresponds to [`std::fs::Permissions::set_readonly`].
86    #[inline]
87    pub fn set_readonly(&mut self, readonly: bool) {
88        self.readonly = readonly;
89
90        #[cfg(any(unix, target_os = "vxworks"))]
91        self.ext.set_readonly(readonly);
92    }
93}
94
95/// Unix-specific extensions to [`Permissions`].
96#[cfg(unix)]
97pub trait PermissionsExt {
98    /// Returns the underlying raw `st_mode` bits that contain the standard
99    /// Unix permissions for this file.
100    fn mode(&self) -> u32;
101
102    /// Sets the underlying raw bits for this set of permissions.
103    fn set_mode(&mut self, mode: u32);
104
105    /// Creates a new instance of `Permissions` from the given set of Unix
106    /// permission bits.
107    fn from_mode(mode: u32) -> Self;
108}
109
110#[cfg(unix)]
111impl PermissionsExt for Permissions {
112    #[inline]
113    fn mode(&self) -> u32 {
114        crate::fs::PermissionsExt::mode(&self.ext)
115    }
116
117    #[inline]
118    fn set_mode(&mut self, mode: u32) {
119        crate::fs::PermissionsExt::set_mode(&mut self.ext, mode)
120    }
121
122    #[inline]
123    fn from_mode(mode: u32) -> Self {
124        Self {
125            readonly: ImplPermissionsExt::readonly(mode as RawMode),
126            ext: crate::fs::PermissionsExt::from_mode(mode),
127        }
128    }
129}
130
131#[cfg(target_os = "vxworks")]
132impl PermissionsExt for Permissions {
133    #[inline]
134    fn mode(&self) -> u32 {
135        self.ext.mode()
136    }
137
138    #[inline]
139    fn set_mode(&mut self, mode: u32) {
140        self.ext.set_mode(mode)
141    }
142
143    #[inline]
144    fn from_mode(mode: u32) -> Self {
145        Self {
146            readonly: ImplPermissionsExt::readonly(mode),
147            ext: ImplPermissionsExt::from(mode),
148        }
149    }
150}