stree 0.1.0

A directory hierarchy mapping format, similar to mtree
Documentation
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)?
        ))
    }
}