use std::mem::MaybeUninit;
use std::path::Path;
use crate::{Result, Error, error, FileType};
use crate::time::FileTime;
use pathstr::PathStr;
use errno::errno;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct Stat
{
pub uid: libc::uid_t,
pub gid: libc::gid_t,
pub mode: libc::mode_t,
pub time: FileTime,
pub filetype: FileType,
pub blocksize: libc::blksize_t,
pub blockcount: libc::blkcnt_t,
pub device: libc::dev_t,
pub rdevice: libc::dev_t,
pub size: usize,
pub nlink: u64,
pub ino: u64
}
impl Default for Stat
{
fn default() -> Self
{
Self
{
uid: 0,
gid: 0,
mode: 0,
time: FileTime::default(),
filetype: FileType::Regular,
blocksize: 0,
blockcount: 0,
device: 0,
rdevice: 0,
size: 0,
nlink: 0,
ino: 0
}
}
}
impl TryFrom<libc::stat> for Stat
{
type Error = Error;
fn try_from(st: libc::stat) -> Result<Self>
{
let mut r = Self::default();
r.uid = st.st_uid;
r.gid = st.st_gid;
r.blockcount = st.st_blocks;
r.blocksize = st.st_blksize;
r.size = st.st_size as usize;
r.device = st.st_dev;
r.rdevice = st.st_rdev;
r.mode = st.st_mode;
r.filetype = FileType::try_from(st.st_mode)?;
r.time = FileTime::from(st);
r.nlink = st.st_nlink;
r.ino = st.st_ino;
Ok(r)
}
}
impl Stat
{
pub fn new<P>(path: P) -> Result<Self>
where P: AsRef<Path>
{
let cpath = PathStr::new(path.as_ref()).cstring()?;
let mut buffer = MaybeUninit::<libc::stat>::uninit();
unsafe
{
if libc::lstat(cpath.as_ptr(), buffer.as_mut_ptr()) == -1
{
error!("Stat::new: {}", errno())
}
}
let buffer = unsafe { buffer.assume_init() };
let stat = Self::try_from(buffer)?;
Ok(stat)
}
#[allow(unused)]
pub fn new_follow<P>(path: P) -> Result<Self>
where P: AsRef<Path>
{
let cpath = PathStr::new(path.as_ref()).cstring()?;
let mut buffer = MaybeUninit::<libc::stat>::uninit();
unsafe
{
if libc::stat(cpath.as_ptr(), buffer.as_mut_ptr()) == -1
{
error!("Stat::new: {}", errno())
}
}
let buffer = unsafe { buffer.assume_init() };
let stat = Self::try_from(buffer)?;
Ok(stat)
}
#[allow(unused)]
pub fn owners(&self) -> Result<(String, String)>
{
Ok((
crate::util::username_from_id(self.uid)?,
crate::util::groupname_from_id(self.gid)?
))
}
}