use std::io::Error;
use std::io::ErrorKind;
use crate::constants::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(u8)]
pub enum FileType {
Socket = 0o14,
Symlink = 0o12,
Regular = 0o10,
BlockDevice = 0o6,
Directory = 0o4,
CharDevice = 0o2,
Fifo = 0o1,
}
impl FileType {
pub fn new(mode: u32) -> Result<Self, Error> {
use FileType::*;
const SOCKET: u8 = FileType::Socket as u8;
const SYMLINK: u8 = FileType::Symlink as u8;
const REGULAR: u8 = FileType::Regular as u8;
const BLOCK: u8 = FileType::BlockDevice as u8;
const DIRECTORY: u8 = FileType::Directory as u8;
const CHAR: u8 = FileType::CharDevice as u8;
const FIFO: u8 = FileType::Fifo as u8;
match mode_to_file_type(mode) {
SOCKET => Ok(Socket),
SYMLINK => Ok(Symlink),
REGULAR => Ok(Regular),
BLOCK => Ok(BlockDevice),
DIRECTORY => Ok(Directory),
CHAR => Ok(CharDevice),
FIFO => Ok(Fifo),
_ => Err(ErrorKind::InvalidData.into()),
}
}
#[allow(unused)]
pub(crate) fn to_mode(self) -> u32 {
u32::from(self as u8) << 12
}
}
impl TryFrom<u32> for FileType {
type Error = Error;
fn try_from(mode: u32) -> Result<Self, Error> {
Self::new(mode)
}
}
pub(crate) fn mode_to_file_type(mode: u32) -> u8 {
((mode & FILE_TYPE_MASK) >> 12) as u8
}
#[cfg(unix)]
impl TryFrom<&std::fs::Metadata> for FileType {
type Error = Error;
fn try_from(other: &std::fs::Metadata) -> Result<Self, Self::Error> {
use std::os::unix::fs::MetadataExt;
FileType::new(other.mode())
}
}
#[cfg(not(unix))]
impl TryFrom<&std::fs::Metadata> for FileType {
type Error = Error;
fn try_from(other: &std::fs::Metadata) -> Result<Self, Self::Error> {
if other.is_dir() {
return Ok(FileType::Directory);
}
if other.is_symlink() {
return Ok(FileType::Symlink);
}
if other.is_file() {
return Ok(FileType::Regular);
}
Err(ErrorKind::InvalidData.into())
}
}