use std::fmt::{self, Write};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Mode(pub u32);
impl Mode {
pub const DIR: Self = Self(1 << 31);
pub const APPEND: Self = Self(1 << 30);
pub const EXCLUSIVE: Self = Self(1 << 29);
pub const TEMPORARY: Self = Self(1 << 28);
pub const SYMLINK: Self = Self(1 << 27);
pub const DEVICE: Self = Self(1 << 26);
pub const NAMED_PIPE: Self = Self(1 << 25);
pub const SOCKET: Self = Self(1 << 24);
pub const SETUID: Self = Self(1 << 23);
pub const SETGID: Self = Self(1 << 22);
pub const CHAR_DEVICE: Self = Self(1 << 21);
pub const STICKY: Self = Self(1 << 20);
pub const IRREGULAR: Self = Self(1 << 19);
}
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut empty = true;
let pairs = [
(Self::DIR, 'd'),
(Self::APPEND, 'a'),
(Self::EXCLUSIVE, 'l'),
(Self::TEMPORARY, 'T'),
(Self::SYMLINK, 'L'),
(Self::DEVICE, 'D'),
(Self::NAMED_PIPE, 'p'),
(Self::SOCKET, 'S'),
(Self::SETUID, 'u'),
(Self::SETGID, 'g'),
(Self::CHAR_DEVICE, 'c'),
(Self::STICKY, 't'),
(Self::IRREGULAR, '?'),
];
for (flag, flag_char) in pairs {
if self.has(flag) {
f.write_char(flag_char)?;
empty = false;
}
}
if empty {
write!(f, "-")?;
}
let rwx = "rwxrwxrwx";
for (i, c) in rwx.char_indices() {
if self.has(Mode(1 << (9 - 1 - i))) {
write!(f, "{}", c)?;
} else {
write!(f, "-")?;
}
}
Ok(())
}
}
impl From<UnixMode> for Mode {
fn from(m: UnixMode) -> Self {
let mut mode = Mode(m.0 & 0o777);
match m & UnixMode::IFMT {
UnixMode::IFBLK => mode |= Mode::DEVICE,
UnixMode::IFCHR => mode |= Mode::DEVICE & Mode::CHAR_DEVICE,
UnixMode::IFDIR => mode |= Mode::DIR,
UnixMode::IFIFO => mode |= Mode::NAMED_PIPE,
UnixMode::IFLNK => mode |= Mode::SYMLINK,
UnixMode::IFREG => { }
UnixMode::IFSOCK => mode |= Mode::SOCKET,
_ => {}
}
if m.has(UnixMode::ISGID) {
mode |= Mode::SETGID
}
if m.has(UnixMode::ISUID) {
mode |= Mode::SETUID
}
if m.has(UnixMode::ISVTX) {
mode |= Mode::STICKY
}
mode
}
}
impl From<MsdosMode> for Mode {
fn from(m: MsdosMode) -> Self {
let mut mode = if m.has(MsdosMode::DIR) {
Mode::DIR | Mode(0o777)
} else {
Mode(0o666)
};
if m.has(MsdosMode::READ_ONLY) {
mode &= Mode(0o222);
}
mode
}
}
impl From<u32> for Mode {
fn from(u: u32) -> Self {
Mode(u)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnixMode(pub u32);
impl UnixMode {
pub const IFMT: Self = Self(0xf000);
pub const IFSOCK: Self = Self(0xc000);
pub const IFLNK: Self = Self(0xa000);
pub const IFREG: Self = Self(0x8000);
pub const IFBLK: Self = Self(0x6000);
pub const IFDIR: Self = Self(0x4000);
pub const IFCHR: Self = Self(0x2000);
pub const IFIFO: Self = Self(0x1000);
pub const ISUID: Self = Self(0x800);
pub const ISGID: Self = Self(0x400);
pub const ISVTX: Self = Self(0x200);
}
impl From<u32> for UnixMode {
fn from(u: u32) -> Self {
UnixMode(u)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MsdosMode(pub u32);
impl MsdosMode {
pub const DIR: Self = Self(0x10);
pub const READ_ONLY: Self = Self(0x01);
}
impl From<u32> for MsdosMode {
fn from(u: u32) -> Self {
MsdosMode(u)
}
}
macro_rules! derive_bitops {
($T: ty) => {
impl std::ops::BitOr for $T {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for $T {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl std::ops::BitAnd for $T {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
}
impl std::ops::BitAndAssign for $T {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl $T {
pub fn has(&self, rhs: Self) -> bool {
self.0 & rhs.0 != 0
}
}
};
}
derive_bitops!(Mode);
derive_bitops!(UnixMode);
derive_bitops!(MsdosMode);