use super::{fs_action::FSACTION_VALUES, FsAction, UmaskParser};
use crate::{
common::{
conf::Configuration,
fs::common_configuration_keys::{FS_PERMISSIONS_UMASK_DEFAULT, FS_PERMISSIONS_UMASK_KEY},
},
hdfs::FsPermissionProto,
};
use once_cell::sync::Lazy;
const UMASK_LABEL: &str = FS_PERMISSIONS_UMASK_KEY;
const DEFAULT_UMASK: i32 = FS_PERMISSIONS_UMASK_DEFAULT;
pub static DIR_DEFAULT_PERM: Lazy<FsPermission> = Lazy::new(FsPermission::get_dir_default);
pub static FILE_DEFAULT_PERM: Lazy<FsPermission> = Lazy::new(FsPermission::get_file_default);
#[derive(Clone, Copy)]
pub struct FsPermission {
useraction: FsAction,
groupaction: FsAction,
otheraction: FsAction,
sticky_bit: bool,
}
impl FsPermission {
fn parse_short(n: i16) -> (FsAction, FsAction, FsAction, bool) {
(
FSACTION_VALUES[(n >> 6 & 7) as usize],
FSACTION_VALUES[(n >> 3 & 7) as usize],
FSACTION_VALUES[(n & 7) as usize],
n >> 9 & 1 == 1,
)
}
pub fn update_short(&mut self, n: i16) {
let (u, g, o, sb) = Self::parse_short(n);
self.useraction = u;
self.groupaction = g;
self.otheraction = o;
self.sticky_bit = sb;
}
pub fn to_short(&self) -> i16 {
(if self.sticky_bit { 1 << 9 } else { 0 })
| (self.useraction.ordinal() << 6) as i16
| (self.groupaction.ordinal() << 3) as i16
| self.otheraction.ordinal() as i16
}
pub fn apply_umask(&self, umask: &FsPermission) -> Self {
Self {
useraction: self.useraction.and(&umask.useraction.not()),
groupaction: self.groupaction.and(&umask.groupaction.not()),
otheraction: self.otheraction.and(&umask.otheraction.not()),
sticky_bit: false,
}
}
pub fn get_umask(conf: Option<&Configuration>) -> anyhow::Result<Self> {
let mut umask = DEFAULT_UMASK as i16;
if let Some(conf) = conf {
if let Some(conf_umask) = conf.get(UMASK_LABEL, None) {
umask = UmaskParser::new(conf_umask)?.get_umask();
}
}
Ok(Self::from(umask))
}
pub fn get_dir_default() -> Self {
Self::from(0o777)
}
pub fn get_file_default() -> Self {
Self::from(0o666)
}
}
impl From<i16> for FsPermission {
fn from(mode: i16) -> Self {
let (u, g, o, sb) = Self::parse_short(mode);
Self {
useraction: u,
groupaction: g,
otheraction: o,
sticky_bit: sb,
}
}
}
impl Into<FsPermissionProto> for &FsPermission {
fn into(self) -> FsPermissionProto {
FsPermissionProto {
perm: self.to_short() as u32,
}
}
}