vahanafs/src/fs/permission.rs
2025-03-01 04:51:23 -06:00

455 lines
11 KiB
Rust

use char_enum::{char_enum_derive::FromChar, AsIter, FromChar, FromStrError, ToChar};
use enumflags2::{bitflags, BitFlag, BitFlags, FromBitsError};
use std::{error::Error, fmt::Display, num::ParseIntError, ops::BitOr, str::FromStr};
use crate::utils::MapWhileRefExt;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseModeError(String);
impl ParseModeError {
pub fn from_bits(bits: &str) -> Self {
Self(format!("invalid mode: `{bits}`"))
}
}
impl Display for ParseModeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for ParseModeError {}
impl From<ParseIntError> for ParseModeError {
fn from(value: ParseIntError) -> Self {
Self(value.to_string())
}
}
impl From<FromBitsError<Mode>> for ParseModeError {
fn from(value: FromBitsError<Mode>) -> Self {
Self::from_bits(&value.invalid_bits().to_string())
}
}
#[bitflags]
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Mode {
IXOTH = 0x0001,
IWOTH = 0x0002,
IROTH = 0x0004,
IXGRP = 0x0010,
IWGRP = 0x0020,
IRGRP = 0x0040,
IXUSR = 0x0100,
IWUSR = 0x0200,
IRUSR = 0x0400,
ISVTX = 0x1000,
ISGID = 0x2000,
ISUID = 0x4000,
}
impl Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ModeFlags(BitFlags<Mode>);
impl FromStr for ModeFlags {
type Err = ParseModeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bits = u16::from_str_radix(s, 16)?;
Ok(Self(BitFlags::from_bits(bits)?))
}
}
impl Display for ModeFlags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:X}", self.0)
}
}
impl TryFrom<u16> for ModeFlags {
type Error = FromBitsError<Mode>;
fn try_from(value: u16) -> Result<Self, Self::Error> {
Ok(Self(BitFlags::from_bits(value)?))
}
}
impl From<BitFlags<Mode>> for ModeFlags {
fn from(value: BitFlags<Mode>) -> Self {
Self(value)
}
}
#[derive(Clone, Copy, Debug, FromChar, PartialEq, Eq)]
pub enum Operator {
#[value = "-"]
Sub,
#[value = "+"]
Add,
#[value = "="]
Eq,
}
impl Operator {
pub fn split(s: &str) -> Option<(&str, char, &str)> {
let mut result = None;
for d in Operator::iter() {
if let Some((a, b)) = s.split_once(d) {
result = Some((a, d, b));
break;
}
}
result
}
}
#[bitflags]
#[repr(u8)]
#[derive(Clone, Copy, Debug, FromChar, PartialEq, Eq)]
pub enum SymbolicMode {
#[value = 'r']
Read,
#[value = 'w']
Write,
#[value = 'x']
Execute,
#[value = 'X']
Search,
#[value = 's']
SetId,
#[value = 't']
Sticky,
}
#[bitflags]
#[repr(u8)]
#[derive(Clone, Copy, Debug, FromChar, PartialEq, Eq)]
pub enum GroupId {
#[value = 'u']
User,
#[value = 'g']
Group,
#[value = 'o']
Other,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Modes<T: BitFlag>(BitFlags<T>);
impl<T: BitFlag> Default for Modes<T> {
fn default() -> Self {
Modes(BitFlags::<T>::default())
}
}
impl<T: BitFlag + FromChar> FromStr for Modes<T> {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let flags = s
.chars()
.map_while_ref(|c: &char| T::from_char(*c))
.fold(BitFlags::default(), BitOr::bitor);
Ok(Self(flags))
}
}
impl<T: BitFlag + Display> Display for Modes<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iter = self.0.iter();
if let Some(head) = iter.next() {
write!(f, "{head}")?;
for item in iter {
write!(f, "{item}")?;
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ParseSymbolicArgsError(FromStrError);
impl Display for ParseSymbolicArgsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for ParseSymbolicArgsError {}
impl From<ParseSymbolicArgsError> for FromStrError {
fn from(value: ParseSymbolicArgsError) -> Self {
value.0
}
}
impl From<FromStrError> for ParseSymbolicArgsError {
fn from(value: FromStrError) -> Self {
Self(value)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SymbolicArgs {
Group(Modes<GroupId>),
Mode(Modes<SymbolicMode>),
}
impl FromStr for SymbolicArgs {
type Err = ParseSymbolicArgsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match Modes::<SymbolicMode>::from_str(s) {
Ok(perms) => Ok(Self::Mode(perms)),
Err(_) => match Modes::<GroupId>::from_str(s) {
Ok(perms) => Ok(Self::Group(perms)),
Err(_) => Err(FromStrError::new(format!("{} is not a valid argument", s)).into()),
},
}
}
}
impl Display for SymbolicArgs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SymbolicArgs::Group(modes) => write!(f, "{modes}"),
SymbolicArgs::Mode(modes) => write!(f, "{modes}"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParseSymbolicError {
Group(String),
Operator(String),
Mode(String),
}
impl Display for ParseSymbolicError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Group(e) => e,
Self::Operator(e) => e,
Self::Mode(e) => e,
}
)
}
}
impl Error for ParseSymbolicError {}
impl From<ParseSymbolicArgsError> for ParseSymbolicError {
fn from(value: ParseSymbolicArgsError) -> Self {
Self::Mode(value.to_string())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SymbolicPermissions {
groups: Modes<GroupId>,
operator: Operator,
mode: SymbolicArgs,
}
impl SymbolicPermissions {
pub fn new(groups: Modes<GroupId>, operator: Operator, mode: SymbolicArgs) -> Self {
Self {
groups,
operator,
mode,
}
}
}
impl FromStr for SymbolicPermissions {
type Err = ParseSymbolicError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match Operator::split(s) {
Some((groups, operator, mode)) => {
let groups =
Modes::from_str(groups).map_err(|e| ParseSymbolicError::Group(e.to_string()));
let operator = Operator::from_char(operator)
.map_err(|o| ParseSymbolicError::Operator(o.to_string()));
let mode = SymbolicArgs::from_str(mode)?;
Ok(Self::new(groups?, operator?, mode))
}
None => Err(ParseSymbolicError::Operator(format!(
"received invalid permission syntax: {s}"
))),
}
}
}
impl Display for SymbolicPermissions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}{}", self.groups, self.operator, self.mode)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseOctalError(String);
impl Display for ParseOctalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for ParseOctalError {}
impl From<ParseModeError> for ParseOctalError {
fn from(value: ParseModeError) -> Self {
Self(value.0)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OctalPermissions(ModeFlags);
impl Display for OctalPermissions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for OctalPermissions {
type Err = ParseOctalError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(ModeFlags::from_str(s)?))
}
}
impl TryFrom<u16> for OctalPermissions {
type Error = FromBitsError<Mode>;
fn try_from(value: u16) -> Result<Self, Self::Error> {
Ok(Self(ModeFlags::try_from(value)?))
}
}
impl From<BitFlags<Mode>> for OctalPermissions {
fn from(value: BitFlags<Mode>) -> Self {
Self(value.into())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParsePermissionsError {
Symbolic(ParseSymbolicError),
Octal(ParseOctalError),
}
impl Display for ParsePermissionsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParsePermissionsError::Symbolic(e) => write!(f, "{e}"),
ParsePermissionsError::Octal(e) => write!(f, "{e}"),
}
}
}
impl Error for ParsePermissionsError {}
impl From<ParseSymbolicError> for ParsePermissionsError {
fn from(value: ParseSymbolicError) -> Self {
Self::Symbolic(value)
}
}
impl From<ParseOctalError> for ParsePermissionsError {
fn from(value: ParseOctalError) -> Self {
Self::Octal(value)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Permissions {
Symbolic(SymbolicPermissions),
Octal(OctalPermissions),
}
impl FromStr for Permissions {
type Err = ParsePermissionsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(SymbolicPermissions::from_str(s)
.map(Self::Symbolic)
.or_else(|_| OctalPermissions::from_str(s).map(Self::Octal))?)
}
}
impl Display for Permissions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Permissions::Symbolic(v) => write!(f, "{v}"),
Permissions::Octal(v) => write!(f, "{v}"),
}
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use enumflags2::BitFlags;
use crate::fs::permission::{
GroupId, Modes, Operator, SymbolicArgs, SymbolicMode, SymbolicPermissions,
};
use super::{ModeFlags, Permissions};
#[test]
fn mode_flags() {
let flags = ModeFlags(BitFlags::all());
assert_eq!(flags.to_string(), "7777");
}
#[test]
fn symbolic_permissions() {
let sym = Permissions::from_str("ug+w").unwrap();
let group_sym = Permissions::from_str("g=u").unwrap();
assert_eq!(
sym,
Permissions::Symbolic(SymbolicPermissions::new(
Modes(GroupId::User | GroupId::Group),
Operator::Add,
SymbolicArgs::Mode(Modes(BitFlags::from(SymbolicMode::Write)))
))
);
assert_eq!(
group_sym,
Permissions::Symbolic(SymbolicPermissions::new(
Modes(GroupId::Group.into()),
Operator::Eq,
SymbolicArgs::Group(Modes(BitFlags::from(GroupId::User)))
))
);
}
}