|
1 | 1 | //! Safe wrappers around functions found in libc "unistd.h" header
|
2 | 2 |
|
3 | 3 | use {Errno, Error, Result, NixPath};
|
4 |
| -use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; |
| 4 | +use fcntl::{AtFlags, fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; |
5 | 5 | use fcntl::FcntlArg::F_SETFD;
|
6 | 6 | use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t};
|
7 | 7 | use std::mem;
|
8 | 8 | use std::ffi::{CString, CStr, OsString, OsStr};
|
9 | 9 | use std::os::unix::ffi::{OsStringExt, OsStrExt};
|
10 | 10 | use std::os::unix::io::RawFd;
|
11 |
| -use std::path::{PathBuf}; |
| 11 | +use std::path::PathBuf; |
12 | 12 | use void::Void;
|
13 | 13 | use sys::stat::Mode;
|
14 | 14 |
|
@@ -819,6 +819,79 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
|
819 | 819 | Ok((fd, PathBuf::from(pathname)))
|
820 | 820 | }
|
821 | 821 |
|
| 822 | +libc_bitflags!{ |
| 823 | + /// Flags that determine what permissions to check for in [`access`](fn.access.html) |
| 824 | + /// and [`faccessat`](fn.faccessat.html) functions. |
| 825 | + pub flags AccessFlags: c_int { |
| 826 | + /// Read permission. |
| 827 | + R_OK, |
| 828 | + /// Write permission. |
| 829 | + W_OK, |
| 830 | + /// Execute permission. |
| 831 | + X_OK, |
| 832 | + } |
| 833 | +} |
| 834 | + |
| 835 | +/// Whether [`access`](fn.access.html) and [`faccessat`](fn.faccessat.html) functions |
| 836 | +/// should check whether a file exists or whether the current process has the requested |
| 837 | +/// permissions to access it. |
| 838 | +pub enum AccessMode { |
| 839 | + /// Check whether the file exists. |
| 840 | + F_OK, |
| 841 | + /// Check whether the file exists and the current process has the requested |
| 842 | + /// permissions to access it. |
| 843 | + Flags(AccessFlags), |
| 844 | +} |
| 845 | + |
| 846 | +impl AccessMode { |
| 847 | + /// Convert the `enum AccessMode` + `flags AccessFlags` combo to the plain |
| 848 | + /// `mode: c_int` syscalls expect. |
| 849 | + fn to_libc_type(&self) -> c_int { |
| 850 | + match self { |
| 851 | + &AccessMode::F_OK => libc::F_OK, |
| 852 | + &AccessMode::Flags(flags) => flags.bits(), |
| 853 | + } |
| 854 | + } |
| 855 | +} |
| 856 | + |
| 857 | +/// Check whether a file exists or whether the current process can access a file ([see access(2)] |
| 858 | +/// (http://man7.org/linux/man-pages/man2/access.2.html)). |
| 859 | +/// |
| 860 | +/// # Example |
| 861 | +/// ``` |
| 862 | +/// use nix::unistd::*; |
| 863 | +/// |
| 864 | +/// let devnull_exists = access("/dev/null", AccessMode::F_OK); |
| 865 | +/// assert!(devnull_exists.is_ok()); |
| 866 | +/// ``` |
| 867 | +pub fn access<P: ?Sized + NixPath>(path: &P, mode: AccessMode) -> Result<()> { |
| 868 | + let res = try!(path.with_nix_path(|path| |
| 869 | + unsafe { |
| 870 | + libc::access(path.as_ptr(), mode.to_libc_type()) |
| 871 | + } |
| 872 | + )); |
| 873 | + Errno::result(res).map(drop) |
| 874 | +} |
| 875 | + |
| 876 | +/// Check whether a file exists or whether the current process can access a file, |
| 877 | +/// relative to a directory file descriptor ([see faccessat(2)] |
| 878 | +/// (http://man7.org/linux/man-pages/man2/faccessat.2.html)). |
| 879 | +pub fn faccessat<P: ?Sized + NixPath>(dirfd: RawFd, |
| 880 | + path: &P, |
| 881 | + mode: AccessMode, |
| 882 | + flags: AtFlags) |
| 883 | + -> Result<()> { |
| 884 | + let res = try!(path.with_nix_path(|path| |
| 885 | + unsafe { |
| 886 | + libc::faccessat(dirfd, |
| 887 | + path.as_ptr(), |
| 888 | + mode.to_libc_type(), |
| 889 | + flags.bits()) |
| 890 | + } |
| 891 | + )); |
| 892 | + Errno::result(res).map(drop) |
| 893 | +} |
| 894 | + |
822 | 895 | #[cfg(any(target_os = "linux", target_os = "android"))]
|
823 | 896 | mod linux {
|
824 | 897 | use libc::{self, uid_t, gid_t};
|
|
0 commit comments