diff --git a/src/dir.rs b/src/dir.rs index 5ce503644e..93ca6c938f 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -6,6 +6,7 @@ use crate::sys; use crate::{Error, NixPath, Result}; use cfg_if::cfg_if; use std::ffi; +use std::os::unix::io::AsFd; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use std::ptr; @@ -39,18 +40,18 @@ impl Dir { mode: sys::stat::Mode, ) -> Result { let fd = fcntl::open(path, oflag, mode)?; - Dir::from_fd(fd) + Dir::from_fd(fd.into_raw_fd()) } /// Opens the given path as with `fcntl::openat`. pub fn openat( - dirfd: RawFd, + dirfd: &impl AsFd, path: &P, oflag: OFlag, mode: sys::stat::Mode, ) -> Result { let fd = fcntl::openat(dirfd, path, oflag, mode)?; - Dir::from_fd(fd) + Dir::from_fd(fd.into_raw_fd()) } /// Converts from a descriptor-based object, closing the descriptor on success or failure. @@ -240,7 +241,7 @@ impl Entry { /// Returns the bare file name of this directory entry without any other leading path component. pub fn file_name(&self) -> &ffi::CStr { - unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } + unsafe { ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } } /// Returns the type of this directory entry, if known. diff --git a/src/fcntl.rs b/src/fcntl.rs index 650828345b..e67139c1fb 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -1,9 +1,11 @@ use crate::errno::Errno; use libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; use std::ffi::OsString; -#[cfg(not(target_os = "redox"))] -use std::os::raw; use std::os::unix::ffi::OsStringExt; +use std::os::unix::io::AsFd; +use std::os::unix::io::AsRawFd; +use std::os::unix::io::FromRawFd; +use std::os::unix::io::OwnedFd; use std::os::unix::io::RawFd; #[cfg(feature = "fs")] @@ -193,51 +195,61 @@ feature! { // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] -pub fn open(path: &P, oflag: OFlag, mode: Mode) -> Result { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } +pub fn open( + path: &(impl ?Sized + NixPath), + oflag: OFlag, + mode: Mode, +) -> Result { + let fd = path.with_nix_path(|cstr| unsafe { + libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) })?; - Errno::result(fd) + Errno::result(fd).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) } // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] #[cfg(not(target_os = "redox"))] -pub fn openat( - dirfd: RawFd, - path: &P, +pub fn openat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), oflag: OFlag, mode: Mode, -) -> Result { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } +) -> Result { + let fd = path.with_nix_path(|cstr| unsafe { + libc::openat( + dirfd.as_fd().as_raw_fd(), + cstr.as_ptr(), + oflag.bits(), + mode.bits() as c_uint, + ) })?; - Errno::result(fd) + + Errno::result(fd).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) } #[cfg(not(target_os = "redox"))] -pub fn renameat( - old_dirfd: Option, - old_path: &P1, - new_dirfd: Option, - new_path: &P2, +pub fn renameat( + old_dirfd: &impl AsFd, + old_path: &(impl ?Sized + NixPath), + new_dirfd: &impl AsFd, + new_path: &(impl ?Sized + NixPath), ) -> Result<()> { let res = old_path.with_nix_path(|old_cstr| { new_path.with_nix_path(|new_cstr| unsafe { libc::renameat( - at_rawfd(old_dirfd), + old_dirfd.as_fd().as_raw_fd(), old_cstr.as_ptr(), - at_rawfd(new_dirfd), + new_dirfd.as_fd().as_raw_fd(), new_cstr.as_ptr(), ) }) })??; Errno::result(res).map(drop) -} + } } -#[cfg(all(target_os = "linux", target_env = "gnu",))] +#[cfg(all(target_os = "linux", target_env = "gnu"))] #[cfg(feature = "fs")] libc_bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] @@ -250,23 +262,20 @@ libc_bitflags! { feature! { #![feature = "fs"] -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] -pub fn renameat2( - old_dirfd: Option, - old_path: &P1, - new_dirfd: Option, - new_path: &P2, +#[cfg(all(target_os = "linux", target_env = "gnu"))] +pub fn renameat2( + old_dirfd: &impl AsFd, + old_path: &(impl ?Sized + NixPath), + new_dirfd: &impl AsFd, + new_path: &(impl ?Sized + NixPath), flags: RenameFlags, ) -> Result<()> { let res = old_path.with_nix_path(|old_cstr| { new_path.with_nix_path(|new_cstr| unsafe { libc::renameat2( - at_rawfd(old_dirfd), + old_dirfd.as_fd().as_raw_fd(), old_cstr.as_ptr(), - at_rawfd(new_dirfd), + new_dirfd.as_fd().as_raw_fd(), new_cstr.as_ptr(), flags.bits(), ) @@ -278,21 +287,21 @@ pub fn renameat2( fn wrap_readlink_result(mut v: Vec, len: ssize_t) -> Result { unsafe { v.set_len(len as usize) } v.shrink_to_fit(); - Ok(OsString::from_vec(v.to_vec())) + Ok(OsString::from_vec(v)) } -fn readlink_maybe_at( - dirfd: Option, - path: &P, +fn readlink_maybe_at( + dirfd: Option<&impl AsFd>, + path: &(impl ?Sized + NixPath), v: &mut Vec, -) -> Result { +) -> Result { path.with_nix_path(|cstr| unsafe { match dirfd { #[cfg(target_os = "redox")] Some(_) => unreachable!(), #[cfg(not(target_os = "redox"))] Some(dirfd) => libc::readlinkat( - dirfd, + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), v.as_mut_ptr() as *mut c_char, v.capacity() as size_t, @@ -306,76 +315,99 @@ fn readlink_maybe_at( }) } -fn inner_readlink(dirfd: Option, path: &P) -> Result { +fn inner_readlink( + dirfd: Option<&impl AsFd>, + path: &(impl ?Sized + NixPath), +) -> Result { let mut v = Vec::with_capacity(libc::PATH_MAX as usize); - // simple case: result is strictly less than `PATH_MAX` - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - return wrap_readlink_result(v, res); + + { + // simple case: result is strictly less than `PATH_MAX` + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + return wrap_readlink_result(v, res); + } } + // Uh oh, the result is too long... // Let's try to ask lstat how many bytes to allocate. - let reported_size = match dirfd { - #[cfg(target_os = "redox")] - Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(dirfd) => { - let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; - super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) - }, - #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] - Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), - None => super::sys::stat::lstat(path) - } + let mut try_size = { + let reported_size = match dirfd { + #[cfg(target_os = "redox")] + Some(_) => unreachable!(), + #[cfg(any(target_os = "android", target_os = "linux"))] + Some(dirfd) => { + let flags = if path.is_empty() { + AtFlags::AT_EMPTY_PATH + } else { + AtFlags::empty() + }; + super::sys::stat::fstatat( + dirfd, + path, + flags | AtFlags::AT_SYMLINK_NOFOLLOW, + ) + } + #[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "redox" + )))] + Some(dirfd) => super::sys::stat::fstatat( + dirfd, + path, + AtFlags::AT_SYMLINK_NOFOLLOW, + ), + None => super::sys::stat::lstat(path), + } .map(|x| x.st_size) .unwrap_or(0); - let mut try_size = if reported_size > 0 { - // Note: even if `lstat`'s apparently valid answer turns out to be - // wrong, we will still read the full symlink no matter what. - reported_size as usize + 1 - } else { - // If lstat doesn't cooperate, or reports an error, be a little less - // precise. - (libc::PATH_MAX as usize).max(128) << 1 + + if reported_size > 0 { + // Note: even if `lstat`'s apparently valid answer turns out to be + // wrong, we will still read the full symlink no matter what. + reported_size as usize + 1 + } else { + // If lstat doesn't cooperate, or reports an error, be a little less + // precise. + (libc::PATH_MAX as usize).max(128) << 1 + } }; + loop { - v.reserve_exact(try_size); - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - break wrap_readlink_result(v, res); - } else { - // Ugh! Still not big enough! - match try_size.checked_shl(1) { - Some(next_size) => try_size = next_size, - // It's absurd that this would happen, but handle it sanely - // anyway. - None => break Err(Errno::ENAMETOOLONG), + { + v.reserve_exact(try_size); + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + return wrap_readlink_result(v, res); } } + + // Ugh! Still not big enough! + match try_size.checked_shl(1) { + Some(next_size) => try_size = next_size, + // It's absurd that this would happen, but handle it sanely + // anyway. + None => break Err(Errno::ENAMETOOLONG), + } } } -pub fn readlink(path: &P) -> Result { - inner_readlink(None, path) +pub fn readlink(path: &(impl ?Sized + NixPath)) -> Result { + inner_readlink(None::<&OwnedFd>, path) } #[cfg(not(target_os = "redox"))] -pub fn readlinkat(dirfd: RawFd, path: &P) -> Result { +pub fn readlinkat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), +) -> Result { inner_readlink(Some(dirfd), path) } - -/// Computes the raw fd consumed by a function of the form `*at`. -#[cfg(not(target_os = "redox"))] -pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { - match fd { - None => libc::AT_FDCWD, - Some(fd) => fd, - } -} } #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] @@ -566,9 +598,9 @@ feature! { /// returned. #[cfg(any(target_os = "android", target_os = "linux"))] pub fn copy_file_range( - fd_in: RawFd, + fd_in: &impl AsFd, off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, + fd_out: &impl AsFd, off_out: Option<&mut libc::loff_t>, len: usize, ) -> Result { @@ -580,11 +612,10 @@ pub fn copy_file_range( .unwrap_or(ptr::null_mut()); let ret = unsafe { - libc::syscall( - libc::SYS_copy_file_range, - fd_in, + libc::copy_file_range( + fd_in.as_fd().as_raw_fd(), off_in, - fd_out, + fd_out.as_fd().as_raw_fd(), off_out, len, 0, @@ -595,9 +626,9 @@ pub fn copy_file_range( #[cfg(any(target_os = "linux", target_os = "android"))] pub fn splice( - fd_in: RawFd, + fd_in: &impl AsFd, off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, + fd_out: &impl AsFd, off_out: Option<&mut libc::loff_t>, len: usize, flags: SpliceFFlags, @@ -609,26 +640,46 @@ pub fn splice( .map(|offset| offset as *mut libc::loff_t) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; + let ret = unsafe { + libc::splice( + fd_in.as_fd().as_raw_fd(), + off_in, + fd_out.as_fd().as_raw_fd(), + off_out, + len, + flags.bits(), + ) + }; Errno::result(ret).map(|r| r as usize) } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result { - let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; +pub fn tee( + fd_in: &impl AsFd, + fd_out: &impl AsFd, + len: usize, + flags: SpliceFFlags, +) -> Result { + let ret = unsafe { + libc::tee( + fd_in.as_fd().as_raw_fd(), + fd_out.as_fd().as_raw_fd(), + len, + flags.bits(), + ) + }; Errno::result(ret).map(|r| r as usize) } #[cfg(any(target_os = "linux", target_os = "android"))] pub fn vmsplice( - fd: RawFd, + fd: &impl AsFd, iov: &[std::io::IoSlice<'_>], - flags: SpliceFFlags - ) -> Result -{ + flags: SpliceFFlags, +) -> Result { let ret = unsafe { libc::vmsplice( - fd, + fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len(), flags.bits(), @@ -681,12 +732,14 @@ feature! { #[cfg(any(target_os = "linux"))] #[cfg(feature = "fs")] pub fn fallocate( - fd: RawFd, + fd: &impl AsFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t, ) -> Result<()> { - let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) }; + let res = unsafe { + libc::fallocate(fd.as_fd().as_raw_fd(), mode.bits(), offset, len) + }; Errno::result(res).map(drop) } @@ -739,30 +792,38 @@ impl SpacectlRange { #[cfg_attr(not(fbsd14), doc = " ```no_run")] /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; -/// # use std::os::unix::io::AsRawFd; /// # use nix::fcntl::*; /// # use tempfile::tempfile; +/// /// const INITIAL: &[u8] = b"0123456789abcdef"; /// let mut f = tempfile().unwrap(); /// f.write_all(INITIAL).unwrap(); /// let mut range = SpacectlRange(3, 6); /// while (!range.is_empty()) { -/// range = fspacectl(f.as_raw_fd(), range).unwrap(); +/// range = fspacectl(f, range).unwrap(); /// } /// let mut buf = vec![0; INITIAL.len()]; /// f.read_exact_at(&mut buf, 0).unwrap(); /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] -pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { - let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; - let res = unsafe { libc::fspacectl( - fd, +pub fn fspacectl( + fd: &impl AsFd, + range: SpacectlRange, +) -> Result { + let mut rqsr = libc::spacectl_range { + r_offset: range.0, + r_len: range.1, + }; + let res = unsafe { + libc::fspacectl( + fd.as_fd().as_raw_fd(), libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; + 0, // No flags are currently supported + &mut rqsr, + ) + }; Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) } @@ -785,30 +846,37 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { #[cfg_attr(not(fbsd14), doc = " ```no_run")] /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; -/// # use std::os::unix::io::AsRawFd; /// # use nix::fcntl::*; /// # use tempfile::tempfile; +/// /// const INITIAL: &[u8] = b"0123456789abcdef"; /// let mut f = tempfile().unwrap(); /// f.write_all(INITIAL).unwrap(); -/// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap(); +/// fspacectl_all(f, 3, 6).unwrap(); /// let mut buf = vec![0; INITIAL.len()]; /// f.read_exact_at(&mut buf, 0).unwrap(); /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] -pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) - -> Result<()> -{ - let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; +pub fn fspacectl_all( + fd: &impl AsFd, + offset: libc::off_t, + len: libc::off_t, +) -> Result<()> { + let mut rqsr = libc::spacectl_range { + r_offset: offset, + r_len: len, + }; while rqsr.r_len > 0 { - let res = unsafe { libc::fspacectl( - fd, + let res = unsafe { + libc::fspacectl( + fd.as_fd().as_raw_fd(), libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; + 0, // No flags are currently supported + &mut rqsr, + ) + }; Errno::result(res)?; } Ok(()) @@ -825,8 +893,9 @@ pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) ))] mod posix_fadvise { use crate::errno::Errno; - use std::os::unix::io::RawFd; use crate::Result; + use std::os::unix::io::AsFd; + use std::os::unix::io::AsRawFd; #[cfg(feature = "fs")] libc_enum! { @@ -846,19 +915,26 @@ mod posix_fadvise { feature! { #![feature = "fs"] pub fn posix_fadvise( - fd: RawFd, + fd: &impl AsFd, offset: libc::off_t, len: libc::off_t, advice: PosixFadviseAdvice, ) -> Result<()> { - let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) }; + let res = unsafe { + libc::posix_fadvise( + fd.as_fd().as_raw_fd(), + offset, + len, + advice as libc::c_int, + ) + }; if res == 0 { Ok(()) } else { Err(Errno::from_i32(res)) } - } + } } } @@ -871,8 +947,13 @@ mod posix_fadvise { target_os = "wasi", target_os = "freebsd" ))] -pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { - let res = unsafe { libc::posix_fallocate(fd, offset, len) }; +pub fn posix_fallocate( + fd: &impl AsFd, + offset: libc::off_t, + len: libc::off_t, +) -> Result<()> { + let res = + unsafe { libc::posix_fallocate(fd.as_fd().as_raw_fd(), offset, len) }; match Errno::result(res) { Err(err) => Err(err), Ok(0) => Ok(()), diff --git a/src/lib.rs b/src/lib.rs index 6b82125761..57e30a71de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,6 +157,7 @@ pub mod unistd; use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; +use std::os::unix::io::BorrowedFd; use std::path::{Path, PathBuf}; use std::{ptr, result, slice}; @@ -177,6 +178,10 @@ pub type Result = result::Result; /// ones. pub type Error = Errno; +/// A file descriptor representing the current working directory. +pub const AT_FDCWD: &BorrowedFd<'static> = + unsafe { &BorrowedFd::borrow_raw(libc::AT_FDCWD) }; + /// Common trait used to represent file system paths by many Nix functions. pub trait NixPath { /// Is the path empty? diff --git a/src/pty.rs b/src/pty.rs index 28ae5e924b..384750de92 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -81,13 +81,15 @@ impl Drop for PtyMaster { impl io::Read for PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0, buf).map_err(io::Error::from) + unistd::read(unsafe { &BorrowedFd::borrow_raw(self.0) }, buf) + .map_err(io::Error::from) } } impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0, buf).map_err(io::Error::from) + unistd::write(unsafe { &BorrowedFd::borrow_raw(self.0) }, buf) + .map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -96,13 +98,15 @@ impl io::Write for PtyMaster { impl io::Read for &PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0, buf).map_err(io::Error::from) + unistd::read(unsafe { &BorrowedFd::borrow_raw(self.0) }, buf) + .map_err(io::Error::from) } } impl io::Write for &PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0, buf).map_err(io::Error::from) + unistd::write(unsafe { &BorrowedFd::borrow_raw(self.0) }, buf) + .map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 84356ec70f..e145b57e5f 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -31,6 +31,7 @@ use cfg_if::cfg_if; use libc::{c_char, c_int}; use std::ffi::{CStr, OsStr, OsString}; use std::mem::{size_of, MaybeUninit}; +use std::os::fd::BorrowedFd; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::ptr; @@ -195,7 +196,8 @@ impl Inotify { let mut events = Vec::new(); let mut offset = 0; - let nread = read(self.fd, &mut buffer)?; + let nread = + read(unsafe { &BorrowedFd::borrow_raw(self.fd) }, &mut buffer)?; while (nread - offset) >= header_size { let event = unsafe { diff --git a/src/sys/select.rs b/src/sys/select.rs index 7a94cff87e..8d0427f7e7 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -304,6 +304,7 @@ mod tests { use super::*; use crate::sys::time::{TimeVal, TimeValLike}; use crate::unistd::{pipe, write}; + use std::os::fd::AsRawFd; use std::os::unix::io::RawFd; #[test] @@ -385,31 +386,31 @@ mod tests { #[test] fn test_select() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(r1.as_raw_fd()); + fd_set.insert(r2.as_raw_fd()); let mut timeout = TimeVal::seconds(10); assert_eq!( 1, select(None, &mut fd_set, None, None, &mut timeout).unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(r1.as_raw_fd())); + assert!(!fd_set.contains(r2.as_raw_fd())); } #[test] fn test_select_nfds() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(r1.as_raw_fd()); + fd_set.insert(r2.as_raw_fd()); let mut timeout = TimeVal::seconds(10); assert_eq!( @@ -423,25 +424,25 @@ mod tests { ) .unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(r1.as_raw_fd())); + assert!(!fd_set.contains(r2.as_raw_fd())); } #[test] fn test_select_nfds2() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(r1.as_raw_fd()); + fd_set.insert(r2.as_raw_fd()); let mut timeout = TimeVal::seconds(10); assert_eq!( 1, select( - ::std::cmp::max(r1, r2) + 1, + std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, &mut fd_set, None, None, @@ -449,7 +450,7 @@ mod tests { ) .unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(r1.as_raw_fd())); + assert!(!fd_set.contains(r2.as_raw_fd())); } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index af19c52dfd..dcda42f66e 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1426,13 +1426,15 @@ impl<'a> ControlMessage<'a> { /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; /// # use std::io::IoSlice; +/// # use std::os::fd::AsRawFd; +/// /// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, /// SockFlag::empty()) /// .unwrap(); /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); /// ``` @@ -1441,14 +1443,16 @@ impl<'a> ControlMessage<'a> { /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; /// # use std::io::IoSlice; +/// # use std::os::fd::AsRawFd; /// # use std::str::FromStr; +/// /// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), /// None).unwrap(); /// let (r, w) = pipe().unwrap(); /// /// let iov = [IoSlice::new(b"hello")]; -/// let fds = [r]; +/// let fds = [r.as_raw_fd()]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` @@ -2207,14 +2211,14 @@ pub fn recvfrom( buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, - addr.as_mut_ptr() as *mut libc::sockaddr, + addr.as_mut_ptr() as *mut sockaddr, &mut len as *mut socklen_t, ))? as usize; Ok(( ret, T::from_raw( - addr.assume_init().as_ptr() as *const libc::sockaddr, + addr.assume_init().as_ptr() as *const sockaddr, Some(len), ), )) @@ -2322,11 +2326,8 @@ pub fn getpeername(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = libc::getpeername( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); + let ret = + libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); Errno::result(ret)?; @@ -2342,11 +2343,8 @@ pub fn getsockname(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = libc::getsockname( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); + let ret = + libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); Errno::result(ret)?; diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 94be4107bc..cde56b6e92 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -10,11 +10,11 @@ pub use libc::stat as FileStat; pub use libc::{dev_t, mode_t}; #[cfg(not(target_os = "redox"))] -use crate::fcntl::{at_rawfd, AtFlags}; +use crate::fcntl::AtFlags; use crate::sys::time::{TimeSpec, TimeVal}; use crate::{errno::Errno, NixPath, Result}; use std::mem; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; libc_bitflags!( /// "File type" flags for `mknod` and related functions. @@ -156,8 +156,8 @@ libc_bitflags! { } /// Create a special or ordinary file, by pathname. -pub fn mknod( - path: &P, +pub fn mknod( + path: &(impl ?Sized + NixPath), kind: SFlag, perm: Mode, dev: dev_t, @@ -177,16 +177,16 @@ pub fn mknod( target_os = "haiku" )))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mknodat( - dirfd: RawFd, - path: &P, +pub fn mknodat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), kind: SFlag, perm: Mode, dev: dev_t, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mknodat( - dirfd, + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev, @@ -222,7 +222,7 @@ pub fn umask(mode: Mode) -> Mode { Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode") } -pub fn stat(path: &P) -> Result { +pub fn stat(path: &(impl ?Sized + NixPath)) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = path.with_nix_path(|cstr| unsafe { libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) @@ -233,7 +233,7 @@ pub fn stat(path: &P) -> Result { Ok(unsafe { dst.assume_init() }) } -pub fn lstat(path: &P) -> Result { +pub fn lstat(path: &(impl ?Sized + NixPath)) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = path.with_nix_path(|cstr| unsafe { libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) @@ -244,9 +244,9 @@ pub fn lstat(path: &P) -> Result { Ok(unsafe { dst.assume_init() }) } -pub fn fstat(fd: RawFd) -> Result { +pub fn fstat(fd: &impl AsFd) -> Result { let mut dst = mem::MaybeUninit::uninit(); - let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) }; + let res = unsafe { libc::fstat(fd.as_fd().as_raw_fd(), dst.as_mut_ptr()) }; Errno::result(res)?; @@ -255,15 +255,15 @@ pub fn fstat(fd: RawFd) -> Result { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat( - dirfd: RawFd, - pathname: &P, +pub fn fstatat( + dirfd: &impl AsFd, + pathname: &(impl ?Sized + NixPath), f: AtFlags, ) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = pathname.with_nix_path(|cstr| unsafe { libc::fstatat( - dirfd, + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int, @@ -280,8 +280,9 @@ pub fn fstatat( /// # References /// /// [fchmod(2)](https://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) }; +pub fn fchmod(fd: &impl AsFd, mode: Mode) -> Result<()> { + let res = + unsafe { libc::fchmod(fd.as_fd().as_raw_fd(), mode.bits() as mode_t) }; Errno::result(res).map(drop) } @@ -311,9 +312,9 @@ pub enum FchmodatFlags { /// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fchmodat( - dirfd: Option, - path: &P, +pub fn fchmodat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), mode: Mode, flag: FchmodatFlags, ) -> Result<()> { @@ -323,7 +324,7 @@ pub fn fchmodat( }; let res = path.with_nix_path(|cstr| unsafe { libc::fchmodat( - at_rawfd(dirfd), + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), mode.bits() as mode_t, atflag.bits() as libc::c_int, @@ -343,8 +344,8 @@ pub fn fchmodat( /// # References /// /// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). -pub fn utimes( - path: &P, +pub fn utimes( + path: &(impl ?Sized + NixPath), atime: &TimeVal, mtime: &TimeVal, ) -> Result<()> { @@ -375,8 +376,8 @@ pub fn utimes( target_os = "netbsd" ))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn lutimes( - path: &P, +pub fn lutimes( + path: &(impl ?Sized + NixPath), atime: &TimeVal, mtime: &TimeVal, ) -> Result<()> { @@ -394,9 +395,13 @@ pub fn lutimes( /// /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). #[inline] -pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { +pub fn futimens( + fd: &impl AsFd, + atime: &TimeSpec, + mtime: &TimeSpec, +) -> Result<()> { let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; - let res = unsafe { libc::futimens(fd, ×[0]) }; + let res = unsafe { libc::futimens(fd.as_fd().as_raw_fd(), ×[0]) }; Errno::result(res).map(drop) } @@ -427,9 +432,9 @@ pub enum UtimensatFlags { /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn utimensat( - dirfd: Option, - path: &P, +pub fn utimensat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), atime: &TimeSpec, mtime: &TimeSpec, flag: UtimensatFlags, @@ -441,7 +446,7 @@ pub fn utimensat( let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { libc::utimensat( - at_rawfd(dirfd), + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), ×[0], atflag.bits() as libc::c_int, @@ -453,13 +458,17 @@ pub fn utimensat( #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat( - fd: RawFd, - path: &P, +pub fn mkdirat( + fd: &impl AsFd, + path: &(impl ?Sized + NixPath), mode: Mode, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) + libc::mkdirat( + fd.as_fd().as_raw_fd(), + cstr.as_ptr(), + mode.bits() as mode_t, + ) })?; Errno::result(res).map(drop) diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index a35fc927f4..a52cc33631 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -33,24 +33,27 @@ pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; use crate::unistd::read; use crate::{errno::Errno, Result}; use libc::c_int; +use std::os::unix::io::OwnedFd; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; /// A timerfd instance. This is also a file descriptor, you can feed it to /// other interfaces consuming file descriptors, epoll for example. #[derive(Debug)] pub struct TimerFd { - fd: RawFd, + fd: OwnedFd, } impl AsRawFd for TimerFd { fn as_raw_fd(&self) -> RawFd { - self.fd + self.fd.as_raw_fd() } } impl FromRawFd for TimerFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - TimerFd { fd } + TimerFd { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + } } } @@ -97,6 +100,7 @@ impl TimerFd { Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) + .map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) .map(|fd| Self { fd }) } @@ -145,7 +149,7 @@ impl TimerFd { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timerfd_settime( - self.fd, + self.fd.as_raw_fd(), flags.bits(), timerspec.as_ref(), std::ptr::null_mut(), @@ -159,7 +163,7 @@ impl TimerFd { pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { - libc::timerfd_gettime(self.fd, timerspec.as_mut()) + libc::timerfd_gettime(self.fd.as_raw_fd(), timerspec.as_mut()) }) .map(|_| { if timerspec.as_ref().it_interval.tv_sec == 0 @@ -179,7 +183,7 @@ impl TimerFd { pub fn unset(&self) -> Result<()> { Errno::result(unsafe { libc::timerfd_settime( - self.fd, + self.fd.as_raw_fd(), TimerSetTimeFlags::empty().bits(), TimerSpec::none().as_ref(), std::ptr::null_mut(), @@ -192,7 +196,7 @@ impl TimerFd { /// /// Note: If the alarm is unset, then you will wait forever. pub fn wait(&self) -> Result<()> { - while let Err(e) = read(self.fd, &mut [0u8; 8]) { + while let Err(e) = read(&self.fd, &mut [0u8; 8]) { if e != Errno::EINTR { return Err(e); } @@ -201,14 +205,3 @@ impl TimerFd { Ok(()) } } - -impl Drop for TimerFd { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::close(self.fd) }); - if let Err(Errno::EBADF) = result { - panic!("close of TimerFd encountered EBADF"); - } - } - } -} diff --git a/src/unistd.rs b/src/unistd.rs index ca07b34a2e..b4b54afb42 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3,9 +3,9 @@ use crate::errno::{self, Errno}; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{at_rawfd, AtFlags}; +use crate::fcntl::AtFlags; #[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +use crate::fcntl::OFlag; #[cfg(all( feature = "fs", any( @@ -31,10 +31,13 @@ use std::convert::Infallible; use std::ffi::{CStr, OsString}; #[cfg(not(target_os = "redox"))] use std::ffi::{CString, OsStr}; +use std::os::fd::IntoRawFd; #[cfg(not(target_os = "redox"))] use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; +use std::os::unix::io::AsFd; use std::os::unix::io::RawFd; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; @@ -252,19 +255,30 @@ impl ForkResult { /// return value of this function. As an example: /// /// ``` -/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}}; -/// -/// match unsafe{fork()} { -/// Ok(ForkResult::Parent { child, .. }) => { -/// println!("Continuing execution in parent process, new child has pid: {}", child); -/// waitpid(child, None).unwrap(); -/// } -/// Ok(ForkResult::Child) => { -/// // Unsafe to use `println!` (or `unwrap`) here. See Safety. -/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); -/// unsafe { libc::_exit(0) }; -/// } -/// Err(_) => println!("Fork failed"), +/// use nix::{ +/// sys::wait::waitpid, +/// unistd::{fork, write, ForkResult}, +/// }; +/// use std::os::fd::BorrowedFd; +/// +/// match unsafe { fork() } { +/// Ok(ForkResult::Parent { child, .. }) => { +/// println!( +/// "Continuing execution in parent process, new child has pid: {}", +/// child +/// ); +/// waitpid(child, None).unwrap(); +/// } +/// Ok(ForkResult::Child) => { +/// // Unsafe to use `println!` (or `unwrap`) here. See Safety. +/// write( +/// unsafe { &BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }, +/// "I'm a new child process\n".as_bytes(), +/// ) +/// .ok(); +/// unsafe { libc::_exit(0) }; +/// } +/// Err(_) => println!("Fork failed"), /// } /// ``` /// @@ -425,10 +439,10 @@ feature! { /// /// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). #[inline] -pub fn dup(oldfd: RawFd) -> Result { - let res = unsafe { libc::dup(oldfd) }; +pub fn dup(oldfd: &impl AsFd) -> Result { + let res = unsafe { libc::dup(oldfd.as_fd().as_raw_fd()) }; - Errno::result(res) + Errno::result(res).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) } /// Create a copy of the specified file descriptor using the specified fd (see @@ -438,10 +452,19 @@ pub fn dup(oldfd: RawFd) -> Result { /// specified fd instead of allocating a new one. See the man pages for more /// detail on the exact behavior of this function. #[inline] -pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { - let res = unsafe { libc::dup2(oldfd, newfd) }; +pub fn dup2(oldfd: &impl AsFd, newfd: &mut OwnedFd) -> Result<()> { + let res = + unsafe { libc::dup2(oldfd.as_fd().as_raw_fd(), newfd.as_raw_fd()) }; + + Errno::result(res).map(drop) +} - Errno::result(res) +#[cfg(feature = "fs")] +libc_bitflags! { + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] + pub struct DupFlags: i32 { + O_CLOEXEC; + } } /// Create a new copy of the specified file descriptor using the specified fd @@ -449,26 +472,16 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. -pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - dup3_polyfill(oldfd, newfd, flags) -} - -#[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - if oldfd == newfd { - return Err(Errno::EINVAL); - } - - let fd = dup2(oldfd, newfd)?; - - if flags.contains(OFlag::O_CLOEXEC) { - if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { - let _ = close(fd); - return Err(e); - } - } +pub fn dup3( + oldfd: &impl AsFd, + newfd: &mut OwnedFd, + flags: DupFlags, +) -> Result<()> { + let res = unsafe { + libc::dup3(oldfd.as_fd().as_raw_fd(), newfd.as_raw_fd(), flags.bits()) + }; - Ok(fd) + Errno::result(res).map(drop) } /// Change the current working directory of the calling process (see @@ -477,10 +490,9 @@ fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { /// This function may fail in a number of different scenarios. See the man /// pages for additional details on possible failure cases. #[inline] -pub fn chdir(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chdir(cstr.as_ptr()) } - })?; +pub fn chdir(path: &(impl ?Sized + NixPath)) -> Result<()> { + let res = + path.with_nix_path(|cstr| unsafe { libc::chdir(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -493,8 +505,8 @@ pub fn chdir(path: &P) -> Result<()> { /// pages for additional details on possible failure cases. #[inline] #[cfg(not(target_os = "fuchsia"))] -pub fn fchdir(dirfd: RawFd) -> Result<()> { - let res = unsafe { libc::fchdir(dirfd) }; +pub fn fchdir(dirfd: &impl AsFd) -> Result<()> { + let res = unsafe { libc::fchdir(dirfd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -526,9 +538,9 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> { /// } /// ``` #[inline] -pub fn mkdir(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } +pub fn mkdir(path: &(impl ?Sized + NixPath), mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) @@ -565,9 +577,9 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { /// ``` #[inline] #[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet -pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } +pub fn mkfifo(path: &(impl ?Sized + NixPath), mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) @@ -585,11 +597,23 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", target_os = "ios", target_os = "haiku", - target_os = "android", target_os = "redox")))] -pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { + target_os = "macos", + target_os = "ios", + target_os = "haiku", + target_os = "android", + target_os = "redox" +)))] +pub fn mkfifoat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), + mode: Mode, +) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) + libc::mkfifoat( + dirfd.as_fd().as_raw_fd(), + cstr.as_ptr(), + mode.bits() as mode_t, + ) })?; Errno::result(res).map(drop) @@ -605,22 +629,20 @@ pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) /// /// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). #[cfg(not(target_os = "redox"))] -pub fn symlinkat( - path1: &P1, - dirfd: Option, - path2: &P2) -> Result<()> { - let res = - path1.with_nix_path(|path1| { - path2.with_nix_path(|path2| { - unsafe { - libc::symlinkat( - path1.as_ptr(), - dirfd.unwrap_or(libc::AT_FDCWD), - path2.as_ptr() - ) - } - }) - })??; +pub fn symlinkat( + path1: &(impl ?Sized + NixPath), + dirfd: &impl AsFd, + path2: &(impl ?Sized + NixPath), +) -> Result<()> { + let res = path1.with_nix_path(|path1| { + path2.with_nix_path(|path2| unsafe { + libc::symlinkat( + path1.as_ptr(), + dirfd.as_fd().as_raw_fd(), + path2.as_ptr(), + ) + }) + })??; Errno::result(res).map(drop) } } @@ -695,13 +717,18 @@ feature! { /// Computes the raw UID and GID values to pass to a `*chown` call. // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] -fn chown_raw_ids(owner: Option, group: Option) -> (libc::uid_t, libc::gid_t) { +fn chown_raw_ids( + owner: Option, + group: Option, +) -> (uid_t, gid_t) { // According to the POSIX specification, -1 is used to indicate that owner and group // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap // around to get -1. - let uid = owner.map(Into::into) + let uid = owner + .map(Into::into) .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); - let gid = group.map(Into::into) + let gid = group + .map(Into::into) .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); (uid, gid) } @@ -714,7 +741,11 @@ fn chown_raw_ids(owner: Option, group: Option) -> (libc::uid_t, libc:: /// provided for that argument. Ownership change will be attempted for the path /// only if `Some` owner/group is provided. #[inline] -pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { +pub fn chown( + path: &(impl ?Sized + NixPath), + owner: Option, + group: Option, +) -> Result<()> { let res = path.with_nix_path(|cstr| { let (uid, gid) = chown_raw_ids(owner, group); unsafe { libc::chown(cstr.as_ptr(), uid, gid) } @@ -731,9 +762,13 @@ pub fn chown(path: &P, owner: Option, group: Option, group: Option) -> Result<()> { +pub fn fchown( + fd: &impl AsFd, + owner: Option, + group: Option, +) -> Result<()> { let (uid, gid) = chown_raw_ids(owner, group); - let res = unsafe { libc::fchown(fd, uid, gid) }; + let res = unsafe { libc::fchown(fd.as_fd().as_raw_fd(), uid, gid) }; Errno::result(res).map(drop) } @@ -766,22 +801,26 @@ pub enum FchownatFlags { /// /// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). #[cfg(not(target_os = "redox"))] -pub fn fchownat( - dirfd: Option, - path: &P, +pub fn fchownat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), owner: Option, group: Option, flag: FchownatFlags, ) -> Result<()> { - let atflag = - match flag { - FchownatFlags::FollowSymlink => AtFlags::empty(), - FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; + let atflag = match flag { + FchownatFlags::FollowSymlink => AtFlags::empty(), + FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); - libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int) + libc::fchownat( + dirfd.as_fd().as_raw_fd(), + cstr.as_ptr(), + uid, + gid, + atflag.bits() as c_int, + ) })?; Errno::result(res).map(drop) @@ -808,14 +847,11 @@ fn to_exec_array>(args: &[S]) -> Vec<*const c_char> { pub fn execv>(path: &CStr, argv: &[S]) -> Result { let args_p = to_exec_array(argv); - unsafe { - libc::execv(path.as_ptr(), args_p.as_ptr()) - }; + unsafe { libc::execv(path.as_ptr(), args_p.as_ptr()) }; Err(Errno::last()) } - /// Replace the current process image with a new one (see /// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). /// @@ -829,13 +865,15 @@ pub fn execv>(path: &CStr, argv: &[S]) -> Result { /// in the `args` list is an argument to the new process. Each element in the /// `env` list should be a string in the form "key=value". #[inline] -pub fn execve, SE: AsRef>(path: &CStr, args: &[SA], env: &[SE]) -> Result { +pub fn execve, SE: AsRef>( + path: &CStr, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); - unsafe { - libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) - }; + unsafe { libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) }; Err(Errno::last()) } @@ -850,12 +888,13 @@ pub fn execve, SE: AsRef>(path: &CStr, args: &[SA], env: & /// would not work if "bash" was specified for the path argument, but `execvp` /// would assuming that a bash executable was on the system `PATH`. #[inline] -pub fn execvp>(filename: &CStr, args: &[S]) -> Result { +pub fn execvp>( + filename: &CStr, + args: &[S], +) -> Result { let args_p = to_exec_array(args); - unsafe { - libc::execvp(filename.as_ptr(), args_p.as_ptr()) - }; + unsafe { libc::execvp(filename.as_ptr(), args_p.as_ptr()) }; Err(Errno::last()) } @@ -867,10 +906,12 @@ pub fn execvp>(filename: &CStr, args: &[S]) -> Result /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an /// environment and have a search path. See these two for additional /// information. -#[cfg(any(target_os = "haiku", - target_os = "linux", - target_os = "openbsd"))] -pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], env: &[SE]) -> Result { +#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +pub fn execvpe, SE: AsRef>( + filename: &CStr, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -891,18 +932,22 @@ pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], e /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -#[cfg(any(target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd"))] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd" +))] #[inline] -pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[SE]) -> Result { +pub fn fexecve, SE: AsRef>( + fd: &impl AsFd, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); - unsafe { - libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) - }; + unsafe { libc::fexecve(fd.as_fd().as_raw_fd(), args_p.as_ptr(), env_p.as_ptr()) }; Err(Errno::last()) } @@ -919,14 +964,25 @@ pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[ /// is referenced as a file descriptor to the base directory plus a path. #[cfg(any(target_os = "android", target_os = "linux"))] #[inline] -pub fn execveat,SE: AsRef>(dirfd: RawFd, pathname: &CStr, args: &[SA], - env: &[SE], flags: super::fcntl::AtFlags) -> Result { +pub fn execveat, SE: AsRef>( + dirfd: &impl AsFd, + pathname: &CStr, + args: &[SA], + env: &[SE], + flags: super::fcntl::AtFlags, +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); unsafe { - libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), - args_p.as_ptr(), env_p.as_ptr(), flags); + libc::syscall( + libc::SYS_execveat, + dirfd.as_fd().as_raw_fd(), + pathname.as_ptr(), + args_p.as_ptr(), + env_p.as_ptr(), + flags, + ); }; Err(Errno::last()) @@ -957,14 +1013,16 @@ pub fn execveat,SE: AsRef>(dirfd: RawFd, pathname: &CStr, /// descriptors will remain identical after daemonizing. /// * `noclose = false`: The process' stdin, stdout, and stderr will point to /// `/dev/null` after daemonizing. -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" +))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; Errno::result(res).map(drop) @@ -1045,32 +1103,28 @@ pub fn gethostname() -> Result { /// /// # Examples /// -/// ```no_run -/// use std::os::unix::io::AsRawFd; -/// use nix::unistd::close; -/// -/// let f = tempfile::tempfile().unwrap(); -/// close(f.as_raw_fd()).unwrap(); // Bad! f will also close on drop! -/// ``` -/// /// ```rust -/// use std::os::unix::io::IntoRawFd; +/// use std::os::unix::io::AsFd; /// use nix::unistd::close; /// /// let f = tempfile::tempfile().unwrap(); -/// close(f.into_raw_fd()).unwrap(); // Good. into_raw_fd consumes f +/// close(f).unwrap(); /// ``` -pub fn close(fd: RawFd) -> Result<()> { - let res = unsafe { libc::close(fd) }; +pub fn close(fd: impl IntoRawFd) -> Result<()> { + let res = unsafe { libc::close(fd.into_raw_fd()) }; Errno::result(res).map(drop) } /// Read from a raw file descriptor. /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) -pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { +pub fn read(fd: &impl AsFd, buf: &mut [u8]) -> Result { let res = unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) + libc::read( + fd.as_fd().as_raw_fd(), + buf.as_mut_ptr() as *mut c_void, + buf.len() as size_t, + ) }; Errno::result(res).map(|r| r as usize) @@ -1079,9 +1133,13 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { /// Write to a raw file descriptor. /// /// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) -pub fn write(fd: RawFd, buf: &[u8]) -> Result { +pub fn write(fd: &impl AsFd, buf: &[u8]) -> Result { let res = unsafe { - libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + libc::write( + fd.as_fd().as_raw_fd(), + buf.as_ptr() as *const c_void, + buf.len() as size_t, + ) }; Errno::result(res).map(|r| r as usize) @@ -1106,37 +1164,47 @@ pub enum Whence { /// Specify an offset relative to the next location in the file greater than or /// equal to offset that contains some data. If offset points to /// some data, then the file offset is set to offset. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + ))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than /// or equal to offset. If offset points into the middle of a hole, then /// the file offset should be set to offset. If there is no hole past offset, /// then the file offset should be adjusted to the end of the file (i.e., there /// is an implicit hole at the end of any file). - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] - SeekHole = libc::SEEK_HOLE + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + ))] + SeekHole = libc::SEEK_HOLE, } /// Move the read/write file offset. /// /// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) -pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result { - let res = unsafe { libc::lseek(fd, offset, whence as i32) }; +pub fn lseek(fd: &impl AsFd, offset: off_t, whence: Whence) -> Result { + let res = + unsafe { libc::lseek(fd.as_fd().as_raw_fd(), offset, whence as i32) }; Errno::result(res).map(|r| r as off_t) } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result { - let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; +pub fn lseek64( + fd: &impl AsFd, + offset: libc::off64_t, + whence: Whence, +) -> Result { + let res = + unsafe { libc::lseek64(fd.as_fd().as_raw_fd(), offset, whence as i32) }; Errno::result(res).map(|r| r as libc::off64_t) } @@ -1145,14 +1213,18 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result std::result::Result<(RawFd, RawFd), Error> { +pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; Error::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }.map( + |fds| unsafe { + (OwnedFd::from_raw_fd(fds.0), OwnedFd::from_raw_fd(fds.1)) + }, + ) } feature! { @@ -1163,31 +1235,42 @@ feature! { /// created: /// /// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. -#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")] -#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")] +#[cfg_attr( + target_os = "linux", + doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode." +)] +#[cfg_attr( + target_os = "netbsd", + doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`." +)] /// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. /// /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" +))] +pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); - let res = unsafe { - libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) - }; + let res = + unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) }; Errno::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }.map( + |fds| unsafe { + (OwnedFd::from_raw_fd(fds.0), OwnedFd::from_raw_fd(fds.1)) + }, + ) } /// Truncate a file to a specified length @@ -1195,12 +1278,9 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { /// See also /// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -pub fn truncate(path: &P, len: off_t) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::truncate(cstr.as_ptr(), len) - } - })?; +pub fn truncate(path: &(impl ?Sized + NixPath), len: off_t) -> Result<()> { + let res = path + .with_nix_path(|cstr| unsafe { libc::truncate(cstr.as_ptr(), len) })?; Errno::result(res).map(drop) } @@ -1209,22 +1289,23 @@ pub fn truncate(path: &P, len: off_t) -> Result<()> { /// /// See also /// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) -pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { - Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) +pub fn ftruncate(fd: &impl AsFd, len: off_t) -> Result<()> { + Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }) + .map(drop) } -pub fn isatty(fd: RawFd) -> Result { +pub fn isatty(fd: &impl AsFd) -> Result { unsafe { // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so // we return `Ok(false)` - if libc::isatty(fd) == 1 { + if libc::isatty(fd.as_fd().as_raw_fd()) == 1 { Ok(true) } else { match Errno::last() { Errno::ENOTTY => Ok(false), err => Err(err), } - } + } } } @@ -1249,47 +1330,38 @@ pub enum LinkatFlags { /// # References /// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html) #[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet -pub fn linkat( - olddirfd: Option, - oldpath: &P, - newdirfd: Option, - newpath: &P, +pub fn linkat( + olddirfd: &impl AsFd, + oldpath: &(impl ?Sized + NixPath), + newdirfd: &impl AsFd, + newpath: &(impl ?Sized + NixPath), flag: LinkatFlags, ) -> Result<()> { + let atflag = match flag { + LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, + LinkatFlags::NoSymlinkFollow => AtFlags::empty(), + }; - let atflag = - match flag { - LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, - LinkatFlags::NoSymlinkFollow => AtFlags::empty(), - }; - - let res = - oldpath.with_nix_path(|oldcstr| { - newpath.with_nix_path(|newcstr| { - unsafe { - libc::linkat( - at_rawfd(olddirfd), - oldcstr.as_ptr(), - at_rawfd(newdirfd), - newcstr.as_ptr(), - atflag.bits() as libc::c_int - ) - } - }) - })??; + let res = oldpath.with_nix_path(|oldcstr| { + newpath.with_nix_path(|newcstr| unsafe { + libc::linkat( + olddirfd.as_fd().as_raw_fd(), + oldcstr.as_ptr(), + newdirfd.as_fd().as_raw_fd(), + newcstr.as_ptr(), + atflag.bits() as c_int, + ) + }) + })??; Errno::result(res).map(drop) } - /// Remove a directory entry /// /// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) -pub fn unlink(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlink(cstr.as_ptr()) - } - })?; +pub fn unlink(path: &(impl ?Sized + NixPath)) -> Result<()> { + let res = + path.with_nix_path(|cstr| unsafe { libc::unlink(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -1311,31 +1383,30 @@ pub enum UnlinkatFlags { /// # References /// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html) #[cfg(not(target_os = "redox"))] -pub fn unlinkat( - dirfd: Option, - path: &P, +pub fn unlinkat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), flag: UnlinkatFlags, ) -> Result<()> { - let atflag = - match flag { - UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, - UnlinkatFlags::NoRemoveDir => AtFlags::empty(), - }; - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) - } + let atflag = match flag { + UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, + UnlinkatFlags::NoRemoveDir => AtFlags::empty(), + }; + let res = path.with_nix_path(|cstr| unsafe { + libc::unlinkat( + dirfd.as_fd().as_raw_fd(), + cstr.as_ptr(), + atflag.bits() as c_int, + ) })?; Errno::result(res).map(drop) } - #[inline] #[cfg(not(target_os = "fuchsia"))] -pub fn chroot(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chroot(cstr.as_ptr()) } - })?; +pub fn chroot(path: &(impl ?Sized + NixPath)) -> Result<()> { + let res = + path.with_nix_path(|cstr| unsafe { libc::chroot(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -1359,8 +1430,8 @@ pub fn sync() { /// /// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) #[cfg(target_os = "linux")] -pub fn syncfs(fd: RawFd) -> Result<()> { - let res = unsafe { libc::syncfs(fd) }; +pub fn syncfs(fd: &impl AsFd) -> Result<()> { + let res = unsafe { libc::syncfs(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -1369,8 +1440,8 @@ pub fn syncfs(fd: RawFd) -> Result<()> { /// /// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) #[inline] -pub fn fsync(fd: RawFd) -> Result<()> { - let res = unsafe { libc::fsync(fd) }; +pub fn fsync(fd: &impl AsFd) -> Result<()> { + let res = unsafe { libc::fsync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -1379,18 +1450,20 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris"))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos", + target_os = "solaris" +))] #[inline] -pub fn fdatasync(fd: RawFd) -> Result<()> { - let res = unsafe { libc::fdatasync(fd) }; +pub fn fdatasync(fd: &impl AsFd) -> Result<()> { + let res = unsafe { libc::fdatasync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -1860,7 +1933,7 @@ pub mod acct { /// Enable process accounting /// /// See also [acct(2)](https://linux.die.net/man/2/acct) - pub fn enable(filename: &P) -> Result<()> { + pub fn enable(filename: &(impl ?Sized + NixPath)) -> Result<()> { let res = filename.with_nix_path(|cstr| { unsafe { libc::acct(cstr.as_ptr()) } })?; @@ -1904,7 +1977,7 @@ feature! { /// // do something with fd /// ``` #[inline] -pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { +pub fn mkstemp(template: &(impl ?Sized + NixPath)) -> Result<(RawFd, PathBuf)> { let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; let p = path.as_mut_ptr() as *mut _; let fd = unsafe { libc::mkstemp(p) }; @@ -2093,7 +2166,7 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result> { /// - `Ok(None)`: the variable has no limit (for limit variables) or is /// unsupported (for option variables) /// - `Err(x)`: an error occurred -pub fn pathconf(path: &P, var: PathconfVar) -> Result> { +pub fn pathconf(path: &(impl ?Sized + NixPath), var: PathconfVar) -> Result> { let raw = path.with_nix_path(|cstr| { unsafe { Errno::clear(); @@ -2739,28 +2812,29 @@ pub fn sysconf(var: SysconfVar) -> Result> { } } -feature! { -#![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "fs")] mod pivot_root { - use crate::{Result, NixPath}; use crate::errno::Errno; + use crate::{NixPath, Result}; - pub fn pivot_root( - new_root: &P1, put_old: &P2) -> Result<()> { + pub fn pivot_root( + new_root: &(impl ?Sized + NixPath), + put_old: &(impl ?Sized + NixPath), + ) -> Result<()> { let res = new_root.with_nix_path(|new_root| { - put_old.with_nix_path(|put_old| { - unsafe { - libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) - } + put_old.with_nix_path(|put_old| unsafe { + libc::syscall( + libc::SYS_pivot_root, + new_root.as_ptr(), + put_old.as_ptr(), + ) }) })??; Errno::result(res).map(drop) } } -} #[cfg(any( target_os = "android", @@ -2903,11 +2977,9 @@ feature! { /// Checks the file named by `path` for accessibility according to the flags given by `amode` /// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) -pub fn access(path: &P, amode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::access(cstr.as_ptr(), amode.bits) - } +pub fn access(path: &(impl ?Sized + NixPath), amode: AccessFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::access(cstr.as_ptr(), amode.bits) })?; Errno::result(res).map(drop) } @@ -2923,11 +2995,19 @@ pub fn access(path: &P, amode: AccessFlags) -> Result<()> { /// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) // redox: does not appear to support the *at family of syscalls. #[cfg(not(target_os = "redox"))] -pub fn faccessat(dirfd: Option, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits()) - } +pub fn faccessat( + dirfd: &impl AsFd, + path: &(impl ?Sized + NixPath), + mode: AccessFlags, + flags: AtFlags, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::faccessat( + dirfd.as_fd().as_raw_fd(), + cstr.as_ptr(), + mode.bits(), + flags.bits(), + ) })?; Errno::result(res).map(drop) } @@ -2944,11 +3024,9 @@ pub fn faccessat(dirfd: Option, path: &P, mode: Acce target_os = "freebsd", target_os = "dragonfly" ))] -pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::eaccess(cstr.as_ptr(), mode.bits) - } +pub fn eaccess(path: &(impl ?Sized + NixPath), mode: AccessFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::eaccess(cstr.as_ptr(), mode.bits) })?; Errno::result(res).map(drop) } @@ -3373,7 +3451,7 @@ feature! { target_os = "macos", target_os = "ios" ))] -pub fn chflags(path: &P, flags: FileFlag) -> Result<()> { +pub fn chflags(path: &(impl ?Sized + NixPath), flags: FileFlag) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::chflags(cstr.as_ptr(), flags.bits()) })?; diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs index 40bda4d90a..c6f86c66ea 100644 --- a/test/sys/test_select.rs +++ b/test/sys/test_select.rs @@ -2,18 +2,19 @@ use nix::sys::select::*; use nix::sys::signal::SigSet; use nix::sys::time::{TimeSpec, TimeValLike}; use nix::unistd::{pipe, write}; +use std::os::fd::AsRawFd; #[test] pub fn test_pselect() { let _mtx = crate::SIGNAL_MTX.lock(); let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(r1.as_raw_fd()); + fd_set.insert(r2.as_raw_fd()); let timeout = TimeSpec::seconds(10); let sigmask = SigSet::empty(); @@ -21,25 +22,25 @@ pub fn test_pselect() { 1, pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(r1.as_raw_fd())); + assert!(!fd_set.contains(r2.as_raw_fd())); } #[test] pub fn test_pselect_nfds2() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + write(&w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(r1.as_raw_fd()); + fd_set.insert(r2.as_raw_fd()); let timeout = TimeSpec::seconds(10); assert_eq!( 1, pselect( - ::std::cmp::max(r1, r2) + 1, + ::std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, &mut fd_set, None, None, @@ -48,8 +49,8 @@ pub fn test_pselect_nfds2() { ) .unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(r1.as_raw_fd())); + assert!(!fd_set.contains(r2.as_raw_fd())); } macro_rules! generate_fdset_bad_fd_tests { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 7ab60ecc28..1dead31025 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -10,6 +10,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::mem::{self, MaybeUninit}; use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::os::fd::AsRawFd; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; @@ -275,9 +276,9 @@ pub fn test_socketpair() { SockFlag::empty(), ) .unwrap(); - write(fd1, b"hello").unwrap(); + write(unsafe { &BorrowedFd::borrow_raw(fd1) }, b"hello").unwrap(); let mut buf = [0; 5]; - read(fd2, &mut buf).unwrap(); + read(unsafe { &BorrowedFd::borrow_raw(fd2) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"hello"); } @@ -771,7 +772,7 @@ pub fn test_scm_rights() { { let iov = [IoSlice::new(b"hello")]; - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsg = ControlMessage::ScmRights(&fds); assert_eq!( sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), @@ -812,12 +813,11 @@ pub fn test_scm_rights() { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w, b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); + read(unsafe { &BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); - close(w).unwrap(); } // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross @@ -876,7 +876,11 @@ pub fn test_af_alg_cipher() { // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + let num_bytes = read( + unsafe { &BorrowedFd::borrow_raw(session_socket) }, + &mut encrypted, + ) + .expect("read encrypt"); assert_eq!(num_bytes, payload_len); let iov = IoSlice::new(&encrypted); @@ -892,7 +896,11 @@ pub fn test_af_alg_cipher() { // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + let num_bytes = read( + unsafe { &BorrowedFd::borrow_raw(session_socket) }, + &mut decrypted, + ) + .expect("read decrypt"); assert_eq!(num_bytes, payload_len); assert_eq!(decrypted, payload); @@ -973,7 +981,11 @@ pub fn test_af_alg_aead() { // allocate buffer for encrypted data let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + let num_bytes = read( + unsafe { &BorrowedFd::borrow_raw(session_socket) }, + &mut encrypted, + ) + .expect("read encrypt"); assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); close(session_socket).expect("close"); @@ -1004,7 +1016,11 @@ pub fn test_af_alg_aead() { // Do not block on read, as we may have fewer bytes than buffer size fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) .expect("fcntl non_blocking"); - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + let num_bytes = read( + unsafe { &BorrowedFd::borrow_raw(session_socket) }, + &mut decrypted, + ) + .expect("read decrypt"); assert!(num_bytes >= payload_len + (assoc_size as usize)); assert_eq!( @@ -1424,7 +1440,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { gid: getgid().as_raw(), } .into(); - let fds = [r]; + let fds = [r.as_raw_fd()]; let cmsgs = [ ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), @@ -1474,12 +1490,11 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w, b"world").unwrap(); + write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); + read(unsafe { &BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); - close(w).unwrap(); } // Test creating and using named unix domain sockets @@ -1512,14 +1527,15 @@ pub fn test_unixdomain() { ) .expect("socket failed"); connect(s2, &sockaddr).expect("connect failed"); - write(s2, b"hello").expect("write failed"); + write(unsafe { &BorrowedFd::borrow_raw(s2) }, b"hello") + .expect("write failed"); close(s2).unwrap(); }); let s3 = accept(s1).expect("accept failed"); let mut buf = [0; 5]; - read(s3, &mut buf).unwrap(); + read(unsafe { &BorrowedFd::borrow_raw(s3) }, &mut buf).unwrap(); close(s3).unwrap(); close(s1).unwrap(); thr.join().unwrap(); diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 2ddbf77b83..171ac02e81 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -134,7 +134,7 @@ fn test_so_tcp_maxseg() { .unwrap(); connect(ssock, &sock_addr).unwrap(); let rsess = accept(rsock).unwrap(); - write(rsess, b"hello").unwrap(); + write(unsafe { &BorrowedFd::borrow_raw(rsess) }, b"hello").unwrap(); let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap(); // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index aaf00084fa..cf41071ae8 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -11,7 +11,8 @@ use nix::unistd::{close, read, write}; fn write_all(f: RawFd, buf: &[u8]) { let mut len = 0; while len < buf.len() { - len += write(f, &buf[len..]).unwrap(); + len += + write(unsafe { &BorrowedFd::borrow_raw(f) }, &buf[len..]).unwrap(); } } @@ -129,7 +130,8 @@ fn test_local_flags() { // Try to read from the master, which should not have anything as echoing was disabled. let mut buf = [0u8; 10]; - let read = read(pty.master, &mut buf).unwrap_err(); + let read = read(unsafe { &BorrowedFd::borrow_raw(pty.master) }, &mut buf) + .unwrap_err(); close(pty.master).unwrap(); close(pty.slave).unwrap(); assert_eq!(read, Errno::EAGAIN); diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 0f4b8a6568..5aad6fa982 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -45,18 +45,16 @@ fn test_writev() { // FileDesc will close its filedesc (reader). let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); // Blocking io, should write all data. - let write_res = writev(writer, &iovecs); + let write_res = writev(writer.as_raw_fd(), &iovecs); let written = write_res.expect("couldn't write"); // Check whether we written all data assert_eq!(to_write.len(), written); - let read_res = read(reader, &mut read_buf[..]); + let read_res = read(&reader, &mut read_buf[..]); let read = read_res.expect("couldn't read"); // Check we have read as much as we written assert_eq!(read, written); // Check equality of written and read data assert_eq!(&to_write, &read_buf); - close(writer).expect("closed writer"); - close(reader).expect("closed reader"); } #[test] @@ -87,8 +85,8 @@ fn test_readv() { } let (reader, writer) = pipe().expect("couldn't create pipe"); // Blocking io, should write all data. - write(writer, &to_write).expect("write failed"); - let read = readv(reader, &mut iovecs[..]).expect("read failed"); + write(&writer, &to_write).expect("write failed"); + let read = readv(reader.as_raw_fd(), &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); // Cccumulate data from iovecs @@ -100,8 +98,6 @@ fn test_readv() { assert_eq!(read_buf.len(), to_write.len()); // Check equality of written and read data assert_eq!(&read_buf, &to_write); - close(reader).expect("couldn't close reader"); - close(writer).expect("couldn't close writer"); } #[test] @@ -236,8 +232,8 @@ fn test_process_vm_readv() { Parent { child } => { close(w).unwrap(); // wait for child - read(r, &mut [0u8]).unwrap(); - close(r).unwrap(); + read(&r, &mut [0u8]).unwrap(); + drop(r); let ptr = vector.as_ptr() as usize; let remote_iov = RemoteIoVec { base: ptr, len: 5 }; @@ -260,8 +256,8 @@ fn test_process_vm_readv() { for i in &mut vector { *i += 1; } - let _ = write(w, b"\0"); - let _ = close(w); + let _ = write(&w, b"\0"); + drop(w); loop { pause(); } diff --git a/test/test.rs b/test/test.rs index 6b42aad950..378e9f8220 100644 --- a/test/test.rs +++ b/test/test.rs @@ -66,6 +66,7 @@ mod test_unistd; use nix::unistd::{chdir, getcwd, read}; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; +use std::os::fd::BorrowedFd; use std::os::unix::io::RawFd; use std::path::PathBuf; @@ -75,7 +76,7 @@ fn read_exact(f: RawFd, buf: &mut [u8]) { while len < buf.len() { // get_mut would be better than split_at_mut, but it requires nightly let (_, remaining) = buf.split_at_mut(len); - len += read(f, remaining).unwrap(); + len += read(unsafe { &BorrowedFd::borrow_raw(f) }, remaining).unwrap(); } } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 345e04daa5..40e7033ef7 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -42,7 +42,7 @@ fn test_openat() { open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) .unwrap(); let fd = openat( - dirfd, + &dirfd, tmp.path().file_name().unwrap(), OFlag::O_RDONLY, Mode::empty(), @@ -50,11 +50,8 @@ fn test_openat() { .unwrap(); let mut buf = [0u8; 1024]; - assert_eq!(4, read(fd, &mut buf).unwrap()); + assert_eq!(4, read(&fd, &mut buf).unwrap()); assert_eq!(CONTENTS, &buf[0..4]); - - close(fd).unwrap(); - close(dirfd).unwrap(); } #[test] @@ -68,13 +65,11 @@ fn test_renameat() { let new_dir = tempfile::tempdir().unwrap(); let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); + renameat(&old_dirfd, "old", &new_dirfd, "new").unwrap(); assert_eq!( - renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), + renameat(&old_dirfd, "old", &new_dirfd, "new").unwrap_err(), Errno::ENOENT ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); assert!(new_dir.path().join("new").exists()); } @@ -98,23 +93,11 @@ fn test_renameat2_behaves_like_renameat_with_no_flags() { let new_dir = tempfile::tempdir().unwrap(); let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty(), - ) - .unwrap(); + renameat2(&old_dirfd, "old", &new_dirfd, "new", RenameFlags::empty()) + .unwrap(); assert_eq!( - renameat2( - Some(old_dirfd), - "old", - Some(new_dirfd), - "new", - RenameFlags::empty() - ) - .unwrap_err(), + renameat2(&old_dirfd, "old", &new_dirfd, "new", RenameFlags::empty()) + .unwrap_err(), Errno::ENOENT ); close(old_dirfd).unwrap(); @@ -151,9 +134,9 @@ fn test_renameat2_exchange() { new_f.write_all(b"new").unwrap(); } renameat2( - Some(old_dirfd), + &old_dirfd, "old", - Some(new_dirfd), + &new_dirfd, "new", RenameFlags::RENAME_EXCHANGE, ) @@ -194,9 +177,9 @@ fn test_renameat2_noreplace() { File::create(new_path).unwrap(); assert_eq!( renameat2( - Some(old_dirfd), + &old_dirfd, "old", - Some(new_dirfd), + &new_dirfd, "new", RenameFlags::RENAME_NOREPLACE ) @@ -222,7 +205,7 @@ fn test_readlink() { assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); assert_eq!( - readlinkat(dirfd, "b").unwrap().to_str().unwrap(), + readlinkat(&dirfd, "b").unwrap().to_str().unwrap(), expected_dir ); } @@ -235,7 +218,7 @@ mod linux_android { use std::os::unix::prelude::*; use nix::fcntl::*; - use nix::unistd::{close, pipe, read, write}; + use nix::unistd::{pipe, read, write}; use tempfile::tempfile; #[cfg(any(target_os = "linux"))] @@ -262,14 +245,7 @@ mod linux_android { tmp1.flush().unwrap(); let mut from_offset: i64 = 3; - copy_file_range( - tmp1.as_raw_fd(), - Some(&mut from_offset), - tmp2.as_raw_fd(), - None, - 3, - ) - .unwrap(); + copy_file_range(&tmp1, Some(&mut from_offset), &tmp2, None, 3).unwrap(); let mut res: String = String::new(); tmp2.seek(SeekFrom::Start(0)).unwrap(); @@ -288,9 +264,9 @@ mod linux_android { let (rd, wr) = pipe().unwrap(); let mut offset: loff_t = 5; let res = splice( - tmp.as_raw_fd(), + &tmp, Some(&mut offset), - wr, + &wr, None, 2, SpliceFFlags::empty(), @@ -300,12 +276,9 @@ mod linux_android { assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(&rd, &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); } #[test] @@ -313,25 +286,20 @@ mod linux_android { let (rd1, wr1) = pipe().unwrap(); let (rd2, wr2) = pipe().unwrap(); - write(wr1, b"abc").unwrap(); - let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap(); + write(&wr1, b"abc").unwrap(); + let res = tee(&rd1, &wr2, 2, SpliceFFlags::empty()).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; // Check the tee'd bytes are at rd2. - assert_eq!(2, read(rd2, &mut buf).unwrap()); + assert_eq!(2, read(&rd2, &mut buf).unwrap()); assert_eq!(b"ab", &buf[0..2]); // Check all the bytes are still at rd1. - assert_eq!(3, read(rd1, &mut buf).unwrap()); + assert_eq!(3, read(&rd1, &mut buf).unwrap()); assert_eq!(b"abc", &buf[0..3]); - - close(rd1).unwrap(); - close(wr1).unwrap(); - close(rd2).unwrap(); - close(wr2).unwrap(); } #[test] @@ -342,17 +310,14 @@ mod linux_android { let buf2 = b"defghi"; let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; - let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); + let res = vmsplice(&wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); assert_eq!(6, res); // Check the bytes can be read at rd. let mut buf = [0u8; 32]; - assert_eq!(6, read(rd, &mut buf).unwrap()); + assert_eq!(6, read(&rd, &mut buf).unwrap()); assert_eq!(b"abcdef", &buf[0..6]); - - close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(any(target_os = "linux"))] @@ -360,7 +325,7 @@ mod linux_android { fn test_fallocate() { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); + let fd = unsafe { &BorrowedFd::borrow_raw(tmp.as_raw_fd()) }; fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); // Check if we read exactly 100 bytes @@ -382,7 +347,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); + let fd = unsafe { &BorrowedFd::borrow_raw(tmp.as_raw_fd()) }; let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in @@ -400,14 +365,15 @@ mod linux_android { flock.l_start = 0; flock.l_len = 0; flock.l_pid = 0; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); + fcntl(fd.as_raw_fd(), F_OFD_SETLKW(&flock)).expect("write lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "WRITE".to_string())), lock_info(inode) ); flock.l_type = libc::F_UNLCK as libc::c_short; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed"); + fcntl(fd.as_raw_fd(), F_OFD_SETLKW(&flock)) + .expect("write unlock failed"); assert_eq!(None, lock_info(inode)); } @@ -420,7 +386,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); + let fd = unsafe { &BorrowedFd::borrow_raw(tmp.as_raw_fd()) }; let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in @@ -438,14 +404,15 @@ mod linux_android { flock.l_start = 0; flock.l_len = 0; flock.l_pid = 0; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); + fcntl(fd.as_raw_fd(), F_OFD_SETLKW(&flock)).expect("read lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "READ".to_string())), lock_info(inode) ); flock.l_type = libc::F_UNLCK as libc::c_short; - fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed"); + fcntl(fd.as_raw_fd(), F_OFD_SETLKW(&flock)) + .expect("read unlock failed"); assert_eq!(None, lock_info(inode)); } @@ -481,17 +448,17 @@ mod linux_android { target_os = "freebsd" ))] mod test_posix_fadvise { - use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; - use std::os::unix::io::{AsRawFd, RawFd}; + use std::os::fd::BorrowedFd; + use std::os::unix::io::AsRawFd; use tempfile::NamedTempFile; #[test] fn test_success() { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); + let fd = unsafe { &BorrowedFd::borrow_raw(tmp.as_raw_fd()) }; posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) .expect("posix_fadvise failed"); } @@ -499,12 +466,8 @@ mod test_posix_fadvise { #[test] fn test_errno() { let (rd, _wr) = pipe().unwrap(); - let res = posix_fadvise( - rd as RawFd, - 0, - 100, - PosixFadviseAdvice::POSIX_FADV_WILLNEED, - ); + let res = + posix_fadvise(&rd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); assert_eq!(res, Err(Errno::ESPIPE)); } } @@ -523,18 +486,19 @@ mod test_posix_fallocate { use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; - use std::{ - io::Read, - os::unix::io::{AsRawFd, RawFd}, - }; + use std::os::fd::BorrowedFd; + use std::{io::Read, os::unix::io::AsRawFd}; use tempfile::NamedTempFile; #[test] fn success() { const LEN: usize = 100; let mut tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - let res = posix_fallocate(fd, 0, LEN as libc::off_t); + let res = posix_fallocate( + unsafe { &BorrowedFd::borrow_raw(tmp.as_raw_fd()) }, + 0, + LEN as libc::off_t, + ); match res { Ok(_) => { let mut data = [1u8; LEN]; @@ -556,7 +520,7 @@ mod test_posix_fallocate { #[test] fn errno() { let (rd, _wr) = pipe().unwrap(); - let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + let err = posix_fallocate(&rd, 0, 100).unwrap_err(); match err { Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), errno => panic!("unexpected errno {}", errno,), diff --git a/test/test_poll.rs b/test/test_poll.rs index 53964e26bb..7bf6d0f2b8 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -3,6 +3,7 @@ use nix::{ poll::{poll, PollFd, PollFlags}, unistd::{pipe, write}, }; +use std::os::fd::AsRawFd; macro_rules! loop_while_eintr { ($poll_expr: expr) => { @@ -19,14 +20,14 @@ macro_rules! loop_while_eintr { #[test] fn test_poll() { let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_raw_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let nfds = loop_while_eintr!(poll(&mut fds, 100)); assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + write(&w, b".").unwrap(); // Poll a readable pipe. Should return an event. let nfds = poll(&mut fds, 100).unwrap(); @@ -51,7 +52,7 @@ fn test_ppoll() { let timeout = TimeSpec::milliseconds(1); let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + let mut fds = [PollFd::new(r.as_raw_fd(), PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let sigset = SigSet::empty(); @@ -59,7 +60,7 @@ fn test_ppoll() { assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); - write(w, b".").unwrap(); + write(&w, b".").unwrap(); // Poll a readable pipe. Should return an event. let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); diff --git a/test/test_pty.rs b/test/test_pty.rs index 5c27e2d632..a08c5acbbc 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -138,9 +138,7 @@ fn open_ptty_pair() -> (PtyMaster, File) { } } - let slave = unsafe { File::from_raw_fd(slave_fd) }; - - (master, slave) + (master, File::from(slave_fd)) } /// Test opening a master/slave PTTY pair @@ -208,7 +206,11 @@ fn test_openpty() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); + write( + unsafe { &BorrowedFd::borrow_raw(pty.master) }, + string.as_bytes(), + ) + .unwrap(); crate::read_exact(pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -222,7 +224,11 @@ fn test_openpty() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\r\n"; let mut buf = [0u8; 14]; - write(pty.slave, string2.as_bytes()).unwrap(); + write( + unsafe { &BorrowedFd::borrow_raw(pty.slave) }, + string2.as_bytes(), + ) + .unwrap(); crate::read_exact(pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -257,7 +263,11 @@ fn test_openpty_with_termios() { // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); + write( + unsafe { &BorrowedFd::borrow_raw(pty.master) }, + string.as_bytes(), + ) + .unwrap(); crate::read_exact(pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -270,7 +280,11 @@ fn test_openpty_with_termios() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\n"; let mut buf = [0u8; 13]; - write(pty.slave, string2.as_bytes()).unwrap(); + write( + unsafe { &BorrowedFd::borrow_raw(pty.slave) }, + string2.as_bytes(), + ) + .unwrap(); crate::read_exact(pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -294,7 +308,11 @@ fn test_forkpty() { let pty = unsafe { forkpty(None, None).unwrap() }; match pty.fork_result { Child => { - write(STDOUT_FILENO, string.as_bytes()).unwrap(); + write( + unsafe { &BorrowedFd::borrow_raw(STDOUT_FILENO) }, + string.as_bytes(), + ) + .unwrap(); pause(); // we need the child to stay alive until the parent calls read unsafe { _exit(0); diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index f73a3b56c3..4b931111f9 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -7,7 +7,7 @@ use tempfile::tempfile; cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { - use nix::unistd::{close, pipe, read}; + use nix::unistd::{pipe, read}; } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] { use std::net::Shutdown; use std::os::unix::net::UnixStream; @@ -23,17 +23,15 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + let res = sendfile(wr.as_raw_fd(), tmp.as_raw_fd(), Some(&mut offset), 2) + .unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(&rd, &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "linux")] @@ -45,17 +43,15 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + let res = sendfile64(wr.as_raw_fd(), tmp.as_raw_fd(), Some(&mut offset), 2) + .unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; - assert_eq!(2, read(rd, &mut buf).unwrap()); + assert_eq!(2, read(&rd, &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); - - close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "freebsd")] diff --git a/test/test_stat.rs b/test/test_stat.rs index 55f15c0771..df2709b7ba 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -1,6 +1,7 @@ #[cfg(not(any(target_os = "redox", target_os = "haiku")))] use std::fs; use std::fs::File; +use std::os::fd::BorrowedFd; #[cfg(not(target_os = "redox"))] use std::os::unix::fs::symlink; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] @@ -14,6 +15,7 @@ use std::time::{Duration, UNIX_EPOCH}; use libc::mode_t; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] use libc::{S_IFLNK, S_IFMT}; +use nix::AT_FDCWD; #[cfg(not(target_os = "redox"))] use nix::errno::Errno; @@ -103,7 +105,7 @@ fn test_stat_and_fstat() { let stat_result = stat(&filename); assert_stat_results(stat_result); - let fstat_result = fstat(file.as_raw_fd()); + let fstat_result = fstat(&file); assert_stat_results(fstat_result); } @@ -114,10 +116,10 @@ fn test_fstatat() { let filename = tempdir.path().join("foo.txt"); File::create(&filename).unwrap(); let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), Mode::empty()) + .unwrap(); - let result = - stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); + let result = stat::fstatat(&dirfd, &filename, fcntl::AtFlags::empty()); assert_stat_results(result); } @@ -142,7 +144,7 @@ fn test_stat_fstat_lstat() { let lstat_result = lstat(&linkname); assert_lstat_results(lstat_result); - let fstat_result = fstat(link.as_raw_fd()); + let fstat_result = fstat(&link); assert_stat_results(fstat_result); } @@ -155,14 +157,14 @@ fn test_fchmod() { let mut mode1 = Mode::empty(); mode1.insert(Mode::S_IRUSR); mode1.insert(Mode::S_IWUSR); - fchmod(file.as_raw_fd(), mode1).unwrap(); + fchmod(&file, mode1).unwrap(); let file_stat1 = stat(&filename).unwrap(); assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); let mut mode2 = Mode::empty(); mode2.insert(Mode::S_IROTH); - fchmod(file.as_raw_fd(), mode2).unwrap(); + fchmod(&file, mode2).unwrap(); let file_stat2 = stat(&filename).unwrap(); assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); @@ -178,14 +180,13 @@ fn test_fchmodat() { File::create(&fullpath).unwrap(); let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), Mode::empty()) .unwrap(); let mut mode1 = Mode::empty(); mode1.insert(Mode::S_IRUSR); mode1.insert(Mode::S_IWUSR); - fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink) - .unwrap(); + fchmodat(&dirfd, filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); let file_stat1 = stat(&fullpath).unwrap(); assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); @@ -194,7 +195,7 @@ fn test_fchmodat() { let mut mode2 = Mode::empty(); mode2.insert(Mode::S_IROTH); - fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); + fchmodat(AT_FDCWD, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); let file_stat2 = stat(&fullpath).unwrap(); assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); @@ -272,10 +273,10 @@ fn test_futimens() { let fullpath = tempdir.path().join("file"); drop(File::create(&fullpath).unwrap()); - let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let fd = + fcntl::open(&fullpath, fcntl::OFlag::empty(), Mode::empty()).unwrap(); - futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); + futimens(&fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap()); } @@ -289,11 +290,11 @@ fn test_utimensat() { drop(File::create(&fullpath).unwrap()); let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), Mode::empty()) .unwrap(); utimensat( - Some(dirfd), + &dirfd, filename, &TimeSpec::seconds(12345), &TimeSpec::seconds(678), @@ -305,7 +306,7 @@ fn test_utimensat() { chdir(tempdir.path()).unwrap(); utimensat( - None, + AT_FDCWD, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800), @@ -321,23 +322,22 @@ fn test_mkdirat_success_path() { let tempdir = tempfile::tempdir().unwrap(); let filename = "example_subdir"; let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(&dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); assert!(Path::exists(&tempdir.path().join(filename))); } #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_mkdirat_success_mode() { - let expected_bits = - stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); + let expected_bits = stat::SFlag::S_IFDIR.bits() | Mode::S_IRWXU.bits(); let tempdir = tempfile::tempdir().unwrap(); let filename = "example_subdir"; let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), Mode::empty()) .unwrap(); - mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); + mkdirat(&dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); let permissions = fs::metadata(tempdir.path().join(filename)) .unwrap() .permissions(); @@ -354,10 +354,10 @@ fn test_mkdirat_fail() { let dirfd = fcntl::open( &tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT, - stat::Mode::empty(), + Mode::empty(), ) .unwrap(); - let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); + let result = mkdirat(&dirfd, filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } @@ -402,7 +402,7 @@ fn test_mknodat() { let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); mknodat( - target_dir.as_raw_fd(), + unsafe { &BorrowedFd::borrow_raw(target_dir.as_raw_fd()) }, file_name, SFlag::S_IFREG, Mode::S_IRWXU, @@ -410,7 +410,7 @@ fn test_mknodat() { ) .unwrap(); let mode = fstatat( - target_dir.as_raw_fd(), + unsafe { &BorrowedFd::borrow_raw(target_dir.as_raw_fd()) }, file_name, AtFlags::AT_SYMLINK_NOFOLLOW, ) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 9e20f977ec..da0add93e7 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,10 +1,10 @@ use libc::{_exit, mode_t, off_t}; use nix::errno::Errno; +#[cfg(not(target_os = "redox"))] +use nix::fcntl::open; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] use nix::fcntl::readlink; use nix::fcntl::OFlag; -#[cfg(not(target_os = "redox"))] -use nix::fcntl::{self, open}; #[cfg(not(any( target_os = "redox", target_os = "fuchsia", @@ -19,6 +19,7 @@ use nix::sys::stat::{self, Mode, SFlag}; use nix::sys::wait::*; use nix::unistd::ForkResult::*; use nix::unistd::*; +use nix::AT_FDCWD; use std::env; #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] use std::ffi::CString; @@ -26,6 +27,7 @@ use std::ffi::CString; use std::fs::DirBuilder; use std::fs::{self, File}; use std::io::Write; +use std::mem::ManuallyDrop; use std::os::unix::prelude::*; #[cfg(not(any( target_os = "fuchsia", @@ -47,7 +49,7 @@ fn test_fork_and_waitpid() { Child => unsafe { _exit(0) }, Parent { child } => { // assert that child was created and pid > 0 - let child_raw: ::libc::pid_t = child.into(); + let child_raw: libc::pid_t = child.into(); assert!(child_raw > 0); let wait_status = waitpid(child, None); match wait_status { @@ -113,7 +115,7 @@ fn test_mkfifo() { mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); let stats = stat::stat(&mkfifo_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); + let typ = SFlag::from_bits_truncate(stats.st_mode as mode_t); assert_eq!(typ, SFlag::S_IFIFO); } @@ -138,10 +140,10 @@ fn test_mkfifoat_none() { let tempdir = tempdir().unwrap(); let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); - mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); + mkfifoat(AT_FDCWD, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); let stats = stat::stat(&mkfifoat_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + let typ = SFlag::from_bits_truncate(stats.st_mode); assert_eq!(typ, SFlag::S_IFIFO); } @@ -154,17 +156,14 @@ fn test_mkfifoat_none() { target_os = "haiku" )))] fn test_mkfifoat() { - use nix::fcntl; - let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let mkfifoat_name = "mkfifoat_name"; - mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); + mkfifoat(&dirfd, mkfifoat_name, Mode::S_IRUSR).unwrap(); - let stats = - stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + let stats = stat::fstatat(&dirfd, mkfifoat_name, AtFlags::empty()).unwrap(); + let typ = SFlag::from_bits_truncate(stats.st_mode); assert_eq!(typ, SFlag::S_IFIFO); } @@ -180,7 +179,7 @@ fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); // mkfifoat should fail if a directory is given - mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR) + mkfifoat(AT_FDCWD, &env::temp_dir(), Mode::S_IRUSR) .expect_err("assertion failed"); } @@ -197,16 +196,16 @@ fn test_mkfifoat_directory() { let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let mkfifoat_dir = "mkfifoat_dir"; - stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); + stat::mkdirat(&dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); - mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) + mkfifoat(&dirfd, mkfifoat_dir, Mode::S_IRUSR) .expect_err("assertion failed"); } #[test] fn test_getpid() { - let pid: ::libc::pid_t = getpid().into(); - let ppid: ::libc::pid_t = getppid().into(); + let pid: libc::pid_t = getpid().into(); + let ppid: libc::pid_t = getppid().into(); assert!(pid > 0); assert!(ppid > 0); } @@ -214,8 +213,8 @@ fn test_getpid() { #[test] #[cfg(not(target_os = "redox"))] fn test_getsid() { - let none_sid: ::libc::pid_t = getsid(None).unwrap().into(); - let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into(); + let none_sid: libc::pid_t = getsid(None).unwrap().into(); + let pid_sid: libc::pid_t = getsid(Some(getpid())).unwrap().into(); assert!(none_sid > 0); assert_eq!(none_sid, pid_sid); } @@ -226,7 +225,7 @@ mod linux_android { #[test] fn test_gettid() { - let tid: ::libc::pid_t = gettid().into(); + let tid: libc::pid_t = gettid().into(); assert!(tid > 0); } } @@ -315,8 +314,9 @@ macro_rules! execve_test_factory ( const BAZ: &'static [u8] = b"baz=quux\0"; fn syscall_cstr_ref() -> Result { + let exe = $exe; $syscall( - $exe, + &exe, $(CString::new($pathname).unwrap().as_c_str(), )* &[CStr::from_bytes_with_nul(EMPTY).unwrap(), CStr::from_bytes_with_nul(DASH_C).unwrap(), @@ -327,8 +327,9 @@ macro_rules! execve_test_factory ( } fn syscall_cstring() -> Result { + let exe = $exe; $syscall( - $exe, + &exe, $(CString::new($pathname).unwrap().as_c_str(), )* &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()), CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()), @@ -356,7 +357,8 @@ macro_rules! execve_test_factory ( match unsafe{fork()}.unwrap() { Child => { // Make `writer` be the stdout of the new process. - dup2(writer, 1).unwrap(); + let mut stdout = ManuallyDrop::new(unsafe { OwnedFd::from_raw_fd(libc::STDOUT_FILENO) }); + dup2(&writer, &mut stdout).unwrap(); let r = syscall(); let _ = std::io::stderr() .write_all(format!("{:?}", r).as_bytes()); @@ -370,7 +372,7 @@ macro_rules! execve_test_factory ( assert_eq!(ws, Ok(WaitStatus::Exited(child, 0))); // Read 1024 bytes. let mut buf = [0u8; 1024]; - read(reader, &mut buf).unwrap(); + read(&reader, &mut buf).unwrap(); // It should contain the things we printed using `/bin/sh`. let string = String::from_utf8_lossy(&buf); assert!(string.contains("nix!!!")); @@ -409,8 +411,8 @@ cfg_if! { target_os = "linux"))] { // These tests frequently fail on musl, probably due to // https://github.com/nix-rust/nix/issues/555 - execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); - execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); + execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap()); + execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap()); } else if #[cfg(any(target_os = "illumos", target_os = "ios", target_os = "macos", @@ -439,11 +441,11 @@ cfg_if! { "/system/bin/sh", AtFlags::empty()); } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { use nix::fcntl::AtFlags; - execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap(), "", AtFlags::AT_EMPTY_PATH); - execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap(), "./sh", AtFlags::empty()); - execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), + execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap(), "/bin/sh", AtFlags::empty()); } } @@ -452,22 +454,20 @@ cfg_if! { #[cfg(not(target_os = "fuchsia"))] fn test_fchdir() { // fchdir changes the process's cwd - let _dr = crate::DirRestore::new(); + let _dr = DirRestore::new(); let tmpdir = tempdir().unwrap(); let tmpdir_path = tmpdir.path().canonicalize().unwrap(); - let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); + let tmpdir_fd = File::open(&tmpdir_path).unwrap(); - fchdir(tmpdir_fd).expect("assertion failed"); + fchdir(&tmpdir_fd).expect("assertion failed"); assert_eq!(getcwd().unwrap(), tmpdir_path); - - close(tmpdir_fd).expect("assertion failed"); } #[test] fn test_getcwd() { // chdir changes the process's cwd - let _dr = crate::DirRestore::new(); + let _dr = DirRestore::new(); let tmpdir = tempdir().unwrap(); let tmpdir_path = tmpdir.path().canonicalize().unwrap(); @@ -516,18 +516,18 @@ fn test_fchown() { let gid = Some(getgid()); let path = tempfile().unwrap(); - let fd = path.as_raw_fd(); - fchown(fd, uid, gid).unwrap(); - fchown(fd, uid, None).unwrap(); - fchown(fd, None, gid).unwrap(); - fchown(999999999, uid, gid).unwrap_err(); + fchown(&path, uid, gid).unwrap(); + fchown(&path, uid, None).unwrap(); + fchown(&path, None, gid).unwrap(); + fchown(unsafe { &BorrowedFd::borrow_raw(999999999) }, uid, gid) + .unwrap_err(); } #[test] #[cfg(not(target_os = "redox"))] fn test_fchownat() { - let _dr = crate::DirRestore::new(); + let _dr = DirRestore::new(); // Testing for anything other than our own UID/GID is hard. let uid = Some(getuid()); let gid = Some(getgid()); @@ -540,14 +540,14 @@ fn test_fchownat() { let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) - .unwrap(); + fchownat(&dirfd, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); chdir(tempdir.path()).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + fchownat(AT_FDCWD, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); fs::remove_file(&path).unwrap(); - fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); + fchownat(AT_FDCWD, "file", uid, gid, FchownatFlags::FollowSymlink) + .unwrap_err(); } #[test] @@ -555,16 +555,13 @@ fn test_lseek() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); let offset: off_t = 5; - lseek(tmpfd, offset, Whence::SeekSet).unwrap(); + lseek(&tmp, offset, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); + read_exact(tmp.as_raw_fd(), &mut buf); assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -573,15 +570,12 @@ fn test_lseek64() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); - lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); + lseek64(&tmp, 5, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); + read_exact(tmp.as_raw_fd(), &mut buf); assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); } cfg_if! { @@ -719,14 +713,12 @@ fn test_getresgid() { #[test] fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); - let m0 = stat::SFlag::from_bits_truncate( - stat::fstat(fd0).unwrap().st_mode as mode_t, - ); + let m0 = + SFlag::from_bits_truncate(stat::fstat(&fd0).unwrap().st_mode as mode_t); // S_IFIFO means it's a pipe assert_eq!(m0, SFlag::S_IFIFO); - let m1 = stat::SFlag::from_bits_truncate( - stat::fstat(fd1).unwrap().st_mode as mode_t, - ); + let m1 = + SFlag::from_bits_truncate(stat::fstat(&fd1).unwrap().st_mode as mode_t); assert_eq!(m1, SFlag::S_IFIFO); } @@ -749,9 +741,13 @@ fn test_pipe2() { use nix::fcntl::{fcntl, FcntlArg, FdFlag}; let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap(); - let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap()); + let f0 = FdFlag::from_bits_truncate( + fcntl(fd0.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f0.contains(FdFlag::FD_CLOEXEC)); - let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap()); + let f1 = FdFlag::from_bits_truncate( + fcntl(fd1.as_raw_fd(), FcntlArg::F_GETFD).unwrap(), + ); assert!(f1.contains(FdFlag::FD_CLOEXEC)); } @@ -778,15 +774,11 @@ fn test_ftruncate() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("file"); - let tmpfd = { - let mut tmp = File::create(&path).unwrap(); - const CONTENTS: &[u8] = b"12345678"; - tmp.write_all(CONTENTS).unwrap(); - tmp.into_raw_fd() - }; + let mut tmp = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + tmp.write_all(CONTENTS).unwrap(); - ftruncate(tmpfd, 2).unwrap(); - close(tmpfd).unwrap(); + ftruncate(&tmp, 2).unwrap(); let metadata = fs::metadata(&path).unwrap(); assert_eq!(2, metadata.len()); @@ -873,7 +865,7 @@ fn test_symlinkat() { let target = tempdir.path().join("a"); let linkpath = tempdir.path().join("b"); - symlinkat(&target, None, &linkpath).unwrap(); + symlinkat(&target, AT_FDCWD, &linkpath).unwrap(); assert_eq!( readlink(&linkpath).unwrap().to_str().unwrap(), target.to_str().unwrap() @@ -882,7 +874,7 @@ fn test_symlinkat() { let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let target = "c"; let linkpath = "d"; - symlinkat(target, Some(dirfd), linkpath).unwrap(); + symlinkat(target, &dirfd, linkpath).unwrap(); assert_eq!( readlink(&tempdir.path().join(linkpath)) .unwrap() @@ -906,15 +898,13 @@ fn test_linkat_file() { File::create(oldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt hard link file at relative path linkat( - Some(dirfd), + &dirfd, oldfilename, - Some(dirfd), + &dirfd, newfilename, LinkatFlags::SymlinkFollow, ) @@ -925,7 +915,7 @@ fn test_linkat_file() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_olddirfd_none() { - let _dr = crate::DirRestore::new(); + let _dr = DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); let oldfilename = "foo.txt"; @@ -939,19 +929,15 @@ fn test_linkat_olddirfd_none() { File::create(oldfilepath).unwrap(); // Get file descriptor for base directory of new file - let dirfd = fcntl::open( - tempdir_newfile.path(), - fcntl::OFlag::empty(), - stat::Mode::empty(), - ) - .unwrap(); + let dirfd = + open(tempdir_newfile.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt hard link file using curent working directory as relative path for old file path chdir(tempdir_oldfile.path()).unwrap(); linkat( - None, + AT_FDCWD, oldfilename, - Some(dirfd), + &dirfd, newfilename, LinkatFlags::SymlinkFollow, ) @@ -962,7 +948,7 @@ fn test_linkat_olddirfd_none() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_newdirfd_none() { - let _dr = crate::DirRestore::new(); + let _dr = DirRestore::new(); let tempdir_oldfile = tempdir().unwrap(); let oldfilename = "foo.txt"; @@ -976,19 +962,15 @@ fn test_linkat_newdirfd_none() { File::create(oldfilepath).unwrap(); // Get file descriptor for base directory of old file - let dirfd = fcntl::open( - tempdir_oldfile.path(), - fcntl::OFlag::empty(), - stat::Mode::empty(), - ) - .unwrap(); + let dirfd = + open(tempdir_oldfile.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt hard link file using current working directory as relative path for new file path chdir(tempdir_newfile.path()).unwrap(); linkat( - Some(dirfd), + &dirfd, oldfilename, - None, + AT_FDCWD, newfilename, LinkatFlags::SymlinkFollow, ) @@ -1020,18 +1002,16 @@ fn test_linkat_no_follow_symlink() { File::create(&oldfilepath).unwrap(); // Create symlink to file - symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); + symlinkat(&oldfilepath, AT_FDCWD, &symoldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt link symlink of file at relative path linkat( - Some(dirfd), + &dirfd, symoldfilename, - Some(dirfd), + &dirfd, newfilename, LinkatFlags::NoSymlinkFollow, ) @@ -1063,18 +1043,16 @@ fn test_linkat_follow_symlink() { File::create(&oldfilepath).unwrap(); // Create symlink to file - symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); + symlinkat(&oldfilepath, AT_FDCWD, &symoldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt link target of symlink of file at relative path linkat( - Some(dirfd), + &dirfd, symoldfilename, - Some(dirfd), + &dirfd, newfilename, LinkatFlags::SymlinkFollow, ) @@ -1084,7 +1062,7 @@ fn test_linkat_follow_symlink() { // Check the file type of the new link assert_eq!( - (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) + (SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) & SFlag::S_IFMT), SFlag::S_IFREG ); @@ -1104,13 +1082,11 @@ fn test_unlinkat_dir_noremovedir() { DirBuilder::new().recursive(true).create(dirpath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt unlink dir at relative path without proper flag let err_result = - unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); + unlinkat(&dirfd, dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM); } @@ -1125,12 +1101,10 @@ fn test_unlinkat_dir_removedir() { DirBuilder::new().recursive(true).create(&dirpath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt unlink dir at relative path with proper flag - unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap(); + unlinkat(&dirfd, dirname, UnlinkatFlags::RemoveDir).unwrap(); assert!(!dirpath.exists()); } @@ -1145,12 +1119,10 @@ fn test_unlinkat_file() { File::create(&filepath).unwrap(); // Get file descriptor for base directory - let dirfd = - fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) - .unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); // Attempt unlink file at relative path - unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap(); + unlinkat(&dirfd, filename, UnlinkatFlags::NoRemoveDir).unwrap(); assert!(!filepath.exists()); } @@ -1213,7 +1185,7 @@ fn test_setfsuid() { // set filesystem UID let fuid = setfsuid(nobody.uid); // trying to open the temporary file should fail with EACCES - let res = fs::File::open(&temp_path); + let res = File::open(&temp_path); let err = res.expect_err("assertion failed"); assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); @@ -1225,7 +1197,7 @@ fn test_setfsuid() { .unwrap(); // open the temporary file with the current thread filesystem UID - fs::File::open(temp_path_2).unwrap(); + File::open(temp_path_2).unwrap(); } #[test] @@ -1244,11 +1216,11 @@ fn test_ttyname() { grantpt(&fd).expect("grantpt failed"); unlockpt(&fd).expect("unlockpt failed"); let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); - let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty()) + let fds = open(Path::new(&sname), OFlag::O_RDWR, Mode::empty()) .expect("open failed"); - assert!(fds > 0); + assert!(fds.as_raw_fd() > 0); - let name = ttyname(fds).expect("ttyname failed"); + let name = ttyname(fds.as_raw_fd()).expect("ttyname failed"); assert!(name.starts_with("/dev")); } @@ -1313,10 +1285,10 @@ fn test_getpeereid_invalid_fd() { #[cfg(not(target_os = "redox"))] fn test_faccessat_none_not_existing() { use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); + let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); assert_eq!( - faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty()) + faccessat(AT_FDCWD, &dir, AccessFlags::F_OK, AtFlags::empty()) .err() .unwrap(), Errno::ENOENT @@ -1327,18 +1299,13 @@ fn test_faccessat_none_not_existing() { #[cfg(not(target_os = "redox"))] fn test_faccessat_not_existing() { use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); + let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let not_exist_file = "does_not_exist.txt"; assert_eq!( - faccessat( - Some(dirfd), - not_exist_file, - AccessFlags::F_OK, - AtFlags::empty(), - ) - .err() - .unwrap(), + faccessat(&dirfd, not_exist_file, AccessFlags::F_OK, AtFlags::empty()) + .err() + .unwrap(), Errno::ENOENT ); } @@ -1347,11 +1314,11 @@ fn test_faccessat_not_existing() { #[cfg(not(target_os = "redox"))] fn test_faccessat_none_file_exists() { use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); + let tempdir = tempdir().unwrap(); let path = tempdir.path().join("does_exist.txt"); let _file = File::create(path.clone()).unwrap(); assert!(faccessat( - None, + AT_FDCWD, &path, AccessFlags::R_OK | AccessFlags::W_OK, AtFlags::empty(), @@ -1363,13 +1330,13 @@ fn test_faccessat_none_file_exists() { #[cfg(not(target_os = "redox"))] fn test_faccessat_file_exists() { use nix::fcntl::AtFlags; - let tempdir = tempfile::tempdir().unwrap(); + let tempdir = tempdir().unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let exist_file = "does_exist.txt"; let path = tempdir.path().join(exist_file); let _file = File::create(path.clone()).unwrap(); assert!(faccessat( - Some(dirfd), + &dirfd, &path, AccessFlags::R_OK | AccessFlags::W_OK, AtFlags::empty(),