#[cfg(unix)]
use {
core::cmp::Ordering,
std::{
fs::{self, Metadata},
io::Error,
os::unix::fs::PermissionsExt,
path::{Path, PathBuf},
},
crate::Result,
};
mod impls;
#[cfg(test)]
mod tests;
#[cfg(unix)]
#[doc(cfg(unix))]
pub type RawPermission = u32;
#[cfg(unix)]
#[doc(cfg(unix))]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd)]
pub enum Permissions {
None = 0,
Read = 4,
Write = 2,
Execute = 1,
ReadWrite = Self::Read as isize | Self::Write as isize,
ReadExecute = Self::Read as isize | Self::Execute as isize,
WriteExecute = Self::Write as isize | Self::Execute as isize,
ReadWriteExecute = Self::Read as isize | Self::Write as isize | Self::Execute as isize,
}
#[cfg(unix)]
#[doc(cfg(unix))]
impl Ord for Permissions {
fn cmp(&self, other: &Self) -> Ordering {
(*self as RawPermission).cmp(&(*other as RawPermission))
}
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd)]
pub struct FilePermissions {
#[cfg(unix)]
user: Permissions,
#[cfg(unix)]
group: Permissions,
#[cfg(unix)]
others: Permissions,
#[cfg(not(unix))]
lock: (),
}
impl FilePermissions {
#[cfg(unix)]
#[doc(cfg(unix))]
pub const fn new(user: Permissions, group: Permissions, others: Permissions) -> Self {
Self {
user,
group,
others,
}
}
#[cfg(not(unix))]
#[doc(cfg(not(unix)))]
pub const fn new() -> Self {
Self {
lock: (),
}
}
#[cfg(unix)]
#[doc(cfg(unix))]
pub const fn user(&self) -> &Permissions {
&self.user
}
#[cfg(unix)]
#[doc(cfg(unix))]
pub const fn group(&self) -> &Permissions {
&self.group
}
#[cfg(unix)]
#[doc(cfg(unix))]
pub const fn others(&self) -> &Permissions {
&self.others
}
#[cfg(all(not(feature="tokio"), unix))]
#[doc(cfg(all(not(feature="tokio"), unix)))]
pub fn set<P>(&self, file: P) -> Result<()> where P: AsRef<Path> {
fs::set_permissions(file, self.into())
}
#[cfg(all(feature="tokio", unix))]
#[doc(cfg(all(feature="tokio", unix)))]
pub async fn set<P>(&self, file: P) -> Result<()> where P: AsRef<Path> {
tokio::fs::set_permissions(file, self.into()).await
}
}
#[cfg(unix)]
#[doc(cfg(unix))]
impl Ord for FilePermissions {
fn cmp(&self, other: &Self) -> Ordering {
RawPermission::from(self).cmp(&other.into())
}
}
#[cfg(unix)]
macro_rules! impl_from_file_permissions_for_fs_permissions { ($($file_permissions: ty,)+) => {
$(
#[cfg(unix)]
#[doc(cfg(unix))]
impl From<$file_permissions> for fs::Permissions {
fn from(file_permissions: $file_permissions) -> Self {
Self::from_mode(file_permissions.into())
}
}
)+
}}
#[cfg(unix)]
impl_from_file_permissions_for_fs_permissions! { &FilePermissions, FilePermissions, }
#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<&fs::Permissions> for FilePermissions {
type Error = Error;
fn try_from(permissions: &fs::Permissions) -> Result<Self> {
let mode = permissions.mode();
Ok(Self::new(
Permissions::try_from(mode << 23 >> 29)?,
Permissions::try_from(mode << 26 >> 29)?,
Permissions::try_from(mode << 29 >> 29)?,
))
}
}
#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<fs::Permissions> for FilePermissions {
type Error = Error;
fn try_from(permissions: fs::Permissions) -> Result<Self> {
Self::try_from(&permissions)
}
}
#[cfg(unix)]
macro_rules! impl_try_from_metadata_for_file_permissions { ($($metadata: ty,)+) => {
$(
#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<$metadata> for FilePermissions {
type Error = Error;
fn try_from(metadata: $metadata) -> Result<Self> {
Self::try_from(&metadata.permissions())
}
}
)+
}}
#[cfg(unix)]
impl_try_from_metadata_for_file_permissions! { &Metadata, Metadata, }
#[cfg(unix)]
macro_rules! impl_try_from_paths_for_file_permissions { ($($path: ty,)+) => {
$(
#[cfg(unix)]
#[doc(cfg(unix))]
impl TryFrom<$path> for FilePermissions {
type Error = Error;
fn try_from(path: $path) -> Result<Self> {
Self::try_from(&path.metadata()?.permissions())
}
}
)+
}}
#[cfg(unix)]
impl_try_from_paths_for_file_permissions! { &Path, &PathBuf, PathBuf, }