From 962a9c53b67dba2fb0405c1c6a75adb5c3eb5113 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Sun, 15 Jan 2023 12:10:36 -0500 Subject: [PATCH] mode: move Parser into separate module --- src/mode/mod.rs | 312 +-------------------------------------------- src/mode/parser.rs | 310 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+), 310 deletions(-) create mode 100644 src/mode/parser.rs diff --git a/src/mode/mod.rs b/src/mode/mod.rs index d250d67..b07b61a 100644 --- a/src/mode/mod.rs +++ b/src/mode/mod.rs @@ -1,6 +1,6 @@ //! Functions for parsing and managing permissions - -use std::{error, fmt::Display, num::ParseIntError}; +mod parser; +pub use parser::{Parser, ParseError}; pub fn get_umask() -> u32 { let mask = unsafe { libc::umask(0) }; @@ -23,311 +23,3 @@ pub enum Bit { OWrite = 0o2, OExec = 0o1, } - -#[derive(Debug, PartialEq)] -pub enum ParseError { - InvalidBit, - InvalidDigit, - OutsideRange, - ParseIntError(ParseIntError), - NoOpSet, -} - -impl Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self:?}") - } -} - -impl error::Error for ParseError {} - -impl From for ParseError { - fn from(value: ParseIntError) -> Self { - Self::ParseIntError(value) - } -} - -#[derive(Debug, PartialEq)] -enum Op { - Add, - Remove, - Equals, -} - -#[derive(Clone, Debug, PartialEq)] -enum Who { - User, - Group, - Other, - All, -} - -pub struct Parser { - mode: u32, - op: Option, - who: Vec, - bits: Vec, -} - -impl Default for Parser { - fn default() -> Self { - let umask = get_umask(); - let mut mode = 0o0777; - mode &= umask; - Self { - mode, - op: None, - who: vec![], - bits: vec![], - } - } -} - -impl Parser { - pub fn new(mode: u32) -> Self { - Self { - mode, - op: None, - who: vec![], - bits: vec![], - } - } - - fn parse_octal(&mut self, value: &str) -> Result { - let m = u32::from_str_radix(value, 8)?; - if m <= 0o7777 { - Ok(m) - } else { - Err(ParseError::OutsideRange) - } - } - - fn add_who(&mut self, who: Who) -> Result<(), ParseError> { - if self.op.is_some() || self.who.contains(&who) || !self.bits.is_empty() { - Err(ParseError::InvalidDigit) - } else { - self.who.push(who); - Ok(()) - } - } - - fn set_op(&mut self, op: Op) -> Result<(), ParseError> { - if self.op.is_some() || !self.bits.is_empty() { - Err(ParseError::InvalidDigit) - } else { - self.op = Some(op); - Ok(()) - } - } - - fn push_bit(&mut self, bit: char) -> Result<(), ParseError> { - match self.op { - Some(_) => if self.bits.contains(&bit) { - return Err(ParseError::InvalidDigit); - } else { - self.bits.push(bit); - }, - None => return Err(ParseError::NoOpSet), - } - Ok(()) - } - - fn push_suid(&mut self) -> Result<(), ParseError> { - for w in &self.who { - if w == &Who::All || w == &Who::Other { - return Err(ParseError::InvalidBit); - } - } - if self.who.is_empty() { - return Err(ParseError::InvalidBit); - } - self.push_bit('s') - } - - fn push_sticky(&mut self) -> Result<(), ParseError> { - for w in &self.who { - if w == &Who::All || w == &Who::User || w == &Who::Group { - return Err(ParseError::InvalidBit); - } - } - if self.who.is_empty() { - return Err(ParseError::InvalidBit); - } - self.push_bit('t') - } - - fn add_user_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode |= Bit::URead as u32, - 'w' => self.mode |= Bit::UWrite as u32, - 'x' => self.mode |= Bit::UExec as u32, - 's' => self.mode |= Bit::Suid as u32, - _ => unreachable!(), - } - } - } - - fn remove_user_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode &= Bit::URead as u32, - 'w' => self.mode &= Bit::UWrite as u32, - 'x' => self.mode &= Bit::UExec as u32, - 's' => self.mode &= Bit::Suid as u32, - _ => unreachable!(), - } - } - } - - fn zero_user_bits(&mut self) { - self.mode &= 0o4444; - } - - fn set_user_bits(&mut self) { - match self.op { - Some(Op::Add) => self.add_user_bits(), - Some(Op::Remove) => self.remove_user_bits(), - Some(Op::Equals) => { - self.zero_user_bits(); - self.add_user_bits(); - }, - None => {}, - } - } - - fn add_group_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode |= Bit::GRead as u32, - 'w' => self.mode |= Bit::GWrite as u32, - 'x' => self.mode |= Bit::GExec as u32, - 's' => self.mode |= Bit::Sgid as u32, - _ => unreachable!(), - } - } - } - - fn remove_group_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode &= Bit::GRead as u32, - 'w' => self.mode &= Bit::GWrite as u32, - 'x' => self.mode &= Bit::GExec as u32, - 's' => self.mode &= Bit::Sgid as u32, - _ => unreachable!(), - } - } - } - - fn zero_group_bits(&mut self) { - self.mode &= 0o2222; - } - - fn set_group_bits(&mut self) { - match self.op { - Some(Op::Add) => self.add_group_bits(), - Some(Op::Remove) => self.remove_group_bits(), - Some(Op::Equals) => { - self.zero_group_bits(); - self.add_group_bits(); - }, - None => {}, - } - } - - fn add_other_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode |= Bit::ORead as u32, - 'w' => self.mode |= Bit::OWrite as u32, - 'x' => self.mode |= Bit::OExec as u32, - 't' => self.mode |= Bit::Sticky as u32, - _ => unreachable!(), - } - } - } - - fn remove_other_bits(&mut self) { - for b in &self.bits { - match b { - 'r' => self.mode &= Bit::ORead as u32, - 'w' => self.mode &= Bit::OWrite as u32, - 'x' => self.mode &= Bit::OExec as u32, - 's' => self.mode &= Bit::Sticky as u32, - _ => unreachable!(), - } - } - } - - fn zero_other_bits(&mut self) { - self.mode &= 0o1111; - } - - fn set_other_bits(&mut self) { - match self.op { - Some(Op::Add) => self.add_other_bits(), - Some(Op::Remove) => self.remove_other_bits(), - Some(Op::Equals) => { - self.zero_other_bits(); - self.add_other_bits(); - }, - None => {}, - } - } - - fn set_bits(&mut self) { - for w in self.who.clone() { - match w { - Who::User => self.set_user_bits(), - Who::Group => self.set_group_bits(), - Who::Other => self.set_other_bits(), - Who::All => { - self.set_user_bits(); - self.set_group_bits(); - self.set_other_bits(); - } - } - } - } - - fn reset(&mut self) { - self.who.clear(); - self.op = None; - self.bits.clear(); - } - - pub fn mode(&self) -> u32 { - self.mode - } - - pub fn parse(&mut self, value: &str) -> Result { - match self.parse_octal(value) { - Ok(mode) => { - self.mode = mode; - return Ok(mode) - }, - Err(e) => if e == ParseError::OutsideRange { - return Err(e); - } - } - for c in value.chars() { - match c { - 'u' => self.add_who(Who::User)?, - 'g' => self.add_who(Who::Group)?, - 'o' => self.add_who(Who::Other)?, - 'a' => self.add_who(Who::All)?, - '-' => self.set_op(Op::Remove)?, - '+' => self.set_op(Op::Add)?, - '=' => self.set_op(Op::Equals)?, - 'r' | 'w' | 'x' => self.push_bit(c)?, - 's' => self.push_suid()?, - 't' => self.push_sticky()?, - _ => return Err(ParseError::InvalidDigit), - } - } - self.set_bits(); - self.reset(); - Ok(self.mode) - } -} diff --git a/src/mode/parser.rs b/src/mode/parser.rs new file mode 100644 index 0000000..7a5ad18 --- /dev/null +++ b/src/mode/parser.rs @@ -0,0 +1,310 @@ +use std::{error, fmt::Display, num::ParseIntError}; +use super::{Bit, get_umask}; + +#[derive(Debug, PartialEq)] +pub enum ParseError { + InvalidBit, + InvalidDigit, + OutsideRange, + ParseIntError(ParseIntError), + NoOpSet, +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl error::Error for ParseError {} + +impl From for ParseError { + fn from(value: ParseIntError) -> Self { + Self::ParseIntError(value) + } +} + +#[derive(Debug, PartialEq)] +enum Op { + Add, + Remove, + Equals, +} + +#[derive(Clone, Debug, PartialEq)] +enum Who { + User, + Group, + Other, + All, +} + +pub struct Parser { + mode: u32, + op: Option, + who: Vec, + bits: Vec, +} + +impl Default for Parser { + fn default() -> Self { + let umask = get_umask(); + let mut mode = 0o0777; + mode &= umask; + Self { + mode, + op: None, + who: vec![], + bits: vec![], + } + } +} + +impl Parser { + pub fn new(mode: u32) -> Self { + Self { + mode, + op: None, + who: vec![], + bits: vec![], + } + } + + fn parse_octal(&mut self, value: &str) -> Result { + let m = u32::from_str_radix(value, 8)?; + if m <= 0o7777 { + Ok(m) + } else { + Err(ParseError::OutsideRange) + } + } + + fn add_who(&mut self, who: Who) -> Result<(), ParseError> { + if self.op.is_some() || self.who.contains(&who) || !self.bits.is_empty() { + Err(ParseError::InvalidDigit) + } else { + self.who.push(who); + Ok(()) + } + } + + fn set_op(&mut self, op: Op) -> Result<(), ParseError> { + if self.op.is_some() || !self.bits.is_empty() { + Err(ParseError::InvalidDigit) + } else { + self.op = Some(op); + Ok(()) + } + } + + fn push_bit(&mut self, bit: char) -> Result<(), ParseError> { + match self.op { + Some(_) => if self.bits.contains(&bit) { + return Err(ParseError::InvalidDigit); + } else { + self.bits.push(bit); + }, + None => return Err(ParseError::NoOpSet), + } + Ok(()) + } + + fn push_suid(&mut self) -> Result<(), ParseError> { + for w in &self.who { + if w == &Who::All || w == &Who::Other { + return Err(ParseError::InvalidBit); + } + } + if self.who.is_empty() { + return Err(ParseError::InvalidBit); + } + self.push_bit('s') + } + + fn push_sticky(&mut self) -> Result<(), ParseError> { + for w in &self.who { + if w == &Who::All || w == &Who::User || w == &Who::Group { + return Err(ParseError::InvalidBit); + } + } + if self.who.is_empty() { + return Err(ParseError::InvalidBit); + } + self.push_bit('t') + } + + fn add_user_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode |= Bit::URead as u32, + 'w' => self.mode |= Bit::UWrite as u32, + 'x' => self.mode |= Bit::UExec as u32, + 's' => self.mode |= Bit::Suid as u32, + _ => unreachable!(), + } + } + } + + fn remove_user_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode &= Bit::URead as u32, + 'w' => self.mode &= Bit::UWrite as u32, + 'x' => self.mode &= Bit::UExec as u32, + 's' => self.mode &= Bit::Suid as u32, + _ => unreachable!(), + } + } + } + + fn zero_user_bits(&mut self) { + self.mode &= 0o4444; + } + + fn set_user_bits(&mut self) { + match self.op { + Some(Op::Add) => self.add_user_bits(), + Some(Op::Remove) => self.remove_user_bits(), + Some(Op::Equals) => { + self.zero_user_bits(); + self.add_user_bits(); + }, + None => {}, + } + } + + fn add_group_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode |= Bit::GRead as u32, + 'w' => self.mode |= Bit::GWrite as u32, + 'x' => self.mode |= Bit::GExec as u32, + 's' => self.mode |= Bit::Sgid as u32, + _ => unreachable!(), + } + } + } + + fn remove_group_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode &= Bit::GRead as u32, + 'w' => self.mode &= Bit::GWrite as u32, + 'x' => self.mode &= Bit::GExec as u32, + 's' => self.mode &= Bit::Sgid as u32, + _ => unreachable!(), + } + } + } + + fn zero_group_bits(&mut self) { + self.mode &= 0o2222; + } + + fn set_group_bits(&mut self) { + match self.op { + Some(Op::Add) => self.add_group_bits(), + Some(Op::Remove) => self.remove_group_bits(), + Some(Op::Equals) => { + self.zero_group_bits(); + self.add_group_bits(); + }, + None => {}, + } + } + + fn add_other_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode |= Bit::ORead as u32, + 'w' => self.mode |= Bit::OWrite as u32, + 'x' => self.mode |= Bit::OExec as u32, + 't' => self.mode |= Bit::Sticky as u32, + _ => unreachable!(), + } + } + } + + fn remove_other_bits(&mut self) { + for b in &self.bits { + match b { + 'r' => self.mode &= Bit::ORead as u32, + 'w' => self.mode &= Bit::OWrite as u32, + 'x' => self.mode &= Bit::OExec as u32, + 's' => self.mode &= Bit::Sticky as u32, + _ => unreachable!(), + } + } + } + + fn zero_other_bits(&mut self) { + self.mode &= 0o1111; + } + + fn set_other_bits(&mut self) { + match self.op { + Some(Op::Add) => self.add_other_bits(), + Some(Op::Remove) => self.remove_other_bits(), + Some(Op::Equals) => { + self.zero_other_bits(); + self.add_other_bits(); + }, + None => {}, + } + } + + fn set_bits(&mut self) { + for w in self.who.clone() { + match w { + Who::User => self.set_user_bits(), + Who::Group => self.set_group_bits(), + Who::Other => self.set_other_bits(), + Who::All => { + self.set_user_bits(); + self.set_group_bits(); + self.set_other_bits(); + } + } + } + } + + fn reset(&mut self) { + self.who.clear(); + self.op = None; + self.bits.clear(); + } + + pub fn mode(&self) -> u32 { + self.mode + } + + pub fn parse(&mut self, value: &str) -> Result { + match self.parse_octal(value) { + Ok(mode) => { + self.mode = mode; + return Ok(mode) + }, + Err(e) => if e == ParseError::OutsideRange { + return Err(e); + } + } + for c in value.chars() { + match c { + 'u' => self.add_who(Who::User)?, + 'g' => self.add_who(Who::Group)?, + 'o' => self.add_who(Who::Other)?, + 'a' => self.add_who(Who::All)?, + '-' => self.set_op(Op::Remove)?, + '+' => self.set_op(Op::Add)?, + '=' => self.set_op(Op::Equals)?, + 'r' | 'w' | 'x' => self.push_bit(c)?, + 's' => self.push_suid()?, + 't' => self.push_sticky()?, + _ => return Err(ParseError::InvalidDigit), + } + } + self.set_bits(); + self.reset(); + Ok(self.mode) + } +}