use core::slice;
use std::{
ffi::{CStr, OsStr},
fmt::Debug,
os::unix::ffi::OsStrExt,
path::Path,
time::SystemTime,
};
use crate::{
helpers::time,
libproc::{
bindings::{vinfo_stat, vnode_info, vnode_info_path},
file_info::ProcFDType,
},
};
use ref_cast::RefCast;
use rustix::fs::{Dev, FileType, Fsid, Gid, Mode, RawMode, Uid};
#[repr(transparent)]
#[derive(RefCast, Clone, Copy)]
pub struct VnodeStat {
raw: vinfo_stat,
}
impl VnodeStat {
pub fn from_raw(raw: vinfo_stat) -> Self {
Self { raw }
}
pub fn as_raw(&self) -> &vinfo_stat {
&self.raw
}
pub fn dev(&self) -> Dev {
self.raw.vst_dev as Dev
}
pub fn raw_mode(&self) -> RawMode {
self.raw.vst_mode
}
pub fn file_type(&self) -> FileType {
FileType::from_raw_mode(self.raw.vst_mode)
}
pub fn mode(&self) -> Mode {
Mode::from_raw_mode(self.raw.vst_mode)
}
pub fn nlink(&self) -> u16 {
self.raw.vst_nlink
}
pub fn ino(&self) -> u64 {
self.raw.vst_ino
}
pub fn uid(&self) -> Uid {
Uid::from_raw_unchecked(self.raw.vst_uid)
}
pub fn gid(&self) -> Gid {
Gid::from_raw_unchecked(self.raw.vst_gid)
}
pub fn atime(&self) -> SystemTime {
time::system_time_from_unix(self.raw.vst_atime, self.raw.vst_atimensec)
}
pub fn mtime(&self) -> SystemTime {
time::system_time_from_unix(self.raw.vst_mtime, self.raw.vst_mtimensec)
}
pub fn ctime(&self) -> SystemTime {
time::system_time_from_unix(self.raw.vst_ctime, self.raw.vst_ctimensec)
}
pub fn birthtime(&self) -> SystemTime {
time::system_time_from_unix(self.raw.vst_birthtime, self.raw.vst_birthtimensec)
}
pub fn size(&self) -> u64 {
self.raw.vst_size.max(0) as u64
}
pub fn blocks(&self) -> u64 {
self.raw.vst_blocks.max(0) as u64
}
pub fn blksize(&self) -> u32 {
self.raw.vst_blksize.max(0) as u32
}
pub fn flags(&self) -> u32 {
self.raw.vst_flags
}
pub fn generation(&self) -> u32 {
self.raw.vst_gen
}
pub fn rdev(&self) -> Dev {
self.raw.vst_rdev as Dev
}
pub fn spare(&self) -> [i64; 2] {
self.raw.vst_qspare
}
}
impl Debug for VnodeStat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VnodeStat")
.field("dev", &self.dev())
.field("mode", &self.mode())
.field("nlink", &self.nlink())
.field("ino", &self.ino())
.field("uid", &self.uid())
.field("gid", &self.gid())
.field("atime", &self.atime())
.field("mtime", &self.mtime())
.field("ctime", &self.ctime())
.field("birthtime", &self.birthtime())
.field("size", &self.size())
.field("blocks", &self.blocks())
.field("blksize", &self.blksize())
.field("flags", &self.flags())
.field("generation", &self.generation())
.field("rdev", &self.rdev())
.finish()
}
}
#[repr(transparent)]
#[derive(RefCast, Clone, Copy)]
pub struct Vnode {
raw: vnode_info,
}
impl Vnode {
pub fn from_raw(raw: vnode_info) -> Self {
Self { raw }
}
pub fn as_raw(&self) -> &vnode_info {
&self.raw
}
pub fn stat(&self) -> VnodeStat {
VnodeStat::from_raw(self.raw.vi_stat)
}
pub fn node_type(&self) -> ProcFDType {
ProcFDType::from(self.raw.vi_type as u32)
}
pub fn pad(&self) -> i32 {
self.raw.vi_pad
}
pub fn fsid(&self) -> Fsid {
unsafe { std::mem::transmute(self.raw.vi_fsid) }
}
}
impl Debug for Vnode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Vnode")
.field("stat", &self.stat())
.field("node_type", &self.node_type())
.field("pad", &self.pad())
.field("fsid", &self.fsid())
.finish()
}
}
#[repr(transparent)]
#[derive(RefCast, Clone, Copy)]
pub struct VnodeWithPath {
raw: vnode_info_path,
}
impl VnodeWithPath {
pub fn from_raw(raw: vnode_info_path) -> Self {
Self { raw }
}
pub fn as_raw(&self) -> &vnode_info_path {
&self.raw
}
pub fn vnode(&self) -> &Vnode {
Vnode::ref_cast(&self.raw.vip_vi)
}
pub fn path(&self) -> &Path {
let i8_slice = self.raw.vip_path.as_slice();
let u8_slice =
unsafe { slice::from_raw_parts(i8_slice.as_ptr() as *const u8, i8_slice.len()) };
let bytes = match CStr::from_bytes_until_nul(u8_slice) {
Ok(c_str) => c_str.to_bytes(),
Err(_) => u8_slice,
};
let osstr = OsStr::from_bytes(bytes);
Path::new(osstr)
}
}
impl Debug for VnodeWithPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VnodeWithPath")
.field("vnode", &self.vnode())
.field("path", &self.path())
.finish()
}
}