#![allow(clippy::useless_conversion)] #![allow(clippy::unnecessary_cast)]
use std::{path::Path, time::SystemTime};
#[cfg(unix)]
pub struct Metadata(rustix::fs::Stat);
#[cfg(not(unix))]
pub struct Metadata(std::fs::Metadata);
impl Metadata {
pub fn from_path_no_follow(path: &Path) -> Result<Self, std::io::Error> {
#[cfg(unix)]
{
rustix::fs::lstat(path).map(Metadata).map_err(Into::into)
}
#[cfg(not(unix))]
path.symlink_metadata().map(Metadata)
}
pub fn from_file(file: &std::fs::File) -> Result<Self, std::io::Error> {
#[cfg(unix)]
{
rustix::fs::fstat(file).map(Metadata).map_err(Into::into)
}
#[cfg(not(unix))]
file.metadata().map(Metadata)
}
}
#[allow(clippy::len_without_is_empty)]
impl Metadata {
pub fn is_dir(&self) -> bool {
#[cfg(unix)]
{
(self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFDIR as u32
}
#[cfg(not(unix))]
self.0.is_dir()
}
pub fn modified(&self) -> Option<SystemTime> {
#[cfg(unix)]
{
#[cfg(not(any(target_os = "aix", target_os = "hurd")))]
let seconds = self.0.st_mtime;
#[cfg(any(target_os = "aix", target_os = "hurd"))]
let seconds = self.0.st_mtim.tv_sec;
#[cfg(not(any(target_os = "aix", target_os = "hurd")))]
let nanoseconds = self.0.st_mtime_nsec;
#[cfg(any(target_os = "aix", target_os = "hurd"))]
let nanoseconds = self.0.st_mtim.tv_nsec;
let seconds = seconds as i64;
system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
}
#[cfg(not(unix))]
self.0.modified().ok()
}
pub fn created(&self) -> Option<SystemTime> {
#[cfg(unix)]
{
#[cfg(not(any(target_os = "aix", target_os = "hurd")))]
let seconds = self.0.st_ctime;
#[cfg(any(target_os = "aix", target_os = "hurd"))]
let seconds = self.0.st_ctim.tv_sec;
#[cfg(not(any(target_os = "aix", target_os = "hurd")))]
let nanoseconds = self.0.st_ctime_nsec;
#[cfg(any(target_os = "aix", target_os = "hurd"))]
let nanoseconds = self.0.st_ctim.tv_nsec;
let seconds = seconds as i64;
system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
}
#[cfg(not(unix))]
self.0.created().ok()
}
pub fn len(&self) -> u64 {
#[cfg(unix)]
{
self.0.st_size as u64
}
#[cfg(not(unix))]
self.0.len()
}
pub fn dev(&self) -> u64 {
#[cfg(unix)]
{
self.0.st_dev as u64
}
#[cfg(not(unix))]
0
}
pub fn ino(&self) -> u64 {
#[cfg(unix)]
{
self.0.st_ino as u64
}
#[cfg(not(unix))]
0
}
pub fn uid(&self) -> u32 {
#[cfg(unix)]
{
self.0.st_uid as u32
}
#[cfg(not(unix))]
0
}
pub fn gid(&self) -> u32 {
#[cfg(unix)]
{
self.0.st_gid as u32
}
#[cfg(not(unix))]
0
}
pub fn is_executable(&self) -> bool {
#[cfg(unix)]
{
(self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
&& self.0.st_mode as u32 & libc::S_IXUSR as u32 == libc::S_IXUSR as u32
}
#[cfg(not(unix))]
gix_fs::is_executable(&self.0)
}
pub fn is_symlink(&self) -> bool {
#[cfg(unix)]
{
(self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFLNK as u32
}
#[cfg(not(unix))]
self.0.is_symlink()
}
pub fn is_file(&self) -> bool {
#[cfg(unix)]
{
(self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
}
#[cfg(not(unix))]
self.0.is_file()
}
}
#[cfg(unix)]
fn system_time_from_secs_nanos(secs: i64, nanos: i32) -> Option<SystemTime> {
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
let (secs, nanos) = if (secs <= 0 && secs > i64::MIN) && (nanos < 0 && nanos > -1_000_000_000) {
(secs - 1, nanos + 1_000_000_000)
} else {
(secs, nanos)
};
let d = std::time::Duration::new(secs.abs_diff(0), nanos.try_into().ok()?);
Some(if secs < 0 {
std::time::UNIX_EPOCH - d
} else {
std::time::UNIX_EPOCH + d
})
}