From 2be51a3e93ee9c284533e29d8dc7de05f210bc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Sat, 17 Apr 2021 21:06:34 +0200 Subject: [PATCH 1/6] add accessors for the underlying stat data This anticipates the statx() interface I'll add soon. Breaking change: Adds a 'SimpleType::Unknown' which can be returned when the filetype can't be determinded. Code matching on SimpleType may add a clause for this when there is no catch-all. --- src/filetype.rs | 2 ++ src/metadata.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) 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..f7259c0 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; @@ -45,12 +46,90 @@ 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(unsafe { libc::major(self.stat.st_dev) } as u64) + } + /// Return device node minor of the file, if available + pub fn dev_minor(&self) -> Option { + Some(unsafe { libc::minor(self.stat.st_dev) } as u64) + } + /// Return device node major of an device descriptor, if available + pub fn rdev_major(&self) -> Option { + match self.file_type()? { + libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::major(self.stat.st_rdev) } as u64), + _ => None, + } + } + /// Return device node minor of an device descriptor, if available + pub fn rdev_minor(&self) -> Option { + match self.file_type()? { + libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::minor(self.stat.st_rdev) } as u64), + _ => None, + } + } + /// Return preferered I/O Blocksize, if available + pub fn blksize(&self) -> Option { + Some(self.stat.st_blksize as u32) + } + /// Return the number of 512 bytes blocks, if available + pub fn blocks(&self) -> Option { + Some(self.stat.st_blocks as u64) + } + /// Returns file size (same as len() but Option), if available + pub fn size(&self) -> Option { + Some(self.stat.st_size as u64) + } + /// Returns number of hard-links, if available + pub fn nlink(&self) -> Option { + Some(self.stat.st_nlink as u32) + } + /// Returns user id, if available + pub fn uid(&self) -> Option { + Some(self.stat.st_uid as u32) + } + /// Returns group id, if available + pub fn gid(&self) -> Option { + Some(self.stat.st_gid as u32) + } + /// 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(test)] mod test { use super::*; From bba06871f3751d1b01359ed14c4a6cc9242ba4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Sun, 18 Apr 2021 02:36:41 +0200 Subject: [PATCH 2/6] FIX: make use of SimpleType::Unknown in simple_type() --- src/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index f7259c0..e71683e 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -18,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) { libc::S_IFREG => SimpleType::File, libc::S_IFDIR => SimpleType::Dir, libc::S_IFLNK => SimpleType::Symlink, + 0 => SimpleType::Unknown, _ => SimpleType::Other, } } From c502cc24da12c97fd872e20353f19ffafe0f05ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Sun, 18 Apr 2021 02:38:24 +0200 Subject: [PATCH 3/6] FIX: use u32 for the 'dev' values --- src/metadata.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index e71683e..f4c2abc 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -55,24 +55,24 @@ impl Metadata { Some(self.stat.st_ino) } /// Return device node major of the file, if available - pub fn dev_major(&self) -> Option { - Some(unsafe { libc::major(self.stat.st_dev) } as u64) + pub fn dev_major(&self) -> Option { + Some(unsafe { libc::major(self.stat.st_dev) }) } /// Return device node minor of the file, if available - pub fn dev_minor(&self) -> Option { - Some(unsafe { libc::minor(self.stat.st_dev) } as u64) + pub fn dev_minor(&self) -> Option { + Some(unsafe { libc::minor(self.stat.st_dev) }) } /// Return device node major of an device descriptor, if available - pub fn rdev_major(&self) -> Option { + pub fn rdev_major(&self) -> Option { match self.file_type()? { - libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::major(self.stat.st_rdev) } as u64), + libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::major(self.stat.st_rdev) }), _ => None, } } /// Return device node minor of an device descriptor, if available - pub fn rdev_minor(&self) -> Option { + pub fn rdev_minor(&self) -> Option { match self.file_type()? { - libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::minor(self.stat.st_rdev) } as u64), + libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::minor(self.stat.st_rdev) }), _ => None, } } From c8f364dc981bb7d6a009bdf5abebf9a75f495c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Sun, 18 Apr 2021 03:04:46 +0200 Subject: [PATCH 4/6] Changes to make macos happy --- src/metadata.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index f4c2abc..a7a9e9c 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -18,7 +18,7 @@ pub struct Metadata { impl Metadata { /// Returns simplified type of the directory entry pub fn simple_type(&self) -> SimpleType { - match self.file_type().unwrap_or(0) { + 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, @@ -48,7 +48,7 @@ impl Metadata { } /// Return low level file type, if available pub fn file_type(&self) -> Option { - Some(self.stat.st_mode & libc::S_IFMT) + Some(self.stat.st_mode as u32 & libc::S_IFMT as u32) } /// Return device node, if available pub fn ino(&self) -> Option { @@ -56,23 +56,23 @@ impl Metadata { } /// Return device node major of the file, if available pub fn dev_major(&self) -> Option { - Some(unsafe { libc::major(self.stat.st_dev) }) + Some(major(self.stat.st_dev)) } /// Return device node minor of the file, if available pub fn dev_minor(&self) -> Option { - Some(unsafe { libc::minor(self.stat.st_dev) }) + 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()? { - libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::major(self.stat.st_rdev) }), + 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()? { - libc::S_IFBLK | libc::S_IFCHR => Some(unsafe { libc::minor(self.stat.st_rdev) }), + match self.file_type()? as libc::mode_t { + libc::S_IFBLK | libc::S_IFCHR => Some(minor(self.stat.st_rdev)), _ => None, } } @@ -102,7 +102,7 @@ impl Metadata { } /// Returns mode bits, if available pub fn file_mode(&self) -> Option { - Some(self.stat.st_mode & 0o7777) + Some(self.stat.st_mode as u32 & 0o7777) } /// Returns last access time, if available pub fn atime(&self) -> Option { @@ -130,6 +130,28 @@ 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::*; From 39fc8039e19b27a7032374a4c4e8b0500b0c3c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Mon, 19 Apr 2021 08:38:11 +0200 Subject: [PATCH 5/6] FIX: replace ino_t with u64 to comply with statx --- src/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index a7a9e9c..275cdb4 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -51,8 +51,8 @@ impl Metadata { Some(self.stat.st_mode as u32 & libc::S_IFMT as u32) } /// Return device node, if available - pub fn ino(&self) -> Option { - Some(self.stat.st_ino) + pub fn ino(&self) -> Option { + Some(self.stat.st_ino as u64) } /// Return device node major of the file, if available pub fn dev_major(&self) -> Option { From ffe5d3fbff770e463123b48346807611ec7170a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Th=C3=A4ter?= Date: Wed, 21 Apr 2021 20:00:36 +0200 Subject: [PATCH 6/6] use types from 'struct stat' instead 'struct statx' --- src/metadata.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index 275cdb4..7b5efb5 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -47,12 +47,12 @@ impl Metadata { self.stat.st_size as u64 } /// Return low level file type, if available - pub fn file_type(&self) -> Option { - Some(self.stat.st_mode as u32 & libc::S_IFMT as u32) + 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 as u64) + 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 { @@ -77,32 +77,32 @@ impl Metadata { } } /// Return preferered I/O Blocksize, if available - pub fn blksize(&self) -> Option { - Some(self.stat.st_blksize as u32) + 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 as u64) + 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 as u64) + 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 as u32) + 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 as u32) + 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 as u32) + 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 as u32 & 0o7777) + pub fn file_mode(&self) -> Option { + Some(self.stat.st_mode & 0o7777) } /// Returns last access time, if available pub fn atime(&self) -> Option {