diff --git a/src/filetype.rs b/src/filetype.rs index efaedbe..4ee98e4 100644 --- a/src/filetype.rs +++ b/src/filetype.rs @@ -7,6 +7,8 @@ use std::fs::Metadata; /// this simplified enum that works for many appalications. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SimpleType { + /// Entry is of unknown type + Unknown, /// Entry is a symlink Symlink, /// Entry is a directory diff --git a/src/metadata.rs b/src/metadata.rs index de7cc22..7b5efb5 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -2,6 +2,7 @@ use std::fs::Permissions; use std::os::unix::fs::PermissionsExt; use libc; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::SimpleType; @@ -17,11 +18,11 @@ pub struct Metadata { impl Metadata { /// Returns simplified type of the directory entry pub fn simple_type(&self) -> SimpleType { - let typ = self.stat.st_mode & libc::S_IFMT; - match typ { + match self.file_type().unwrap_or(0) as libc::mode_t { libc::S_IFREG => SimpleType::File, libc::S_IFDIR => SimpleType::Dir, libc::S_IFLNK => SimpleType::Symlink, + 0 => SimpleType::Unknown, _ => SimpleType::Other, } } @@ -45,12 +46,112 @@ impl Metadata { pub fn len(&self) -> u64 { self.stat.st_size as u64 } + /// Return low level file type, if available + pub fn file_type(&self) -> Option { + Some(self.stat.st_mode & libc::S_IFMT) + } + /// Return device node, if available + pub fn ino(&self) -> Option { + Some(self.stat.st_ino) + } + /// Return device node major of the file, if available + pub fn dev_major(&self) -> Option { + Some(major(self.stat.st_dev)) + } + /// Return device node minor of the file, if available + pub fn dev_minor(&self) -> Option { + Some(minor(self.stat.st_dev)) + } + /// Return device node major of an device descriptor, if available + pub fn rdev_major(&self) -> Option { + match self.file_type()? as libc::mode_t { + libc::S_IFBLK | libc::S_IFCHR => Some(major(self.stat.st_rdev)), + _ => None, + } + } + /// Return device node minor of an device descriptor, if available + pub fn rdev_minor(&self) -> Option { + match self.file_type()? as libc::mode_t { + libc::S_IFBLK | libc::S_IFCHR => Some(minor(self.stat.st_rdev)), + _ => None, + } + } + /// Return preferered I/O Blocksize, if available + pub fn blksize(&self) -> Option { + Some(self.stat.st_blksize) + } + /// Return the number of 512 bytes blocks, if available + pub fn blocks(&self) -> Option { + Some(self.stat.st_blocks) + } + /// Returns file size (same as len() but Option), if available + pub fn size(&self) -> Option { + Some(self.stat.st_size) + } + /// Returns number of hard-links, if available + pub fn nlink(&self) -> Option { + Some(self.stat.st_nlink) + } + /// Returns user id, if available + pub fn uid(&self) -> Option { + Some(self.stat.st_uid) + } + /// Returns group id, if available + pub fn gid(&self) -> Option { + Some(self.stat.st_gid) + } + /// Returns mode bits, if available + pub fn file_mode(&self) -> Option { + Some(self.stat.st_mode & 0o7777) + } + /// Returns last access time, if available + pub fn atime(&self) -> Option { + Some(unix_systemtime(self.stat.st_atime, self.stat.st_atime_nsec)) + } + /// Returns creation, if available + pub fn btime(&self) -> Option { + None + } + /// Returns last status change time, if available + pub fn ctime(&self) -> Option { + Some(unix_systemtime(self.stat.st_ctime, self.stat.st_ctime_nsec)) + } + /// Returns last modification time, if available + pub fn mtime(&self) -> Option { + Some(unix_systemtime(self.stat.st_mtime, self.stat.st_mtime_nsec)) + } } pub fn new(stat: libc::stat) -> Metadata { Metadata { stat: stat } } +fn unix_systemtime(sec: libc::time_t, nsec: i64) -> SystemTime { + UNIX_EPOCH + Duration::from_secs(sec as u64) + Duration::from_nanos(nsec as u64) +} + +#[cfg(not(target_os = "macos"))] +pub fn major(dev: libc::dev_t) -> u32 { + unsafe { libc::major(dev) } +} + +#[cfg(not(target_os = "macos"))] +pub fn minor(dev: libc::dev_t) -> u32 { + unsafe { libc::minor(dev) } +} + +// major/minor are not in rust's darwin libc (why) +// see https://github.com/apple/darwin-xnu/blob/main/bsd/sys/types.h +#[cfg(target_os = "macos")] +pub fn major(dev: libc::dev_t) -> u32 { + (dev as u32 >> 24) & 0xff +} + +#[cfg(target_os = "macos")] +pub fn minor(dev: libc::dev_t) -> u32 { + dev as u32 & 0xffffff +} + #[cfg(test)] mod test { use super::*;