New trait Mode, currently just prints the symbolic representation of a

Unix mode, as extracted from u32
This commit is contained in:
Nathan Fisher 2023-01-16 22:30:12 -05:00
parent 97d4fe1947
commit 1ff61def39
2 changed files with 127 additions and 2 deletions

View File

@ -1,15 +1,21 @@
//! Functions for parsing and managing permissions
mod parser;
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
use std::{
fmt::{self, Write},
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
};
pub use parser::{ParseError, Parser};
/// Gets the umask for the current user
#[must_use]
pub fn get_umask() -> u32 {
let mask = unsafe { libc::umask(0) };
unsafe { libc::umask(mask) }
let _mask = unsafe { libc::umask(mask) };
mask
}
/// Unix permission bit flags
#[derive(Clone, Copy, PartialEq)]
pub enum Bit {
Suid = 0o4000,
@ -26,6 +32,61 @@ pub enum Bit {
OExec = 0o1,
}
impl Bit {
fn as_char(&self, mode: u32) -> char {
if mode & *self != 0 {
match self {
Self::Suid | Self::Sgid => 's',
Self::Sticky => 't',
Self::URead | Self::GRead | Self::ORead => 'r',
Self::UWrite | Self::GWrite | Self::OWrite => 'w',
Self::UExec if mode & Self::Suid != 0 => 's',
Self::GExec if mode & Self::Sgid != 0 => 's',
Self::OExec if mode & Self::Sticky != 0 => 't',
Self::UExec | Self::GExec | Self::OExec => 'x',
}
} else {
'-'
}
}
}
/// Functions for extracting information about Unix modes
pub trait Mode {
/// Returns a string representing permissions in symbolic format
fn mode_string(&self) -> Result<String, fmt::Error>;
}
impl Mode for u32 {
fn mode_string(&self) -> Result<String, fmt::Error> {
let b = if self & 0o40000 != 0 && self & 0o20000 != 0 {
'b'
} else if self & 0o40000 != 0 {
'd'
} else if self & 0o20000 != 0 {
'c'
} else {
'-'
};
let mut s = String::new();
write!(s, "{b}")?;
[
Bit::URead,
Bit::UWrite,
Bit::UExec,
Bit::GRead,
Bit::GWrite,
Bit::GExec,
Bit::ORead,
Bit::OWrite,
Bit::OExec,
]
.iter()
.try_for_each(|b| write!(s, "{}", b.as_char(*self)))?;
Ok(s)
}
}
impl BitAnd<u32> for Bit {
type Output = u32;
@ -69,3 +130,66 @@ impl BitOrAssign<Bit> for u32 {
*self = *self | rhs;
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn getumask() {
let mask = unsafe { libc::umask(0o22) };
assert_eq!(get_umask(), 0o022);
unsafe {
libc::umask(mask);
}
}
#[test]
fn display_bits_dir() {
let m: u32 = 0o40755;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "drwxr-xr-x")
}
#[test]
fn display_bits_char() {
let m: u32 = 0o20666;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "crw-rw-rw-")
}
#[test]
fn display_bits_block() {
let m: u32 = 0o60660;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "brw-rw----")
}
#[test]
fn display_bits_file() {
let m: u32 = 0o100644;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "-rw-r--r--")
}
#[test]
fn display_bits_suid() {
let m: u32 = 0o104755;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "-rwsr-xr-x")
}
#[test]
fn display_bits_sgid() {
let m: u32 = 0o102755;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "-rwxr-sr-x")
}
#[test]
fn display_bits_sticky() {
let m: u32 = 0o41777;
let s = m.mode_string().unwrap();
assert_eq!(s.as_str(), "drwxrwxrwt")
}
}

View File

@ -6,6 +6,7 @@ use std::{
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
};
/// Errors which might occur when parsing Unix permissions from a string
#[derive(Debug, PartialEq)]
pub enum ParseError {
/// the given `Bit` cannot be set for the given `Who`