use super::symbol::{Operator, Permission};
use super::Command;
#[must_use]
pub fn new_mask(current: u16, command: &Command) -> u16 {
match command {
Command::Show { .. } => current,
Command::Set(clauses) => {
let mut result = current;
for clause in clauses {
for action in &clause.actions {
let resolution = match action.permission {
Permission::CopyUser => copy(current >> 6),
Permission::CopyGroup => copy(current >> 3),
Permission::CopyOther => copy(current),
Permission::Literal {
mask,
conditional_executable,
} => {
let add_x = conditional_executable && current & 0o111 != 0;
mask | (if add_x { 0o111 } else { 0 })
}
};
let who = clause.who.mask;
result = match action.operator {
Operator::Add => (resolution & who) | result,
Operator::Remove => !(resolution & who) & result,
Operator::Set => (resolution & who) | (result & !who),
};
}
}
result
}
}
}
fn copy(mask: u16) -> u16 {
let mask = mask & 0o7;
mask << 6 | mask << 3 | mask
}
#[cfg(test)]
mod tests {
use super::*;
use crate::umask::symbol::{Action, Clause, Who};
#[test]
fn new_mask_for_show() {
let result = new_mask(0o766, &Command::Show { symbolic: false });
assert_eq!(result, 0o766);
}
#[test]
fn new_mask_all_set_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o777 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o635);
}
#[test]
fn new_mask_user_set_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o700 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o666);
}
#[test]
fn new_mask_group_set_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o070 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o736);
}
#[test]
fn new_mask_other_set_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o007 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o765);
}
#[test]
fn new_mask_set_conditional_without_initial_x() {
let command = Command::Set(vec![
Clause {
who: Who { mask: 0o700 },
actions: vec![Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o111,
conditional_executable: false,
},
}],
},
Clause {
who: Who { mask: 0o007 },
actions: vec![Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o000,
conditional_executable: true,
},
}],
},
]);
let result = new_mask(0o660, &command);
assert_eq!(result, 0o760);
}
#[test]
fn new_mask_set_conditional_with_initial_x() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o007 },
actions: vec![Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o000,
conditional_executable: true,
},
}],
}]);
let result = new_mask(0o760, &command);
assert_eq!(result, 0o761);
}
#[test]
fn new_mask_set_copy_user() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o777 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::CopyUser,
}],
}]);
let result = new_mask(0o650, &command);
assert_eq!(result, 0o666);
}
#[test]
fn new_mask_set_copy_group() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o777 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::CopyGroup,
}],
}]);
let result = new_mask(0o650, &command);
assert_eq!(result, 0o555);
}
#[test]
fn new_mask_set_copy_other() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o777 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::CopyOther,
}],
}]);
let result = new_mask(0o650, &command);
assert_eq!(result, 0o000);
}
#[test]
fn new_mask_add_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o770 },
actions: vec![Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o653, &command);
assert_eq!(result, 0o673);
}
#[test]
fn new_mask_remove_literal() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o770 },
actions: vec![Action {
operator: Operator::Remove,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
}]);
let result = new_mask(0o753, &command);
assert_eq!(result, 0o143);
}
#[test]
fn new_mask_with_multiple_actions() {
let command = Command::Set(vec![Clause {
who: Who { mask: 0o770 },
actions: vec![
Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
},
Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o000,
conditional_executable: true,
},
},
],
}]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o736);
}
#[test]
fn new_mask_with_multiple_clauses() {
let command = Command::Set(vec![
Clause {
who: Who { mask: 0o700 },
actions: vec![Action {
operator: Operator::Set,
permission: Permission::Literal {
mask: 0o635,
conditional_executable: false,
},
}],
},
Clause {
who: Who { mask: 0o007 },
actions: vec![Action {
operator: Operator::Add,
permission: Permission::Literal {
mask: 0o000,
conditional_executable: true,
},
}],
},
]);
let result = new_mask(0o766, &command);
assert_eq!(result, 0o667);
}
}