use nuts_bytes::{FromBytes, ToBytes};
#[cfg(test)]
mod tests;
const MASK_TYPE: u16 = 0x0600;
const TYPE_FILE: u16 = 0x0000;
const TYPE_DIR: u16 = 0x0200;
const TYPE_SYMLINK: u16 = 0x0400;
const MASK_USR_R: u16 = 0x0001;
const MASK_USR_W: u16 = 0x0002;
const MASK_USR_X: u16 = 0x0004;
const MASK_GRP_R: u16 = 0x0008;
const MASK_GRP_W: u16 = 0x0010;
const MASK_GRP_X: u16 = 0x0020;
const MASK_OTH_R: u16 = 0x0040;
const MASK_OTH_W: u16 = 0x0080;
const MASK_OTH_X: u16 = 0x0100;
const DEFAULT_ACCESS_RIGHTS: u16 =
MASK_USR_R | MASK_USR_W | MASK_USR_X | MASK_GRP_R | MASK_GRP_X | MASK_OTH_R | MASK_OTH_X;
#[derive(Clone, Copy, PartialEq)]
pub enum Group {
User,
Group,
Other,
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
pub(crate) struct Mode(u16);
impl Mode {
pub fn file() -> Mode {
Mode(TYPE_FILE | DEFAULT_ACCESS_RIGHTS)
}
pub fn directory() -> Mode {
Mode(TYPE_DIR | DEFAULT_ACCESS_RIGHTS)
}
pub fn symlink() -> Mode {
Mode(TYPE_SYMLINK | DEFAULT_ACCESS_RIGHTS)
}
pub fn is_file(&self) -> bool {
self.0 & MASK_TYPE == TYPE_FILE
}
pub fn is_directory(&self) -> bool {
self.0 & MASK_TYPE == TYPE_DIR
}
pub fn is_symlink(&self) -> bool {
self.0 & MASK_TYPE == TYPE_SYMLINK
}
pub fn can_read(&self, group: Group) -> bool {
self.0 & Self::read_mask(group) > 0
}
pub fn set_readable(&mut self, group: Group, readable: bool) {
self.update_mask(readable, Self::read_mask(group));
}
pub fn can_write(&self, group: Group) -> bool {
self.0 & Self::write_mask(group) > 0
}
pub fn set_writable(&mut self, group: Group, writable: bool) {
self.update_mask(writable, Self::write_mask(group));
}
pub fn can_execute(&self, group: Group) -> bool {
self.0 & Self::execute_mask(group) > 0
}
pub fn set_executable(&mut self, group: Group, executable: bool) {
self.update_mask(executable, Self::execute_mask(group));
}
fn read_mask(group: Group) -> u16 {
match group {
Group::User => MASK_USR_R,
Group::Group => MASK_GRP_R,
Group::Other => MASK_OTH_R,
}
}
fn write_mask(group: Group) -> u16 {
match group {
Group::User => MASK_USR_W,
Group::Group => MASK_GRP_W,
Group::Other => MASK_OTH_W,
}
}
fn execute_mask(group: Group) -> u16 {
match group {
Group::User => MASK_USR_X,
Group::Group => MASK_GRP_X,
Group::Other => MASK_OTH_X,
}
}
fn update_mask(&mut self, enable: bool, mask: u16) {
if enable {
self.0 |= mask;
} else {
self.0 &= !mask;
}
}
}