use crate::CoreError;
use crate::error::syscall_ret;
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PathStat {
pub uid: u32,
pub inode: u64,
pub ctime_sec: i64,
pub ctime_nsec: i64,
pub mtime_sec: i64,
pub mtime_nsec: i64,
}
pub fn path_uid(path: impl AsRef<Path>) -> Result<u32, CoreError> {
Ok(path_stat(path)?.uid)
}
pub fn path_stat(path: impl AsRef<Path>) -> Result<PathStat, CoreError> {
stat_path(path.as_ref(), "stat", true)
}
pub fn path_lstat(path: impl AsRef<Path>) -> Result<PathStat, CoreError> {
stat_path(path.as_ref(), "lstat", false)
}
pub fn proc_uid(pid: i32) -> Result<u32, CoreError> {
proc_uid_at("/proc", pid)
}
pub fn proc_uid_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<u32, CoreError> {
Ok(proc_stat_at(proc_root, pid)?.uid)
}
pub fn proc_stat(pid: i32) -> Result<PathStat, CoreError> {
proc_stat_at("/proc", pid)
}
pub fn proc_stat_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<PathStat, CoreError> {
let path = proc_root.as_ref().join(pid.to_string());
stat_path(&path, "stat", true)
}
#[inline(always)]
pub fn effective_uid() -> u32 {
unsafe { libc::geteuid() }
}
pub fn chown_path(path: impl AsRef<Path>, uid: u32, gid: Option<u32>) -> Result<(), CoreError> {
let path = CString::new(path.as_ref().as_os_str().as_bytes())
.map_err(|_| CoreError::sys(libc::EINVAL, "chown"))?;
let gid = gid.unwrap_or(u32::MAX);
let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
syscall_ret(ret, "chown")
}
fn stat_path(path: &Path, op: &'static str, follow_symlink: bool) -> Result<PathStat, CoreError> {
let path =
CString::new(path.as_os_str().as_bytes()).map_err(|_| CoreError::sys(libc::EINVAL, op))?;
let mut stat_buf: libc::stat = unsafe { std::mem::zeroed() };
let ret = if follow_symlink {
unsafe { libc::stat(path.as_ptr(), &mut stat_buf) }
} else {
unsafe { libc::lstat(path.as_ptr(), &mut stat_buf) }
};
syscall_ret(ret, op)?;
Ok(PathStat {
uid: stat_buf.st_uid,
inode: stat_buf.st_ino as _,
ctime_sec: stat_buf.st_ctime as _,
ctime_nsec: stat_buf.st_ctime_nsec as _,
mtime_sec: stat_buf.st_mtime as _,
mtime_nsec: stat_buf.st_mtime_nsec as _,
})
}