pub use libc::{dev_t, mode_t};
pub use libc::stat as FileStat;
use crate::{Result, NixPath, errno::Errno};
#[cfg(not(target_os = "redox"))]
use crate::fcntl::{AtFlags, at_rawfd};
use std::mem;
use std::os::unix::io::RawFd;
use crate::sys::time::{TimeSpec, TimeVal};
libc_bitflags!(
pub struct SFlag: mode_t {
S_IFIFO;
S_IFCHR;
S_IFDIR;
S_IFBLK;
S_IFREG;
S_IFLNK;
S_IFSOCK;
S_IFMT;
}
);
libc_bitflags! {
pub struct Mode: mode_t {
S_IRWXU;
S_IRUSR;
S_IWUSR;
S_IXUSR;
S_IRWXG;
S_IRGRP;
S_IWGRP;
S_IXGRP;
S_IRWXO;
S_IROTH;
S_IWOTH;
S_IXOTH;
S_ISUID as mode_t;
S_ISGID as mode_t;
S_ISVTX as mode_t;
}
}
pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
})?;
Errno::result(res).map(drop)
}
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn mknodat<P: ?Sized + NixPath>(
dirfd: RawFd,
path: &P,
kind: SFlag,
perm: Mode,
dev: dev_t,
) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
})?;
Errno::result(res).map(drop)
}
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub const fn major(dev: dev_t) -> u64 {
((dev >> 32) & 0xffff_f000) |
((dev >> 8) & 0x0000_0fff)
}
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub const fn minor(dev: dev_t) -> u64 {
((dev >> 12) & 0xffff_ff00) |
((dev ) & 0x0000_00ff)
}
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub const fn makedev(major: u64, minor: u64) -> dev_t {
((major & 0xffff_f000) << 32) |
((major & 0x0000_0fff) << 8) |
((minor & 0xffff_ff00) << 12) |
(minor & 0x0000_00ff)
}
pub fn umask(mode: Mode) -> Mode {
let prev = unsafe { libc::umask(mode.bits() as mode_t) };
Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
}
pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
let mut dst = mem::MaybeUninit::uninit();
let res = path.with_nix_path(|cstr| {
unsafe {
libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
}
})?;
Errno::result(res)?;
Ok(unsafe{dst.assume_init()})
}
pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
let mut dst = mem::MaybeUninit::uninit();
let res = path.with_nix_path(|cstr| {
unsafe {
libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
}
})?;
Errno::result(res)?;
Ok(unsafe{dst.assume_init()})
}
pub fn fstat(fd: RawFd) -> Result<FileStat> {
let mut dst = mem::MaybeUninit::uninit();
let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
Errno::result(res)?;
Ok(unsafe{dst.assume_init()})
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
let mut dst = mem::MaybeUninit::uninit();
let res = pathname.with_nix_path(|cstr| {
unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
})?;
Errno::result(res)?;
Ok(unsafe{dst.assume_init()})
}
pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
Errno::result(res).map(drop)
}
#[derive(Clone, Copy, Debug)]
pub enum FchmodatFlags {
FollowSymlink,
NoFollowSymlink,
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn fchmodat<P: ?Sized + NixPath>(
dirfd: Option<RawFd>,
path: &P,
mode: Mode,
flag: FchmodatFlags,
) -> Result<()> {
let atflag =
match flag {
FchmodatFlags::FollowSymlink => AtFlags::empty(),
FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
};
let res = path.with_nix_path(|cstr| unsafe {
libc::fchmodat(
at_rawfd(dirfd),
cstr.as_ptr(),
mode.bits() as mode_t,
atflag.bits() as libc::c_int,
)
})?;
Errno::result(res).map(drop)
}
pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = path.with_nix_path(|cstr| unsafe {
libc::utimes(cstr.as_ptr(), ×[0])
})?;
Errno::result(res).map(drop)
}
#[cfg(any(target_os = "linux",
target_os = "haiku",
target_os = "ios",
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = path.with_nix_path(|cstr| unsafe {
libc::lutimes(cstr.as_ptr(), ×[0])
})?;
Errno::result(res).map(drop)
}
#[inline]
pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = unsafe { libc::futimens(fd, ×[0]) };
Errno::result(res).map(drop)
}
#[derive(Clone, Copy, Debug)]
pub enum UtimensatFlags {
FollowSymlink,
NoFollowSymlink,
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn utimensat<P: ?Sized + NixPath>(
dirfd: Option<RawFd>,
path: &P,
atime: &TimeSpec,
mtime: &TimeSpec,
flag: UtimensatFlags
) -> Result<()> {
let atflag =
match flag {
UtimensatFlags::FollowSymlink => AtFlags::empty(),
UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
};
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = path.with_nix_path(|cstr| unsafe {
libc::utimensat(
at_rawfd(dirfd),
cstr.as_ptr(),
×[0],
atflag.bits() as libc::c_int,
)
})?;
Errno::result(res).map(drop)
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
let res = path.with_nix_path(|cstr| {
unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
})?;
Errno::result(res).map(drop)
}