use crate::{Mode, User, Protection, ProtectionBit, Special, SpecialBit};
use std::str::FromStr;
use std::iter::Peekable;
use std::str::Chars;
use std::num::ParseIntError;
use std::fmt::{self, Display};
use std::error::Error;
#[derive(Debug)]
pub enum ModeParseError {
UnexpectedChar(&'static str, char),
UnexpectedEnd(&'static str),
OctalParseError(ParseIntError),
}
impl Display for ModeParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ModeParseError::*;
match self {
UnexpectedChar(expected, c) => write!(f, "unexpected character '{}', expected: {}", c, expected),
UnexpectedEnd(expected) => write!(f, "unexpected end of string, expected: {}", expected),
OctalParseError(_) => write!(f, "failed to parse octal value"),
}
}
}
impl Error for ModeParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use ModeParseError::*;
match self {
UnexpectedChar(_, _) => None,
UnexpectedEnd(_) => None,
OctalParseError(err) => Some(err),
}
}
}
#[derive(Debug)]
struct Users(Vec<User>);
impl Users {
fn parse(chars: &mut Peekable<Chars>) -> Users {
use User::*;
let mut users = Vec::new();
loop {
match chars.peek() {
Some('u') => { users.push(Owner); },
Some('g') => { users.push(Group); },
Some('o') => { users.push(Other); },
Some('a') => {
users.push(Owner);
users.push(Group);
users.push(Other);
}
_ => return Users(users)
}
chars.next();
}
}
}
#[derive(Debug)]
enum Operator {
Add,
Sub,
Set,
}
impl Operator {
fn parse(chars: &mut Peekable<Chars>) -> Result<Operator, ModeParseError> {
use Operator::*;
let c = chars.next().ok_or(ModeParseError::UnexpectedEnd("operator"))?;
match c {
'-' => Ok(Sub),
'+' => Ok(Add),
'=' => Ok(Set),
c => Err(ModeParseError::UnexpectedChar("[-+=]", c))
}
}
}
#[derive(Debug)]
enum Bit {
Protection(ProtectionBit),
Special(SpecialBit),
}
impl Bit {
fn parse(chars: &mut Peekable<Chars>) -> Result<Bit, ModeParseError> {
use ProtectionBit::*;
use SpecialBit::*;
let c = chars.next().ok_or(ModeParseError::UnexpectedEnd("operator"))?;
match c {
'r' => Ok(Bit::Protection(Read)),
'w' => Ok(Bit::Protection(Write)),
'x' => Ok(Bit::Protection(Execute)),
'X' => Ok(Bit::Protection(Search)),
's' => Ok(Bit::Special(SetId)),
't' => Ok(Bit::Special(Sticky)),
c => Err(ModeParseError::UnexpectedChar("[rwxXst]", c))
}
}
}
#[derive(Debug)]
enum Value {
Bits(Vec<Bit>),
Source(User),
}
impl Value {
fn parse(chars: &mut Peekable<Chars>) -> Result<Value, ModeParseError> {
use Value::*;
use User::*;
if let Some(c) = chars.peek() {
let user = match c {
'u' => Some(Owner),
'g' => Some(Group),
'o' => Some(Other),
_ => None,
};
if let Some(user) = user {
chars.next();
Ok(Source(user))
} else {
let mut bits = Vec::new();
while chars.peek().is_some() {
bits.push(Bit::parse(chars).unwrap());
}
Ok(Value::Bits(bits))
}
} else {
Ok(Value::Bits(Vec::new()))
}
}
}
#[derive(Debug)]
struct Expression {
operator: Operator,
value: Value,
}
impl Expression {
fn parse(chars: &mut Peekable<Chars>) -> Result<Expression, ModeParseError> {
Ok(Expression {
operator: Operator::parse(chars)?,
value: Value::parse(chars)?,
})
}
}
#[derive(Debug)]
struct SymbolicMode {
users: Users,
expressions: Vec<Expression>,
}
impl SymbolicMode {
fn parse(chars: &mut Peekable<Chars>) -> Result<SymbolicMode, ModeParseError> {
let users = Users::parse(chars);
let mut expressions = Vec::new();
loop {
if chars.peek().is_none() {
break
}
expressions.push(Expression::parse(chars)?);
}
if expressions.is_empty() {
Err(ModeParseError::UnexpectedEnd("bits or user flags"))
} else {
Ok(SymbolicMode {
users,
expressions,
})
}
}
}
#[derive(Debug)]
struct OctalMode {
operator: Operator,
mode: Mode,
}
impl OctalMode {
fn parse(chars: &mut Peekable<Chars>) -> Result<OctalMode, ModeParseError> {
let operator = Operator::parse(chars)?;
let mut mode = String::new();
for c in chars {
match c {
c @ '0'..='7' => mode.push(c),
c => return Err(ModeParseError::UnexpectedChar("[0-7]", c)),
}
}
if mode.is_empty() {
mode.push('0')
}
let mode = u32::from_str_radix(&mode, 8).map_err(ModeParseError::OctalParseError)?;
Ok(OctalMode {
operator,
mode: Mode::new(mode, 0o7777),
})
}
}
#[derive(Debug)]
enum ModeString {
Symbolic(SymbolicMode),
Octal(OctalMode),
}
impl FromStr for ModeString {
type Err = ModeParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut chars = s.chars().peekable();
let mode_string = if s.ends_with(|c| ('0'..='7').contains(&c)) {
ModeString::Octal(OctalMode::parse(&mut chars)?)
} else {
ModeString::Symbolic(SymbolicMode::parse(&mut chars)?)
};
if let Some(c) = chars.next() {
Err(ModeParseError::UnexpectedChar("no more characters", c))
} else {
Ok(mode_string)
}
}
}
impl ModeString {
fn into_operations(self, ref_mode: u32, umask: u32) -> Vec<(Operator, Mode)> {
let mut ops = Vec::new();
match self {
ModeString::Symbolic(symbolic) => {
let (users, umask) = if symbolic.users.0.is_empty() {
(vec![User::Owner, User::Group, User::Other], umask)
} else {
(symbolic.users.0, 0o0)
};
for expr in symbolic.expressions {
let mut mode = Mode::empty();
let mut protection = match &expr.operator {
Operator::Set => Protection::all_clear(), _ => Protection::empty(),
};
let mut special = Special::empty();
match expr.value {
Value::Bits(bits) => for bit in bits {
match bit {
Bit::Protection(protection_bit) => protection.set(protection_bit),
Bit::Special(special_bit) => special.set(special_bit),
}
}
Value::Source(source_user) => {
let mask = match &expr.operator {
Operator::Set => 0o777, _ => ref_mode, };
let mut ref_mode = Mode::new(ref_mode, mask);
ref_mode.set(&mode);
protection = ref_mode.user_protection(source_user);
}
}
for user in &users {
mode.set_protection(*user, &protection);
mode.set_special(*user, &special);
}
mode.apply_umask(umask);
ops.push((expr.operator, mode));
}
}
ModeString::Octal(OctalMode { operator, mode }) => ops.push((operator, mode)),
}
ops
}
}
pub(crate) fn mode_set_from_str(mode: &mut Mode, mode_str: &str, umask: u32) -> Result<(), ModeParseError> {
for mode_str in mode_str.split(',') {
set(mode, mode_str, umask)?;
}
Ok(())
}
fn set(target: &mut Mode, mode_str: &str, umask: u32) -> Result<(), ModeParseError> {
let ms = ModeString::from_str(mode_str)?;
for (operator, mode) in ms.into_operations(target.mode, umask) {
match operator {
Operator::Add => target.add(&mode),
Operator::Sub => target.sub(&mode),
Operator::Set => target.set(&mode),
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn test_parse_users() {
use User::*;
let mut i = "a".chars().peekable();
assert_eq!(Users::parse(&mut i).0, vec![Owner, Group, Other]);
assert!(i.next().is_none());
let mut i = "uog".chars().peekable();
assert_eq!(Users::parse(&mut i).0, vec![Owner, Other, Group]);
assert!(i.next().is_none());
let mut i = "uxog".chars().peekable();
assert_eq!(Users::parse(&mut i).0, vec![Owner]);
assert_eq!(&i.collect::<String>(), "xog");
let mut i = "uoxg".chars().peekable();
assert_eq!(Users::parse(&mut i).0, vec![Owner, Other]);
assert_eq!(&i.collect::<String>(), "xg");
let mut i = "uogx".chars().peekable();
assert_eq!(Users::parse(&mut i).0, vec![Owner, Other, Group]);
assert_eq!(&i.collect::<String>(), "x");
}
#[test]
fn test_parse_value() {
use ProtectionBit::*;
use SpecialBit::*;
let mut i = "".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Bits(bits) => {
assert!(bits.is_empty());
});
assert!(i.next().is_none());
let mut i = "rwxst".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Bits(bits) => {
let mut b = bits.into_iter();
assert_matches!(b.next().unwrap(), Bit::Protection(Read));
assert_matches!(b.next().unwrap(), Bit::Protection(Write));
assert_matches!(b.next().unwrap(), Bit::Protection(Execute));
assert_matches!(b.next().unwrap(), Bit::Special(SetId));
assert_matches!(b.next().unwrap(), Bit::Special(Sticky));
assert!(b.next().is_none());
});
assert!(i.next().is_none());
let mut i = "xw".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Bits(bits) => {
let mut b = bits.into_iter();
assert_matches!(b.next().unwrap(), Bit::Protection(Execute));
assert_matches!(b.next().unwrap(), Bit::Protection(Write));
assert!(b.next().is_none());
});
assert!(i.next().is_none());
let mut i = "u".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Source(User::Owner));
assert!(i.next().is_none());
let mut i = "g".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Source(User::Group));
assert!(i.next().is_none());
let mut i = "o".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Source(User::Other));
assert!(i.next().is_none());
let mut i = "oo?".chars().peekable();
assert_matches!(Value::parse(&mut i).unwrap(), Value::Source(User::Other));
assert_eq!(i.next(), Some('o'));
}
#[test]
fn test_parse_symbolic_mode() {
use User::*;
let mut i = "u+r".chars().peekable();
assert_matches!(SymbolicMode::parse(&mut i).unwrap(), SymbolicMode { users, expressions } => {
assert_eq!(users.0, vec![Owner]);
let mut e = expressions.into_iter();
assert_matches!(e.next().unwrap(), Expression { operator: Operator::Add, value } => {
assert_matches!(value, Value::Bits(bits) => {
let mut b = bits.into_iter();
assert_matches!(b.next().unwrap(), Bit::Protection(ProtectionBit::Read));
assert!(b.next().is_none());
});
});
assert!(e.next().is_none());
});
assert!(i.next().is_none());
let mut i = "=rs".chars().peekable();
assert_matches!(SymbolicMode::parse(&mut i).unwrap(), SymbolicMode { users, expressions } => {
assert_eq!(users.0, vec![]);
let mut e = expressions.into_iter();
assert_matches!(e.next().unwrap(), Expression { operator: Operator::Set, value } => {
assert_matches!(value, Value::Bits(bits) => {
let mut b = bits.into_iter();
assert_matches!(b.next().unwrap(), Bit::Protection(ProtectionBit::Read));
assert_matches!(b.next().unwrap(), Bit::Special(SpecialBit::SetId));
assert!(b.next().is_none());
});
});
assert!(e.next().is_none());
});
assert!(i.next().is_none());
let mut i = "a=u".chars().peekable();
assert_matches!(SymbolicMode::parse(&mut i).unwrap(), SymbolicMode { users, expressions } => {
assert_eq!(users.0, vec![Owner, Group, Other]);
let mut e = expressions.into_iter();
assert_matches!(e.next().unwrap(), Expression { operator: Operator::Set, value } => {
assert_matches!(value, Value::Source(Owner));
});
assert!(e.next().is_none());
});
assert!(i.next().is_none());
}
#[test]
fn test_parse_octal_mode() {
let mut i = "=777".chars().peekable();
assert_matches!(OctalMode::parse(&mut i).unwrap(), OctalMode { operator: Operator::Set, mode } => {
assert_eq!(mode, Mode::new(0o777, 0o7777));
});
assert!(i.next().is_none());
let mut i = "-7".chars().peekable();
assert_matches!(OctalMode::parse(&mut i).unwrap(), OctalMode { operator: Operator::Sub, mode } => {
assert_eq!(mode, Mode::new(0o007, 0o7777));
});
assert!(i.next().is_none());
let mut i = "+23".chars().peekable();
assert_matches!(OctalMode::parse(&mut i).unwrap(), OctalMode { operator: Operator::Add, mode } => {
assert_eq!(mode, Mode::new(0o023, 0o7777));
});
assert!(i.next().is_none());
let mut i = "+023".chars().peekable();
assert_matches!(OctalMode::parse(&mut i).unwrap(), OctalMode { operator: Operator::Add, mode } => {
assert_eq!(mode, Mode::new(0o023, 0o7777));
});
assert!(i.next().is_none());
let mut i = "=".chars().peekable();
assert_matches!(OctalMode::parse(&mut i).unwrap(), OctalMode { operator: Operator::Set, mode } => {
assert_eq!(mode, Mode::new(0o000, 0o7777));
});
assert!(i.next().is_none());
}
}