|  | 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(target_os = "linux")] | 
|  | pub fn major(dev: dev_t) -> u64 { | 
|  | ((dev >> 32) & 0xffff_f000) | | 
|  | ((dev >>  8) & 0x0000_0fff) | 
|  | } | 
|  |  | 
|  | #[cfg(target_os = "linux")] | 
|  | pub fn minor(dev: dev_t) -> u64 { | 
|  | ((dev >> 12) & 0xffff_ff00) | | 
|  | ((dev      ) & 0x0000_00ff) | 
|  | } | 
|  |  | 
|  | #[cfg(target_os = "linux")] | 
|  | pub 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"))] | 
|  | 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()}) | 
|  | } | 
|  |  | 
|  | /// Change the file permission bits of the file specified by a file descriptor. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). | 
|  | pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { | 
|  | let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; | 
|  |  | 
|  | Errno::result(res).map(drop) | 
|  | } | 
|  |  | 
|  | /// Flags for `fchmodat` function. | 
|  | #[derive(Clone, Copy, Debug)] | 
|  | pub enum FchmodatFlags { | 
|  | FollowSymlink, | 
|  | NoFollowSymlink, | 
|  | } | 
|  |  | 
|  | /// Change the file permission bits. | 
|  | /// | 
|  | /// The file to be changed is determined relative to the directory associated | 
|  | /// with the file descriptor `dirfd` or the current working directory | 
|  | /// if `dirfd` is `None`. | 
|  | /// | 
|  | /// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, | 
|  | /// then the mode of the symbolic link is changed. | 
|  | /// | 
|  | /// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to | 
|  | /// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented | 
|  | /// in the `nix` crate. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). | 
|  | #[cfg(not(target_os = "redox"))] | 
|  | 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) | 
|  | } | 
|  |  | 
|  | /// Change the access and modification times of a file. | 
|  | /// | 
|  | /// `utimes(path, times)` is identical to | 
|  | /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former | 
|  | /// is a deprecated API so prefer using the latter if the platforms you care | 
|  | /// about support it. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). | 
|  | 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) | 
|  | } | 
|  |  | 
|  | /// Change the access and modification times of a file without following symlinks. | 
|  | /// | 
|  | /// `lutimes(path, times)` is identical to | 
|  | /// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former | 
|  | /// is a deprecated API so prefer using the latter if the platforms you care | 
|  | /// about support it. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). | 
|  | #[cfg(any(target_os = "linux", | 
|  | target_os = "haiku", | 
|  | target_os = "ios", | 
|  | target_os = "macos", | 
|  | target_os = "freebsd", | 
|  | target_os = "netbsd"))] | 
|  | 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) | 
|  | } | 
|  |  | 
|  | /// Change the access and modification times of the file specified by a file descriptor. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). | 
|  | #[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) | 
|  | } | 
|  |  | 
|  | /// Flags for `utimensat` function. | 
|  | #[derive(Clone, Copy, Debug)] | 
|  | pub enum UtimensatFlags { | 
|  | FollowSymlink, | 
|  | NoFollowSymlink, | 
|  | } | 
|  |  | 
|  | /// Change the access and modification times of a file. | 
|  | /// | 
|  | /// The file to be changed is determined relative to the directory associated | 
|  | /// with the file descriptor `dirfd` or the current working directory | 
|  | /// if `dirfd` is `None`. | 
|  | /// | 
|  | /// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link, | 
|  | /// then the mode of the symbolic link is changed. | 
|  | /// | 
|  | /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to | 
|  | /// `utimes(path, times)`. The latter is a deprecated API so prefer using the | 
|  | /// former if the platforms you care about support it. | 
|  | /// | 
|  | /// # References | 
|  | /// | 
|  | /// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). | 
|  | #[cfg(not(target_os = "redox"))] | 
|  | 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"))] | 
|  | 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) | 
|  | } |