From 30b32c4b7b2c9be7e74ee504197fec0341cd3854 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 12 Nov 2022 19:46:37 -0800 Subject: [PATCH 1/3] Convert common syscalls to safe I/O types Signed-off-by: Alex Saveau --- src/dir.rs | 9 +- src/fcntl.rs | 174 +++++++++++++++----------- src/lib.rs | 13 ++ src/pty.rs | 25 ++-- src/sys/inotify.rs | 16 ++- src/sys/select.rs | 33 ++--- src/sys/socket/mod.rs | 8 +- src/sys/stat.rs | 55 +++++---- src/sys/timerfd.rs | 2 +- src/unistd.rs | 237 +++++++++++++++++++++--------------- test/sys/test_select.rs | 23 ++-- test/sys/test_socket.rs | 49 +++++--- test/sys/test_sockopt.rs | 3 +- test/sys/test_stat.rs | 5 +- test/sys/test_termios.rs | 10 +- test/sys/test_uio.rs | 25 +--- test/test.rs | 4 +- test/test_fcntl.rs | 150 ++++++++--------------- test/test_poll.rs | 9 +- test/test_pty.rs | 29 +++-- test/test_sendfile.rs | 22 +--- test/test_stat.rs | 57 ++++----- test/test_unistd.rs | 255 ++++++++++++++++++--------------------- 23 files changed, 620 insertions(+), 593 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index e1854c35e8..ea93c5f8bd 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, + pub fn openat( + dirfd: &Fd, 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. diff --git a/src/fcntl.rs b/src/fcntl.rs index 1e24f603f6..379281ee77 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -1,9 +1,12 @@ 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; +#[cfg(not(target_os = "redox"))] +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")] @@ -197,42 +200,48 @@ pub fn open( path: &P, oflag: OFlag, mode: Mode, -) -> Result { +) -> 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, +pub fn openat( + dirfd: &Fd, path: &P, oflag: OFlag, mode: Mode, -) -> Result { +) -> Result { let fd = path.with_nix_path(|cstr| unsafe { - libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) + 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, +pub fn renameat( + old_dirfd: &Fd1, old_path: &P1, - new_dirfd: Option, + new_dirfd: &Fd2, new_path: &P2, ) -> 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(), ) }) @@ -255,19 +264,19 @@ libc_bitflags! { feature! { #![feature = "fs"] #[cfg(all(target_os = "linux", target_env = "gnu"))] -pub fn renameat2( - old_dirfd: Option, +pub fn renameat2( + old_dirfd: &Fd1, old_path: &P1, - new_dirfd: Option, + new_dirfd: &Fd2, new_path: &P2, 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(), ) @@ -279,21 +288,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, +fn readlink_maybe_at( + dirfd: Option<&Fd>, path: &P, 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, @@ -307,8 +316,8 @@ fn readlink_maybe_at( }) } -fn inner_readlink( - dirfd: Option, +fn inner_readlink( + dirfd: Option<&Fd>, path: &P, ) -> Result { let mut v = Vec::with_capacity(libc::PATH_MAX as usize); @@ -390,25 +399,16 @@ fn inner_readlink( } pub fn readlink(path: &P) -> Result { - inner_readlink(None, path) + inner_readlink(None::<&OwnedFd>, path) } #[cfg(not(target_os = "redox"))] -pub fn readlinkat( - dirfd: RawFd, +pub fn readlinkat( + dirfd: &Fd, path: &P, ) -> 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"))] @@ -622,10 +622,10 @@ feature! { /// On successful completion the number of bytes actually copied will be /// returned. #[cfg(any(target_os = "android", target_os = "linux"))] -pub fn copy_file_range( - fd_in: RawFd, +pub fn copy_file_range( + fd_in: &Fd1, off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, + fd_out: &Fd2, off_out: Option<&mut libc::loff_t>, len: usize, ) -> Result { @@ -639,9 +639,9 @@ pub fn copy_file_range( let ret = unsafe { libc::syscall( libc::SYS_copy_file_range, - fd_in, + fd_in.as_fd().as_raw_fd(), off_in, - fd_out, + fd_out.as_fd().as_raw_fd(), off_out, len, 0, @@ -651,10 +651,10 @@ pub fn copy_file_range( } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn splice( - fd_in: RawFd, +pub fn splice( + fd_in: &Fd1, off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, + fd_out: &Fd2, off_out: Option<&mut libc::loff_t>, len: usize, flags: SpliceFFlags, @@ -667,31 +667,45 @@ pub fn splice( .unwrap_or(ptr::null_mut()); let ret = unsafe { - libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) + 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, +pub fn tee( + fd_in: &Fd1, + fd_out: &Fd2, len: usize, flags: SpliceFFlags, ) -> Result { - let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; + 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, +pub fn vmsplice( + fd: &Fd, iov: &[std::io::IoSlice<'_>], 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(), @@ -743,13 +757,15 @@ feature! { /// file referred to by fd. #[cfg(any(target_os = "linux"))] #[cfg(feature = "fs")] -pub fn fallocate( - fd: RawFd, +pub fn fallocate( + fd: &Fd, 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) } @@ -802,29 +818,32 @@ 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 { +pub fn fspacectl( + fd: &Fd, + range: SpacectlRange, +) -> Result { let mut rqsr = libc::spacectl_range { r_offset: range.0, r_len: range.1, }; let res = unsafe { libc::fspacectl( - fd, + fd.as_fd().as_raw_fd(), libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, 0, // No flags are currently supported @@ -853,20 +872,20 @@ 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, +pub fn fspacectl_all( + fd: &Fd, offset: libc::off_t, len: libc::off_t, ) -> Result<()> { @@ -877,7 +896,7 @@ pub fn fspacectl_all( while rqsr.r_len > 0 { let res = unsafe { libc::fspacectl( - fd, + fd.as_fd().as_raw_fd(), libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, 0, // No flags are currently supported @@ -901,7 +920,8 @@ pub fn fspacectl_all( mod posix_fadvise { use crate::errno::Errno; use crate::Result; - use std::os::unix::io::RawFd; + use std::os::unix::io::AsFd; + use std::os::unix::io::AsRawFd; #[cfg(feature = "fs")] libc_enum! { @@ -920,13 +940,20 @@ mod posix_fadvise { feature! { #![feature = "fs"] - pub fn posix_fadvise( - fd: RawFd, + pub fn posix_fadvise( + fd: &Fd, 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(()) @@ -946,12 +973,13 @@ mod posix_fadvise { target_os = "wasi", target_os = "freebsd" ))] -pub fn posix_fallocate( - fd: RawFd, +pub fn posix_fallocate( + fd: &Fd, offset: libc::off_t, len: libc::off_t, ) -> Result<()> { - let res = unsafe { libc::posix_fallocate(fd, offset, len) }; + 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 6349d37e0f..5b5d8ce921 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,6 +162,8 @@ pub mod unistd; use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; +#[cfg(not(target_os = "redox"))] +use std::os::unix::io::BorrowedFd; use std::path::{Path, PathBuf}; use std::{ptr, result, slice}; @@ -182,6 +184,17 @@ pub type Result = result::Result; /// ones. pub type Error = Errno; +/// A file descriptor representing the current working directory. +#[cfg(not(target_os = "redox"))] +pub const AT_FDCWD: &BorrowedFd<'static> = unsafe { + &BorrowedFd::borrow_raw(if cfg!(target_os = "haiku") { + // Hack to work around BorrowedFd not allowing -1 + -2 + } else { + 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 2866c6df48..b5390d4c53 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -46,28 +46,27 @@ pub struct ForkptyResult { #[derive(Debug)] pub struct PtyMaster(OwnedFd); -impl AsRawFd for PtyMaster { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() +impl AsFd for PtyMaster { + fn as_fd(&self) -> BorrowedFd { + self.0.as_fd() } } impl IntoRawFd for PtyMaster { fn into_raw_fd(self) -> RawFd { - let fd = self.0; - fd.into_raw_fd() + self.0.into_raw_fd() } } impl io::Read for PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::read(self, buf).map_err(io::Error::from) } } impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(self, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -76,13 +75,13 @@ impl io::Write for PtyMaster { impl io::Read for &PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::read(self, buf).map_err(io::Error::from) } } impl io::Write for &PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) + unistd::write(self, buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -96,7 +95,7 @@ impl io::Write for &PtyMaster { /// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave. #[inline] pub fn grantpt(fd: &PtyMaster) -> Result<()> { - if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 { + if unsafe { libc::grantpt(fd.0.as_raw_fd()) } < 0 { return Err(Errno::last()); } @@ -165,7 +164,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result { /// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`. #[inline] pub unsafe fn ptsname(fd: &PtyMaster) -> Result { - let name_ptr = libc::ptsname(fd.as_raw_fd()); + let name_ptr = libc::ptsname(fd.0.as_raw_fd()); if name_ptr.is_null() { return Err(Errno::last()); } @@ -191,7 +190,7 @@ pub fn ptsname_r(fd: &PtyMaster) -> Result { let name_buf_ptr = name_buf.as_mut_ptr(); let cname = unsafe { let cap = name_buf.capacity(); - if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 { + if libc::ptsname_r(fd.0.as_raw_fd(), name_buf_ptr, cap) != 0 { return Err(crate::Error::last()); } CStr::from_ptr(name_buf.as_ptr()) @@ -209,7 +208,7 @@ pub fn ptsname_r(fd: &PtyMaster) -> Result { /// pseudoterminal. #[inline] pub fn unlockpt(fd: &PtyMaster) -> Result<()> { - if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { + if unsafe { libc::unlockpt(fd.0.as_raw_fd()) } < 0 { return Err(Errno::last()); } diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 2398c16e0b..eec8fb2ba3 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -143,7 +143,9 @@ impl Inotify { pub fn init(flags: InitFlags) -> Result { let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } }) + res.map(|fd| Inotify { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) } /// Adds a new watch on the target file or directory. @@ -157,7 +159,11 @@ impl Inotify { mask: AddWatchFlags, ) -> Result { let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits()) + libc::inotify_add_watch( + self.fd.as_raw_fd(), + cstr.as_ptr(), + mask.bits(), + ) })?; Errno::result(res).map(|wd| WatchDescriptor { wd }) @@ -195,7 +201,7 @@ impl Inotify { let mut events = Vec::new(); let mut offset = 0; - let nread = read(self.fd.as_raw_fd(), &mut buffer)?; + let nread = read(&self.fd, &mut buffer)?; while (nread - offset) >= header_size { let event = unsafe { @@ -237,6 +243,8 @@ impl Inotify { impl FromRawFd for Inotify { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd: OwnedFd::from_raw_fd(fd) } + Inotify { + fd: OwnedFd::from_raw_fd(fd), + } } } diff --git a/src/sys/select.rs b/src/sys/select.rs index 7a94cff87e..cbbb48fe13 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::unix::io::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 a67a5ab34a..73a1eafe09 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1427,13 +1427,15 @@ impl<'a> ControlMessage<'a> { /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; /// # use std::io::IoSlice; +/// # use std::os::unix::io::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(); /// ``` @@ -1442,14 +1444,16 @@ impl<'a> ControlMessage<'a> { /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; /// # use std::io::IoSlice; +/// # use std::os::unix::io::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(); /// ``` diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 78203bfbe3..f2b33a06f7 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. @@ -191,8 +191,8 @@ pub fn mknod( target_os = "haiku" )))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mknodat( - dirfd: RawFd, +pub fn mknodat( + dirfd: &Fd, path: &P, kind: SFlag, perm: Mode, @@ -200,7 +200,7 @@ pub fn mknodat( ) -> 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, @@ -258,9 +258,9 @@ pub fn lstat(path: &P) -> Result { Ok(unsafe { dst.assume_init() }) } -pub fn fstat(fd: RawFd) -> Result { +pub fn fstat(fd: &Fd) -> 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)?; @@ -269,15 +269,15 @@ pub fn fstat(fd: RawFd) -> Result { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat( - dirfd: RawFd, +pub fn fstatat( + dirfd: &Fd, pathname: &P, 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, @@ -294,8 +294,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: &Fd, mode: Mode) -> Result<()> { + let res = + unsafe { libc::fchmod(fd.as_fd().as_raw_fd(), mode.bits() as mode_t) }; Errno::result(res).map(drop) } @@ -325,8 +326,8 @@ 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, +pub fn fchmodat( + dirfd: &Fd, path: &P, mode: Mode, flag: FchmodatFlags, @@ -337,7 +338,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, @@ -408,9 +409,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: &Fd, + 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) } @@ -441,8 +446,8 @@ 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, +pub fn utimensat( + dirfd: &Fd, path: &P, atime: &TimeSpec, mtime: &TimeSpec, @@ -455,7 +460,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, @@ -467,13 +472,17 @@ pub fn utimensat( #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat( - fd: RawFd, +pub fn mkdirat( + fd: &Fd, path: &P, 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 90a05a8ccd..b51ec9736a 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -201,7 +201,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.as_fd().as_raw_fd(), &mut [0u8; 8]) { + while let Err(e) = read(&self.fd, &mut [0u8; 8]) { if e != Errno::EINTR { return Err(e); } diff --git a/src/unistd.rs b/src/unistd.rs index ae1cca9542..5104a22bc8 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3,7 +3,7 @@ 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}; #[cfg(all( @@ -34,7 +34,10 @@ use std::ffi::{CString, OsStr}; #[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::IntoRawFd; use std::os::unix::io::RawFd; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; @@ -250,19 +253,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::unix::io::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"), /// } /// ``` /// @@ -423,10 +437,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: &Fd) -> 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 @@ -436,10 +450,11 @@ 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: &Fd, newfd: &mut OwnedFd) -> Result<()> { + let res = + unsafe { libc::dup2(oldfd.as_fd().as_raw_fd(), newfd.as_raw_fd()) }; - Errno::result(res) + Errno::result(res).map(drop) } /// Create a new copy of the specified file descriptor using the specified fd @@ -447,26 +462,31 @@ 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 { +pub fn dup3( + oldfd: &Fd, + newfd: &mut OwnedFd, + flags: OFlag, +) -> Result<()> { dup3_polyfill(oldfd, newfd, flags) } #[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - if oldfd == newfd { +fn dup3_polyfill( + oldfd: &Fd, + newfd: &mut OwnedFd, + flags: OFlag, +) -> Result<()> { + if oldfd.as_fd().as_raw_fd() == newfd.as_raw_fd() { return Err(Errno::EINVAL); } - let fd = dup2(oldfd, newfd)?; + 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); - } + fcntl(newfd.as_raw_fd(), F_SETFD(FdFlag::FD_CLOEXEC))?; } - Ok(fd) + Ok(()) } /// Change the current working directory of the calling process (see @@ -490,8 +510,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: &Fd) -> Result<()> { + let res = unsafe { libc::fchdir(dirfd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -588,13 +608,17 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { target_os = "android", target_os = "redox" )))] -pub fn mkfifoat( - dirfd: Option, +pub fn mkfifoat( + dirfd: &Fd, path: &P, 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) @@ -610,16 +634,16 @@ pub fn mkfifoat( /// /// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). #[cfg(not(target_os = "redox"))] -pub fn symlinkat( +pub fn symlinkat( path1: &P1, - dirfd: Option, + dirfd: &Fd, 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), + dirfd.as_fd().as_raw_fd(), path2.as_ptr(), ) }) @@ -742,9 +766,13 @@ pub fn chown( /// provided for that argument. Ownership change will be attempted for the path /// only if `Some` owner/group is provided. #[inline] -pub fn fchown(fd: RawFd, owner: Option, group: Option) -> Result<()> { +pub fn fchown( + fd: &Fd, + 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) } @@ -777,8 +805,8 @@ pub enum FchownatFlags { /// /// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). #[cfg(not(target_os = "redox"))] -pub fn fchownat( - dirfd: Option, +pub fn fchownat( + dirfd: &Fd, path: &P, owner: Option, group: Option, @@ -791,11 +819,11 @@ pub fn fchownat( let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); libc::fchownat( - at_rawfd(dirfd), + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int, + atflag.bits() as c_int, ) })?; @@ -915,15 +943,15 @@ pub fn execvpe, SE: AsRef>( target_os = "freebsd" ))] #[inline] -pub fn fexecve, SE: AsRef>( - fd: RawFd, +pub fn fexecve, SE: AsRef>( + fd: &Fd, 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()) } @@ -940,8 +968,8 @@ pub fn fexecve, SE: AsRef>( /// 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, +pub fn execveat, SE: AsRef>( + dirfd: &Fd, pathname: &CStr, args: &[SA], env: &[SE], @@ -953,7 +981,7 @@ pub fn execveat, SE: AsRef>( unsafe { libc::syscall( libc::SYS_execveat, - dirfd, + dirfd.as_fd().as_raw_fd(), pathname.as_ptr(), args_p.as_ptr(), env_p.as_ptr(), @@ -1079,32 +1107,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: Fd) -> 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: &Fd, 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) @@ -1113,9 +1137,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: &Fd, 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) @@ -1166,19 +1194,21 @@ pub enum Whence { /// 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: &Fd, 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, +pub fn lseek64( + fd: &Fd, offset: libc::off64_t, whence: Whence, ) -> Result { - let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; + 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) } @@ -1187,14 +1217,18 @@ pub fn lseek64( /// Create an interprocess channel. /// /// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) -pub fn pipe() -> 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! { @@ -1228,7 +1262,7 @@ feature! { target_os = "openbsd", target_os = "solaris" ))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { +pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); let res = @@ -1236,7 +1270,11 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { 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 @@ -1255,15 +1293,16 @@ 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: &Fd, 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: &Fd) -> 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() { @@ -1295,11 +1334,11 @@ 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: &Fd1, + oldpath: &P1, + newdirfd: &Fd2, + newpath: &P2, flag: LinkatFlags, ) -> Result<()> { let atflag = match flag { @@ -1310,11 +1349,11 @@ pub fn linkat( let res = oldpath.with_nix_path(|oldcstr| { newpath.with_nix_path(|newcstr| unsafe { libc::linkat( - at_rawfd(olddirfd), + olddirfd.as_fd().as_raw_fd(), oldcstr.as_ptr(), - at_rawfd(newdirfd), + newdirfd.as_fd().as_raw_fd(), newcstr.as_ptr(), - atflag.bits() as libc::c_int, + atflag.bits() as c_int, ) }) })??; @@ -1348,8 +1387,8 @@ 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, +pub fn unlinkat( + dirfd: &Fd, path: &P, flag: UnlinkatFlags, ) -> Result<()> { @@ -1359,9 +1398,9 @@ pub fn unlinkat( }; let res = path.with_nix_path(|cstr| unsafe { libc::unlinkat( - at_rawfd(dirfd), + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), - atflag.bits() as libc::c_int, + atflag.bits() as c_int, ) })?; Errno::result(res).map(drop) @@ -1395,8 +1434,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: &Fd) -> Result<()> { + let res = unsafe { libc::syncfs(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -1405,8 +1444,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: &Fd) -> Result<()> { + let res = unsafe { libc::fsync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -1427,8 +1466,8 @@ pub fn fsync(fd: RawFd) -> Result<()> { target_os = "solaris" ))] #[inline] -pub fn fdatasync(fd: RawFd) -> Result<()> { - let res = unsafe { libc::fdatasync(fd) }; +pub fn fdatasync(fd: &Fd) -> Result<()> { + let res = unsafe { libc::fdatasync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) } @@ -3390,15 +3429,15 @@ 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, +pub fn faccessat( + dirfd: &Fd, path: &P, mode: AccessFlags, flags: AtFlags, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::faccessat( - at_rawfd(dirfd), + dirfd.as_fd().as_raw_fd(), cstr.as_ptr(), mode.bits(), flags.bits(), diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs index 40bda4d90a..a1fb19a0f6 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::unix::io::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 2ab6c54f6e..03dc351cbb 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -5,6 +5,8 @@ use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::{SocketAddrV4, SocketAddrV6}; +use std::os::unix::io::AsRawFd; +use std::os::unix::io::BorrowedFd; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; @@ -195,9 +197,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"); } @@ -691,7 +693,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(), @@ -732,12 +734,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 @@ -796,7 +797,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); @@ -812,7 +817,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); @@ -893,7 +902,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"); @@ -924,7 +937,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!( @@ -1344,7 +1361,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), @@ -1394,12 +1411,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 @@ -1432,14 +1448,15 @@ pub fn test_named_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 34bef945e1..2ef3d0708c 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -96,6 +96,7 @@ fn test_so_tcp_maxseg() { use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; use nix::unistd::{close, write}; use std::net::SocketAddrV4; + use std::os::unix::io::BorrowedFd; use std::str::FromStr; let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); @@ -134,7 +135,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_stat.rs b/test/sys/test_stat.rs index 426b4b6588..19c1f69da0 100644 --- a/test/sys/test_stat.rs +++ b/test/sys/test_stat.rs @@ -7,13 +7,12 @@ fn test_chflags() { sys::stat::{fstat, FileFlag}, unistd::chflags, }; - use std::os::unix::io::AsRawFd; use tempfile::NamedTempFile; let f = NamedTempFile::new().unwrap(); let initial = FileFlag::from_bits_truncate( - fstat(f.as_raw_fd()).unwrap().st_flags.into(), + fstat(f.as_file()).unwrap().st_flags.into(), ); // UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted // in any way, so it's handy for testing. @@ -22,7 +21,7 @@ fn test_chflags() { chflags(f.path(), commanded).unwrap(); let changed = FileFlag::from_bits_truncate( - fstat(f.as_raw_fd()).unwrap().st_flags.into(), + fstat(f.as_file()).unwrap().st_flags.into(), ); assert_eq!(commanded, changed); diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index 83919378a7..42603680a3 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -4,14 +4,14 @@ use tempfile::tempfile; use nix::errno::Errno; use nix::fcntl; use nix::pty::openpty; -use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; +use nix::sys::termios::{tcgetattr, LocalFlags, OutputFlags}; use nix::unistd::{read, write}; /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s fn write_all(f: Fd, buf: &[u8]) { let mut len = 0; while len < buf.len() { - len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap(); + len += write(&f, &buf[len..]).unwrap(); } } @@ -22,14 +22,14 @@ fn test_tcgetattr_pty() { let _m = crate::PTSNAME_MTX.lock(); let pty = openpty(None, None).expect("openpty failed"); - termios::tcgetattr(&pty.slave).unwrap(); + tcgetattr(&pty.slave).unwrap(); } // Test tcgetattr on something that isn't a terminal #[test] fn test_tcgetattr_enotty() { let file = tempfile().unwrap(); - assert_eq!(termios::tcgetattr(&file).err(), Some(Errno::ENOTTY)); + assert_eq!(tcgetattr(&file).err(), Some(Errno::ENOTTY)); } // Test modifying output flags @@ -102,6 +102,6 @@ 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.as_raw_fd(), &mut buf).unwrap_err(); + let read = read(&pty.master, &mut buf).unwrap_err(); assert_eq!(read, Errno::EAGAIN); } diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index fc09465f19..beb46c5a98 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -4,7 +4,6 @@ use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use std::fs::OpenOptions; use std::io::IoSlice; -use std::os::unix::io::{FromRawFd, OwnedFd}; use std::{cmp, iter}; #[cfg(not(target_os = "redox"))] @@ -43,23 +42,17 @@ fn test_writev() { let (reader, writer) = pipe().expect("Couldn't create pipe"); // FileDesc will close its filedesc (reader). let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); - - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let writer = unsafe { OwnedFd::from_raw_fd(writer) }; - // Blocking io, should write all data. let write_res = writev(&writer, &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(reader).expect("closed reader"); } #[test] @@ -90,12 +83,7 @@ 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"); - - // Temporary workaround to cope with the existing RawFd pipe(2), should be - // removed when pipe(2) becomes I/O-safe. - let reader = unsafe { OwnedFd::from_raw_fd(reader) }; - + write(&writer, &to_write).expect("write failed"); let read = readv(&reader, &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); @@ -108,7 +96,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(writer).expect("couldn't close writer"); } #[test] @@ -243,8 +230,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 }; @@ -267,8 +254,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 efd5fd2a6f..bb744931ad 100644 --- a/test/test.rs +++ b/test/test.rs @@ -66,7 +66,7 @@ mod test_unistd; use nix::unistd::{chdir, getcwd, read}; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; -use std::os::unix::io::{AsFd, AsRawFd}; +use std::os::unix::io::AsFd; use std::path::PathBuf; /// Helper function analogous to `std::io::Read::read_exact`, but for `Fd`s @@ -75,7 +75,7 @@ fn read_exact(f: Fd, 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.as_fd().as_raw_fd(), remaining).unwrap(); + len += read(&f, remaining).unwrap(); } } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 8f50f16b5a..354c50ec35 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -18,7 +18,7 @@ use nix::fcntl::{renameat2, RenameFlags}; #[cfg(not(target_os = "redox"))] use nix::sys::stat::Mode; #[cfg(not(target_os = "redox"))] -use nix::unistd::{close, read}; +use nix::unistd::read; #[cfg(not(target_os = "redox"))] use std::fs::File; #[cfg(not(target_os = "redox"))] @@ -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,27 +93,13 @@ 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(); - close(new_dirfd).unwrap(); assert!(new_dir.path().join("new").exists()); } @@ -151,9 +132,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, ) @@ -166,8 +147,6 @@ fn test_renameat2_exchange() { let mut old_f = File::open(&old_path).unwrap(); old_f.read_to_string(&mut buf).unwrap(); assert_eq!(buf, "new"); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); } #[test] @@ -194,17 +173,15 @@ 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 ) .unwrap_err(), Errno::EEXIST ); - close(old_dirfd).unwrap(); - close(new_dirfd).unwrap(); assert!(new_dir.path().join("new").exists()); assert!(old_dir.path().join("old").exists()); } @@ -222,7 +199,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 ); } @@ -232,10 +209,9 @@ mod linux_android { use libc::loff_t; use std::io::prelude::*; use std::io::IoSlice; - 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 +238,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.rewind().unwrap(); @@ -288,9 +257,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 +269,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 +279,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 +303,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,12 +318,11 @@ mod linux_android { fn test_fallocate() { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap(); + fallocate(tmp.as_file(), FallocateFlags::empty(), 0, 100).unwrap(); // Check if we read exactly 100 bytes let mut buf = [0u8; 200]; - assert_eq!(100, read(fd, &mut buf).unwrap()); + assert_eq!(100, read(tmp.as_file(), &mut buf).unwrap()); } // The tests below are disabled for the listed targets @@ -379,18 +336,18 @@ mod linux_android { fn test_ofd_write_lock() { use nix::sys::stat::fstat; use std::mem; + use std::os::unix::prelude::*; let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); + 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 // stat(2), but a different one shows up in /proc/locks. So we must // skip the test. skip!("/proc/locks does not work on overlayfs"); } - let inode = fstat(fd).expect("fstat failed").st_ino as usize; + let inode = fstat(tmp.as_file()).expect("fstat failed").st_ino as usize; let mut flock: libc::flock = unsafe { mem::zeroed() // required for Linux/mips @@ -400,14 +357,16 @@ 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(tmp.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(tmp.as_raw_fd(), F_OFD_SETLKW(&flock)) + .expect("write unlock failed"); assert_eq!(None, lock_info(inode)); } @@ -417,18 +376,18 @@ mod linux_android { fn test_ofd_read_lock() { use nix::sys::stat::fstat; use std::mem; + use std::os::unix::prelude::*; let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); + 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 // stat(2), but a different one shows up in /proc/locks. So we must // skip the test. skip!("/proc/locks does not work on overlayfs"); } - let inode = fstat(fd).expect("fstat failed").st_ino as usize; + let inode = fstat(tmp.as_file()).expect("fstat failed").st_ino as usize; let mut flock: libc::flock = unsafe { mem::zeroed() // required for Linux/mips @@ -438,14 +397,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(tmp.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(tmp.as_raw_fd(), F_OFD_SETLKW(&flock)) + .expect("read unlock failed"); assert_eq!(None, lock_info(inode)); } @@ -481,30 +441,28 @@ 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 tempfile::NamedTempFile; #[test] fn test_success() { let tmp = NamedTempFile::new().unwrap(); - let fd = tmp.as_raw_fd(); - posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) - .expect("posix_fadvise failed"); + posix_fadvise( + tmp.as_file(), + 0, + 100, + PosixFadviseAdvice::POSIX_FADV_WILLNEED, + ) + .expect("posix_fadvise failed"); } #[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 +481,14 @@ 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::io::Read; 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(tmp.as_file(), 0, LEN as libc::off_t); match res { Ok(_) => { let mut data = [1u8; LEN]; @@ -556,7 +510,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..67586eccd4 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::unix::io::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 4cc6620c3c..9fcd357271 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -18,7 +18,7 @@ fn test_ptsname_equivalence() { // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); + assert!(master_fd.as_fd().as_raw_fd() > 0); // Get the name of the slave let slave_name = unsafe { ptsname(&master_fd) }.unwrap(); @@ -106,22 +106,23 @@ fn open_ptty_pair() -> (PtyMaster, File) { // after opening a device path returned from ptsname(). let ptem = b"ptem\0"; let ldterm = b"ldterm\0"; - let r = unsafe { ioctl(slave_fd, I_FIND, ldterm.as_ptr()) }; + let r = unsafe { ioctl(slave_fd.as_raw_fd(), I_FIND, ldterm.as_ptr()) }; if r < 0 { panic!("I_FIND failure"); } else if r == 0 { - if unsafe { ioctl(slave_fd, I_PUSH, ptem.as_ptr()) } < 0 { + if unsafe { ioctl(slave_fd.as_raw_fd(), I_PUSH, ptem.as_ptr()) } < 0 + { panic!("I_PUSH ptem failure"); } - if unsafe { ioctl(slave_fd, I_PUSH, ldterm.as_ptr()) } < 0 { + if unsafe { ioctl(slave_fd.as_raw_fd(), I_PUSH, ldterm.as_ptr()) } + < 0 + { panic!("I_PUSH ldterm failure"); } } } - let slave = unsafe { File::from_raw_fd(slave_fd) }; - - (master, slave) + (master, slave_fd.into()) } /// Test opening a master/slave PTTY pair @@ -185,7 +186,7 @@ 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.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -199,7 +200,7 @@ fn test_openpty() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\r\n"; let mut buf = [0u8; 14]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -224,7 +225,7 @@ 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.as_raw_fd(), string.as_bytes()).unwrap(); + write(&pty.master, string.as_bytes()).unwrap(); crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); @@ -237,7 +238,7 @@ fn test_openpty_with_termios() { let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\n"; let mut buf = [0u8; 13]; - write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + write(&pty.slave, string2.as_bytes()).unwrap(); crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); @@ -258,7 +259,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 c6ac6e6fa1..912940bc74 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -1,6 +1,4 @@ use std::io::prelude::*; -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::os::unix::io::{FromRawFd, OwnedFd}; use libc::off_t; use nix::sys::sendfile::*; @@ -8,7 +6,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; @@ -24,21 +22,14 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile(&wr, &tmp, 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(); } #[cfg(target_os = "linux")] @@ -50,21 +41,14 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` - // becomes I/O-safe: - // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> - // then it is no longer needed. - let wr = unsafe { OwnedFd::from_raw_fd(wr) }; let res = sendfile64(&wr, &tmp, 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(); } #[cfg(target_os = "freebsd")] diff --git a/test/test_stat.rs b/test/test_stat.rs index 55f15c0771..c30778f98f 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -5,7 +5,6 @@ use std::fs::File; use std::os::unix::fs::symlink; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] use std::os::unix::fs::PermissionsExt; -use std::os::unix::prelude::AsRawFd; #[cfg(not(target_os = "redox"))] use std::path::Path; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] @@ -14,6 +13,8 @@ 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}; +#[cfg(not(target_os = "redox"))] +use nix::AT_FDCWD; #[cfg(not(target_os = "redox"))] use nix::errno::Errno; @@ -103,7 +104,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 +115,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 +143,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 +156,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 +179,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 +194,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 +272,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 +289,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 +305,7 @@ fn test_utimensat() { chdir(tempdir.path()).unwrap(); utimensat( - None, + AT_FDCWD, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800), @@ -321,23 +321,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 +353,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); } @@ -396,13 +395,15 @@ fn test_mknodat() { use fcntl::{AtFlags, OFlag}; use nix::dir::Dir; use stat::{fstatat, mknodat, SFlag}; + use std::os::unix::io::AsRawFd; + use std::os::unix::io::BorrowedFd; let file_name = "test_file"; let tempdir = tempfile::tempdir().unwrap(); 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 +411,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 1d50c5fa48..31b155b4e5 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,8 @@ use nix::sys::stat::{self, Mode, SFlag}; use nix::sys::wait::*; use nix::unistd::ForkResult::*; use nix::unistd::*; +#[cfg(not(target_os = "redox"))] +use nix::AT_FDCWD; use std::env; #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] use std::ffi::CString; @@ -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,16 @@ fn test_mkfifoat_none() { target_os = "haiku" )))] fn test_mkfifoat() { - use nix::fcntl; + use nix::fcntl::AtFlags; 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 +181,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 +198,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 +215,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 +227,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 +316,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 +329,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 +359,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 = std::mem::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 +374,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!!!")); @@ -402,48 +406,48 @@ macro_rules! execve_test_factory ( cfg_if! { if #[cfg(target_os = "android")] { - execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); - execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); + execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap()); + execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap()); } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", 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", target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] { - execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); + execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap()); // No fexecve() on ios, macos, NetBSD, OpenBSD. } } #[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] -execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); +execve_test_factory!(test_execvpe, execvpe, CString::new("sh").unwrap()); cfg_if! { if #[cfg(target_os = "android")] { use nix::fcntl::AtFlags; execve_test_factory!(test_execveat_empty, execveat, - File::open("/system/bin/sh").unwrap().into_raw_fd(), + File::open("/system/bin/sh").unwrap(), "", AtFlags::AT_EMPTY_PATH); execve_test_factory!(test_execveat_relative, execveat, - File::open("/system/bin/").unwrap().into_raw_fd(), + File::open("/system/bin/").unwrap(), "./sh", AtFlags::empty()); execve_test_factory!(test_execveat_absolute, execveat, - File::open("/").unwrap().into_raw_fd(), + File::open("/").unwrap(), "/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 +456,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 +518,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 +542,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] @@ -557,7 +559,7 @@ fn test_lseek() { tmp.write_all(CONTENTS).unwrap(); let offset: off_t = 5; - lseek(tmp.as_raw_fd(), offset, Whence::SeekSet).unwrap(); + lseek(&tmp, offset, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; crate::read_exact(&tmp, &mut buf); @@ -571,7 +573,7 @@ fn test_lseek64() { let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); - lseek64(tmp.as_raw_fd(), 5, Whence::SeekSet).unwrap(); + lseek64(&tmp, 5, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; crate::read_exact(&tmp, &mut buf); @@ -713,14 +715,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); } @@ -743,9 +743,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)); } @@ -772,15 +776,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()); @@ -862,7 +862,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() @@ -871,7 +871,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() @@ -895,15 +895,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, ) @@ -914,7 +912,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"; @@ -928,19 +926,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, ) @@ -951,7 +945,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"; @@ -965,19 +959,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, ) @@ -1009,18 +999,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, ) @@ -1052,18 +1040,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, ) @@ -1073,7 +1059,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 ); @@ -1093,13 +1079,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); } @@ -1114,12 +1098,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()); } @@ -1134,12 +1116,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()); } @@ -1202,7 +1182,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); @@ -1214,7 +1194,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] @@ -1225,7 +1205,7 @@ fn test_setfsuid() { )))] fn test_ttyname() { let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); - assert!(fd.as_raw_fd() > 0); + assert!(fd.as_fd().as_raw_fd() > 0); // on linux, we can just call ttyname on the pty master directly, but // apparently osx requires that ttyname is called on a slave pty (can't @@ -1233,11 +1213,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")); } @@ -1302,10 +1282,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 @@ -1316,18 +1296,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 ); } @@ -1336,11 +1311,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(), @@ -1352,13 +1327,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(), From c6af95734b1ec4fc9d2555fab388e4eed788574d Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Wed, 7 Dec 2022 21:59:52 -0800 Subject: [PATCH 2/3] Support type-safe path FDs Signed-off-by: Alex Saveau --- src/dir.rs | 7 ++-- src/fcntl.rs | 56 ++++++++++++++------------- src/lib.rs | 43 ++++++++++++++++----- src/sys/epoll.rs | 2 +- src/sys/stat.rs | 44 ++++++++++----------- src/unistd.rs | 82 ++++++++++++++++++++-------------------- test/sys/test_socket.rs | 20 +++++----- test/sys/test_sockopt.rs | 2 +- test/test_fcntl.rs | 4 +- test/test_pty.rs | 2 +- test/test_stat.rs | 10 ++--- test/test_unistd.rs | 28 +++++++------- 12 files changed, 160 insertions(+), 140 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index ea93c5f8bd..8f45535b57 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -2,11 +2,10 @@ use crate::errno::Errno; use crate::fcntl::{self, OFlag}; -use crate::sys; +use crate::{sys, AsDirFd}; 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; @@ -44,8 +43,8 @@ impl Dir { } /// Opens the given path as with `fcntl::openat`. - pub fn openat( - dirfd: &Fd, + pub fn openat( + dirfd: Fd, path: &P, oflag: OFlag, mode: sys::stat::Mode, diff --git a/src/fcntl.rs b/src/fcntl.rs index 379281ee77..79f81286d1 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -9,6 +9,8 @@ use std::os::unix::io::FromRawFd; use std::os::unix::io::OwnedFd; use std::os::unix::io::RawFd; +#[cfg(not(target_os = "redox"))] +use crate::AsDirFd; #[cfg(feature = "fs")] use crate::{sys::stat::Mode, NixPath, Result}; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -211,15 +213,15 @@ pub fn open( // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] #[cfg(not(target_os = "redox"))] -pub fn openat( - dirfd: &Fd, +pub fn openat( + dirfd: Fd, path: &P, oflag: OFlag, mode: Mode, ) -> Result { let fd = path.with_nix_path(|cstr| unsafe { libc::openat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint, @@ -230,18 +232,18 @@ pub fn openat( } #[cfg(not(target_os = "redox"))] -pub fn renameat( - old_dirfd: &Fd1, +pub fn renameat( + old_dirfd: Fd1, old_path: &P1, - new_dirfd: &Fd2, + new_dirfd: Fd2, new_path: &P2, ) -> Result<()> { let res = old_path.with_nix_path(|old_cstr| { new_path.with_nix_path(|new_cstr| unsafe { libc::renameat( - old_dirfd.as_fd().as_raw_fd(), + old_dirfd.as_dir_fd(), old_cstr.as_ptr(), - new_dirfd.as_fd().as_raw_fd(), + new_dirfd.as_dir_fd(), new_cstr.as_ptr(), ) }) @@ -264,19 +266,19 @@ libc_bitflags! { feature! { #![feature = "fs"] #[cfg(all(target_os = "linux", target_env = "gnu"))] -pub fn renameat2( - old_dirfd: &Fd1, +pub fn renameat2( + old_dirfd: Fd1, old_path: &P1, - new_dirfd: &Fd2, + new_dirfd: Fd2, new_path: &P2, flags: RenameFlags, ) -> Result<()> { let res = old_path.with_nix_path(|old_cstr| { new_path.with_nix_path(|new_cstr| unsafe { libc::renameat2( - old_dirfd.as_fd().as_raw_fd(), + old_dirfd.as_dir_fd(), old_cstr.as_ptr(), - new_dirfd.as_fd().as_raw_fd(), + new_dirfd.as_dir_fd(), new_cstr.as_ptr(), flags.bits(), ) @@ -404,10 +406,10 @@ pub fn readlink(path: &P) -> Result { #[cfg(not(target_os = "redox"))] pub fn readlinkat( - dirfd: &Fd, + dirfd: Fd, path: &P, ) -> Result { - inner_readlink(Some(dirfd), path) + inner_readlink(Some(&dirfd), path) } } @@ -623,9 +625,9 @@ feature! { /// returned. #[cfg(any(target_os = "android", target_os = "linux"))] pub fn copy_file_range( - fd_in: &Fd1, + fd_in: Fd1, off_in: Option<&mut libc::loff_t>, - fd_out: &Fd2, + fd_out: Fd2, off_out: Option<&mut libc::loff_t>, len: usize, ) -> Result { @@ -652,9 +654,9 @@ pub fn copy_file_range( #[cfg(any(target_os = "linux", target_os = "android"))] pub fn splice( - fd_in: &Fd1, + fd_in: Fd1, off_in: Option<&mut libc::loff_t>, - fd_out: &Fd2, + fd_out: Fd2, off_out: Option<&mut libc::loff_t>, len: usize, flags: SpliceFFlags, @@ -681,8 +683,8 @@ pub fn splice( #[cfg(any(target_os = "linux", target_os = "android"))] pub fn tee( - fd_in: &Fd1, - fd_out: &Fd2, + fd_in: Fd1, + fd_out: Fd2, len: usize, flags: SpliceFFlags, ) -> Result { @@ -699,7 +701,7 @@ pub fn tee( #[cfg(any(target_os = "linux", target_os = "android"))] pub fn vmsplice( - fd: &Fd, + fd: Fd, iov: &[std::io::IoSlice<'_>], flags: SpliceFFlags, ) -> Result { @@ -758,7 +760,7 @@ feature! { #[cfg(any(target_os = "linux"))] #[cfg(feature = "fs")] pub fn fallocate( - fd: &Fd, + fd: Fd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t, @@ -834,7 +836,7 @@ impl SpacectlRange { /// ``` #[cfg(target_os = "freebsd")] pub fn fspacectl( - fd: &Fd, + fd: Fd, range: SpacectlRange, ) -> Result { let mut rqsr = libc::spacectl_range { @@ -885,7 +887,7 @@ pub fn fspacectl( /// ``` #[cfg(target_os = "freebsd")] pub fn fspacectl_all( - fd: &Fd, + fd: Fd, offset: libc::off_t, len: libc::off_t, ) -> Result<()> { @@ -941,7 +943,7 @@ mod posix_fadvise { feature! { #![feature = "fs"] pub fn posix_fadvise( - fd: &Fd, + fd: Fd, offset: libc::off_t, len: libc::off_t, advice: PosixFadviseAdvice, @@ -974,7 +976,7 @@ mod posix_fadvise { target_os = "freebsd" ))] pub fn posix_fallocate( - fd: &Fd, + fd: Fd, offset: libc::off_t, len: libc::off_t, ) -> Result<()> { diff --git a/src/lib.rs b/src/lib.rs index 5b5d8ce921..7220478db8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,8 +162,7 @@ pub mod unistd; use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; -#[cfg(not(target_os = "redox"))] -use std::os::unix::io::BorrowedFd; +use std::os::unix::io::{AsFd, AsRawFd, RawFd}; use std::path::{Path, PathBuf}; use std::{ptr, result, slice}; @@ -184,16 +183,40 @@ pub type Result = result::Result; /// ones. pub type Error = Errno; -/// A file descriptor representing the current working directory. +/// A trait representing directory file descriptors, to be used in the +/// `*at` family of functions. +pub trait AsDirFd { + /// Extracts the raw file descriptor. + fn as_dir_fd(&self) -> RawFd; +} + +impl AsDirFd for Fd { + fn as_dir_fd(&self) -> RawFd { + self.as_fd().as_raw_fd() + } +} + +/// The `AT_FDCWD` marker file descriptor. +/// +/// # Examples +/// +/// ``` +/// # use nix::Cwd; +/// # use nix::fcntl::{OFlag, openat}; +/// # use nix::sys::stat::Mode; +/// +/// let file = openat(Cwd, "README.md", OFlag::O_RDONLY, Mode::empty()); +/// ``` +#[cfg(not(target_os = "redox"))] +#[derive(Copy, Clone, Debug)] +pub struct Cwd; + #[cfg(not(target_os = "redox"))] -pub const AT_FDCWD: &BorrowedFd<'static> = unsafe { - &BorrowedFd::borrow_raw(if cfg!(target_os = "haiku") { - // Hack to work around BorrowedFd not allowing -1 - -2 - } else { +impl AsDirFd for Cwd { + fn as_dir_fd(&self) -> RawFd { libc::AT_FDCWD - }) -}; + } +} /// Common trait used to represent file system paths by many Nix functions. pub trait NixPath { diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 9fdb1495bc..bd25754afd 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -87,7 +87,7 @@ impl EpollEvent { /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; /// /// // Arm eventfd & Time wait -/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?; +/// write(&eventfd, &1u64.to_ne_bytes())?; /// let now = Instant::now(); /// /// // Wait on event diff --git a/src/sys/stat.rs b/src/sys/stat.rs index f2b33a06f7..57f7ed9a82 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -9,10 +9,10 @@ pub use libc::c_ulong; pub use libc::stat as FileStat; pub use libc::{dev_t, mode_t}; -#[cfg(not(target_os = "redox"))] -use crate::fcntl::AtFlags; use crate::sys::time::{TimeSpec, TimeVal}; use crate::{errno::Errno, NixPath, Result}; +#[cfg(not(target_os = "redox"))] +use crate::{fcntl::AtFlags, AsDirFd}; use std::mem; use std::os::unix::io::{AsFd, AsRawFd}; @@ -191,8 +191,8 @@ pub fn mknod( target_os = "haiku" )))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mknodat( - dirfd: &Fd, +pub fn mknodat( + dirfd: Fd, path: &P, kind: SFlag, perm: Mode, @@ -200,7 +200,7 @@ pub fn mknodat( ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mknodat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev, @@ -258,7 +258,7 @@ pub fn lstat(path: &P) -> Result { Ok(unsafe { dst.assume_init() }) } -pub fn fstat(fd: &Fd) -> Result { +pub fn fstat(fd: Fd) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = unsafe { libc::fstat(fd.as_fd().as_raw_fd(), dst.as_mut_ptr()) }; @@ -269,15 +269,15 @@ pub fn fstat(fd: &Fd) -> Result { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat( - dirfd: &Fd, +pub fn fstatat( + dirfd: Fd, pathname: &P, f: AtFlags, ) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = pathname.with_nix_path(|cstr| unsafe { libc::fstatat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int, @@ -294,7 +294,7 @@ pub fn fstatat( /// # References /// /// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). -pub fn fchmod(fd: &Fd, mode: Mode) -> Result<()> { +pub fn fchmod(fd: Fd, mode: Mode) -> Result<()> { let res = unsafe { libc::fchmod(fd.as_fd().as_raw_fd(), mode.bits() as mode_t) }; @@ -326,8 +326,8 @@ 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: &Fd, +pub fn fchmodat( + dirfd: Fd, path: &P, mode: Mode, flag: FchmodatFlags, @@ -338,7 +338,7 @@ pub fn fchmodat( }; let res = path.with_nix_path(|cstr| unsafe { libc::fchmodat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), mode.bits() as mode_t, atflag.bits() as libc::c_int, @@ -410,7 +410,7 @@ pub fn lutimes( /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html). #[inline] pub fn futimens( - fd: &Fd, + fd: Fd, atime: &TimeSpec, mtime: &TimeSpec, ) -> Result<()> { @@ -446,8 +446,8 @@ 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: &Fd, +pub fn utimensat( + dirfd: Fd, path: &P, atime: &TimeSpec, mtime: &TimeSpec, @@ -460,7 +460,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( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), ×[0], atflag.bits() as libc::c_int, @@ -472,17 +472,13 @@ pub fn utimensat( #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat( - fd: &Fd, +pub fn mkdirat( + fd: Fd, path: &P, mode: Mode, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::mkdirat( - fd.as_fd().as_raw_fd(), - cstr.as_ptr(), - mode.bits() as mode_t, - ) + libc::mkdirat(fd.as_dir_fd(), cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) diff --git a/src/unistd.rs b/src/unistd.rs index 5104a22bc8..bdc6647873 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -20,6 +20,8 @@ use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] use crate::sys::stat::Mode; +#[cfg(not(target_os = "redox"))] +use crate::AsDirFd; use crate::{Error, NixPath, Result}; #[cfg(not(target_os = "redox"))] use cfg_if::cfg_if; @@ -270,7 +272,7 @@ impl ForkResult { /// Ok(ForkResult::Child) => { /// // Unsafe to use `println!` (or `unwrap`) here. See Safety. /// write( -/// unsafe { &BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }, +/// unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }, /// "I'm a new child process\n".as_bytes(), /// ) /// .ok(); @@ -437,7 +439,7 @@ feature! { /// /// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`). #[inline] -pub fn dup(oldfd: &Fd) -> Result { +pub fn dup(oldfd: Fd) -> Result { let res = unsafe { libc::dup(oldfd.as_fd().as_raw_fd()) }; Errno::result(res).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) @@ -450,7 +452,7 @@ pub fn dup(oldfd: &Fd) -> 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: &Fd, newfd: &mut OwnedFd) -> Result<()> { +pub fn dup2(oldfd: Fd, newfd: &mut OwnedFd) -> Result<()> { let res = unsafe { libc::dup2(oldfd.as_fd().as_raw_fd(), newfd.as_raw_fd()) }; @@ -463,7 +465,7 @@ pub fn dup2(oldfd: &Fd, newfd: &mut OwnedFd) -> Result<()> { /// This function behaves similar to `dup2()` but allows for flags to be /// specified. pub fn dup3( - oldfd: &Fd, + oldfd: Fd, newfd: &mut OwnedFd, flags: OFlag, ) -> Result<()> { @@ -472,7 +474,7 @@ pub fn dup3( #[inline] fn dup3_polyfill( - oldfd: &Fd, + oldfd: Fd, newfd: &mut OwnedFd, flags: OFlag, ) -> Result<()> { @@ -510,7 +512,7 @@ pub fn chdir(path: &P) -> Result<()> { /// pages for additional details on possible failure cases. #[inline] #[cfg(not(target_os = "fuchsia"))] -pub fn fchdir(dirfd: &Fd) -> Result<()> { +pub fn fchdir(dirfd: Fd) -> Result<()> { let res = unsafe { libc::fchdir(dirfd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) @@ -608,14 +610,14 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { target_os = "android", target_os = "redox" )))] -pub fn mkfifoat( - dirfd: &Fd, +pub fn mkfifoat( + dirfd: Fd, path: &P, mode: Mode, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mkfifoat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), mode.bits() as mode_t, ) @@ -634,16 +636,16 @@ pub fn mkfifoat( /// /// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). #[cfg(not(target_os = "redox"))] -pub fn symlinkat( +pub fn symlinkat( path1: &P1, - dirfd: &Fd, + dirfd: Fd, path2: &P2, ) -> 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(), + dirfd.as_dir_fd(), path2.as_ptr(), ) }) @@ -767,7 +769,7 @@ pub fn chown( /// only if `Some` owner/group is provided. #[inline] pub fn fchown( - fd: &Fd, + fd: Fd, owner: Option, group: Option, ) -> Result<()> { @@ -805,8 +807,8 @@ pub enum FchownatFlags { /// /// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html). #[cfg(not(target_os = "redox"))] -pub fn fchownat( - dirfd: &Fd, +pub fn fchownat( + dirfd: Fd, path: &P, owner: Option, group: Option, @@ -819,7 +821,7 @@ pub fn fchownat( let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); libc::fchownat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), uid, gid, @@ -944,7 +946,7 @@ pub fn execvpe, SE: AsRef>( ))] #[inline] pub fn fexecve, SE: AsRef>( - fd: &Fd, + fd: Fd, args: &[SA], env: &[SE], ) -> Result { @@ -968,8 +970,8 @@ pub fn fexecve, SE: AsRef>( /// 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: &Fd, +pub fn execveat, SE: AsRef>( + dirfd: Fd, pathname: &CStr, args: &[SA], env: &[SE], @@ -981,7 +983,7 @@ pub fn execveat, SE: AsRef>( unsafe { libc::syscall( libc::SYS_execveat, - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), pathname.as_ptr(), args_p.as_ptr(), env_p.as_ptr(), @@ -1122,7 +1124,7 @@ pub fn close(fd: Fd) -> Result<()> { /// Read from a raw file descriptor. /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) -pub fn read(fd: &Fd, buf: &mut [u8]) -> Result { +pub fn read(fd: Fd, buf: &mut [u8]) -> Result { let res = unsafe { libc::read( fd.as_fd().as_raw_fd(), @@ -1137,7 +1139,7 @@ pub fn read(fd: &Fd, 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: &Fd, buf: &[u8]) -> Result { +pub fn write(fd: Fd, buf: &[u8]) -> Result { let res = unsafe { libc::write( fd.as_fd().as_raw_fd(), @@ -1194,7 +1196,7 @@ pub enum Whence { /// Move the read/write file offset. /// /// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html) -pub fn lseek(fd: &Fd, offset: off_t, whence: Whence) -> Result { +pub fn lseek(fd: Fd, offset: off_t, whence: Whence) -> Result { let res = unsafe { libc::lseek(fd.as_fd().as_raw_fd(), offset, whence as i32) }; @@ -1203,7 +1205,7 @@ pub fn lseek(fd: &Fd, offset: off_t, whence: Whence) -> Result #[cfg(any(target_os = "linux", target_os = "android"))] pub fn lseek64( - fd: &Fd, + fd: Fd, offset: libc::off64_t, whence: Whence, ) -> Result { @@ -1293,12 +1295,12 @@ 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: &Fd, len: off_t) -> Result<()> { +pub fn ftruncate(fd: Fd, len: off_t) -> Result<()> { Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }) .map(drop) } -pub fn isatty(fd: &Fd) -> Result { +pub fn isatty(fd: Fd) -> Result { unsafe { // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so // we return `Ok(false)` @@ -1334,10 +1336,10 @@ 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: &Fd1, +pub fn linkat( + olddirfd: Fd1, oldpath: &P1, - newdirfd: &Fd2, + newdirfd: Fd2, newpath: &P2, flag: LinkatFlags, ) -> Result<()> { @@ -1349,9 +1351,9 @@ pub fn linkat( let res = oldpath.with_nix_path(|oldcstr| { newpath.with_nix_path(|newcstr| unsafe { libc::linkat( - olddirfd.as_fd().as_raw_fd(), + olddirfd.as_dir_fd(), oldcstr.as_ptr(), - newdirfd.as_fd().as_raw_fd(), + newdirfd.as_dir_fd(), newcstr.as_ptr(), atflag.bits() as c_int, ) @@ -1387,8 +1389,8 @@ 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: &Fd, +pub fn unlinkat( + dirfd: Fd, path: &P, flag: UnlinkatFlags, ) -> Result<()> { @@ -1398,7 +1400,7 @@ pub fn unlinkat( }; let res = path.with_nix_path(|cstr| unsafe { libc::unlinkat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), atflag.bits() as c_int, ) @@ -1434,7 +1436,7 @@ 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: &Fd) -> Result<()> { +pub fn syncfs(fd: Fd) -> Result<()> { let res = unsafe { libc::syncfs(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) @@ -1444,7 +1446,7 @@ pub fn syncfs(fd: &Fd) -> Result<()> { /// /// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) #[inline] -pub fn fsync(fd: &Fd) -> Result<()> { +pub fn fsync(fd: Fd) -> Result<()> { let res = unsafe { libc::fsync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) @@ -1466,7 +1468,7 @@ pub fn fsync(fd: &Fd) -> Result<()> { target_os = "solaris" ))] #[inline] -pub fn fdatasync(fd: &Fd) -> Result<()> { +pub fn fdatasync(fd: Fd) -> Result<()> { let res = unsafe { libc::fdatasync(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(drop) @@ -3429,15 +3431,15 @@ 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: &Fd, +pub fn faccessat( + dirfd: Fd, path: &P, mode: AccessFlags, flags: AtFlags, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::faccessat( - dirfd.as_fd().as_raw_fd(), + dirfd.as_dir_fd(), cstr.as_ptr(), mode.bits(), flags.bits(), diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 03dc351cbb..00123f5bfd 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -197,9 +197,9 @@ pub fn test_socketpair() { SockFlag::empty(), ) .unwrap(); - write(unsafe { &BorrowedFd::borrow_raw(fd1) }, b"hello").unwrap(); + write(unsafe { BorrowedFd::borrow_raw(fd1) }, b"hello").unwrap(); let mut buf = [0; 5]; - read(unsafe { &BorrowedFd::borrow_raw(fd2) }, &mut buf).unwrap(); + read(unsafe { BorrowedFd::borrow_raw(fd2) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"hello"); } @@ -736,7 +736,7 @@ pub fn test_scm_rights() { // Ensure that the received file descriptor works write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; - read(unsafe { &BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); + read(unsafe { BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); } @@ -798,7 +798,7 @@ pub fn test_af_alg_cipher() { // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; let num_bytes = read( - unsafe { &BorrowedFd::borrow_raw(session_socket) }, + unsafe { BorrowedFd::borrow_raw(session_socket) }, &mut encrypted, ) .expect("read encrypt"); @@ -818,7 +818,7 @@ pub fn test_af_alg_cipher() { // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; let num_bytes = read( - unsafe { &BorrowedFd::borrow_raw(session_socket) }, + unsafe { BorrowedFd::borrow_raw(session_socket) }, &mut decrypted, ) .expect("read decrypt"); @@ -903,7 +903,7 @@ pub fn test_af_alg_aead() { let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; let num_bytes = read( - unsafe { &BorrowedFd::borrow_raw(session_socket) }, + unsafe { BorrowedFd::borrow_raw(session_socket) }, &mut encrypted, ) .expect("read encrypt"); @@ -938,7 +938,7 @@ pub fn test_af_alg_aead() { fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) .expect("fcntl non_blocking"); let num_bytes = read( - unsafe { &BorrowedFd::borrow_raw(session_socket) }, + unsafe { BorrowedFd::borrow_raw(session_socket) }, &mut decrypted, ) .expect("read decrypt"); @@ -1413,7 +1413,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { // Ensure that the received file descriptor works write(&w, b"world").unwrap(); let mut buf = [0u8; 5]; - read(unsafe { &BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); + read(unsafe { BorrowedFd::borrow_raw(received_r) }, &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); } @@ -1448,7 +1448,7 @@ pub fn test_named_unixdomain() { ) .expect("socket failed"); connect(s2, &sockaddr).expect("connect failed"); - write(unsafe { &BorrowedFd::borrow_raw(s2) }, b"hello") + write(unsafe { BorrowedFd::borrow_raw(s2) }, b"hello") .expect("write failed"); close(s2).unwrap(); }); @@ -1456,7 +1456,7 @@ pub fn test_named_unixdomain() { let s3 = accept(s1).expect("accept failed"); let mut buf = [0; 5]; - read(unsafe { &BorrowedFd::borrow_raw(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 2ef3d0708c..2bb35bddb7 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -135,7 +135,7 @@ fn test_so_tcp_maxseg() { .unwrap(); connect(ssock, &sock_addr).unwrap(); let rsess = accept(rsock).unwrap(); - write(unsafe { &BorrowedFd::borrow_raw(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/test_fcntl.rs b/test/test_fcntl.rs index 354c50ec35..5b9c933772 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -340,7 +340,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must @@ -380,7 +380,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must diff --git a/test/test_pty.rs b/test/test_pty.rs index 9fcd357271..25200e039e 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -260,7 +260,7 @@ fn test_forkpty() { match pty.fork_result { Child => { write( - unsafe { &BorrowedFd::borrow_raw(STDOUT_FILENO) }, + unsafe { BorrowedFd::borrow_raw(STDOUT_FILENO) }, string.as_bytes(), ) .unwrap(); diff --git a/test/test_stat.rs b/test/test_stat.rs index c30778f98f..a204eecc0f 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -14,7 +14,7 @@ use libc::mode_t; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] use libc::{S_IFLNK, S_IFMT}; #[cfg(not(target_os = "redox"))] -use nix::AT_FDCWD; +use nix::Cwd; #[cfg(not(target_os = "redox"))] use nix::errno::Errno; @@ -194,7 +194,7 @@ fn test_fchmodat() { let mut mode2 = Mode::empty(); mode2.insert(Mode::S_IROTH); - fchmodat(AT_FDCWD, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); + fchmodat(Cwd, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); let file_stat2 = stat(&fullpath).unwrap(); assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); @@ -305,7 +305,7 @@ fn test_utimensat() { chdir(tempdir.path()).unwrap(); utimensat( - AT_FDCWD, + Cwd, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800), @@ -403,7 +403,7 @@ fn test_mknodat() { let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); mknodat( - unsafe { &BorrowedFd::borrow_raw(target_dir.as_raw_fd()) }, + unsafe { BorrowedFd::borrow_raw(target_dir.as_raw_fd()) }, file_name, SFlag::S_IFREG, Mode::S_IRWXU, @@ -411,7 +411,7 @@ fn test_mknodat() { ) .unwrap(); let mode = fstatat( - unsafe { &BorrowedFd::borrow_raw(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 31b155b4e5..ebba852b02 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -20,7 +20,7 @@ use nix::sys::wait::*; use nix::unistd::ForkResult::*; use nix::unistd::*; #[cfg(not(target_os = "redox"))] -use nix::AT_FDCWD; +use nix::Cwd; use std::env; #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] use std::ffi::CString; @@ -140,7 +140,7 @@ fn test_mkfifoat_none() { let tempdir = tempdir().unwrap(); let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); - mkfifoat(AT_FDCWD, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); + mkfifoat(Cwd, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); let stats = stat::stat(&mkfifoat_fifo).unwrap(); let typ = SFlag::from_bits_truncate(stats.st_mode); @@ -181,7 +181,7 @@ fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); // mkfifoat should fail if a directory is given - mkfifoat(AT_FDCWD, &env::temp_dir(), Mode::S_IRUSR) + mkfifoat(Cwd, &env::temp_dir(), Mode::S_IRUSR) .expect_err("assertion failed"); } @@ -522,8 +522,7 @@ fn test_fchown() { 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(); + fchown(unsafe { BorrowedFd::borrow_raw(999999999) }, uid, gid).unwrap_err(); } #[test] @@ -545,11 +544,10 @@ fn test_fchownat() { fchownat(&dirfd, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); chdir(tempdir.path()).unwrap(); - fchownat(AT_FDCWD, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + fchownat(Cwd, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); fs::remove_file(&path).unwrap(); - fchownat(AT_FDCWD, "file", uid, gid, FchownatFlags::FollowSymlink) - .unwrap_err(); + fchownat(Cwd, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err(); } #[test] @@ -862,7 +860,7 @@ fn test_symlinkat() { let target = tempdir.path().join("a"); let linkpath = tempdir.path().join("b"); - symlinkat(&target, AT_FDCWD, &linkpath).unwrap(); + symlinkat(&target, Cwd, &linkpath).unwrap(); assert_eq!( readlink(&linkpath).unwrap().to_str().unwrap(), target.to_str().unwrap() @@ -932,7 +930,7 @@ fn test_linkat_olddirfd_none() { // Attempt hard link file using curent working directory as relative path for old file path chdir(tempdir_oldfile.path()).unwrap(); linkat( - AT_FDCWD, + Cwd, oldfilename, &dirfd, newfilename, @@ -967,7 +965,7 @@ fn test_linkat_newdirfd_none() { linkat( &dirfd, oldfilename, - AT_FDCWD, + Cwd, newfilename, LinkatFlags::SymlinkFollow, ) @@ -999,7 +997,7 @@ fn test_linkat_no_follow_symlink() { File::create(&oldfilepath).unwrap(); // Create symlink to file - symlinkat(&oldfilepath, AT_FDCWD, &symoldfilepath).unwrap(); + symlinkat(&oldfilepath, Cwd, &symoldfilepath).unwrap(); // Get file descriptor for base directory let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); @@ -1040,7 +1038,7 @@ fn test_linkat_follow_symlink() { File::create(&oldfilepath).unwrap(); // Create symlink to file - symlinkat(&oldfilepath, AT_FDCWD, &symoldfilepath).unwrap(); + symlinkat(&oldfilepath, Cwd, &symoldfilepath).unwrap(); // Get file descriptor for base directory let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); @@ -1285,7 +1283,7 @@ fn test_faccessat_none_not_existing() { let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); assert_eq!( - faccessat(AT_FDCWD, &dir, AccessFlags::F_OK, AtFlags::empty()) + faccessat(Cwd, &dir, AccessFlags::F_OK, AtFlags::empty()) .err() .unwrap(), Errno::ENOENT @@ -1315,7 +1313,7 @@ fn test_faccessat_none_file_exists() { let path = tempdir.path().join("does_exist.txt"); let _file = File::create(path.clone()).unwrap(); assert!(faccessat( - AT_FDCWD, + Cwd, &path, AccessFlags::R_OK | AccessFlags::W_OK, AtFlags::empty(), From e89b47a98850099bcf978755e745b7e5bfc75c00 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Wed, 7 Dec 2022 22:37:05 -0800 Subject: [PATCH 3/3] Rewrite dup implementations to allow passing in RawFd Signed-off-by: Alex Saveau --- src/unistd.rs | 62 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index bdc6647873..feedcdbf03 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -4,8 +4,6 @@ use crate::errno::{self, Errno}; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] use crate::fcntl::AtFlags; -#[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; #[cfg(all( feature = "fs", any( @@ -459,36 +457,58 @@ pub fn dup2(oldfd: Fd, newfd: &mut OwnedFd) -> Result<()> { Errno::result(res).map(drop) } +#[inline] +pub fn dup2_raw( + oldfd: Fd1, + newfd: Fd2, +) -> Result { + let res = + unsafe { libc::dup2(oldfd.as_fd().as_raw_fd(), newfd.as_raw_fd()) }; + + Errno::result(res) + .map(|_| unsafe { OwnedFd::from_raw_fd(newfd.into_raw_fd()) }) +} + /// Create a new copy of the specified file descriptor using the specified fd /// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. +#[cfg(any(target_os = "android", target_os = "linux"))] pub fn dup3( oldfd: Fd, newfd: &mut OwnedFd, - flags: OFlag, + flags: crate::fcntl::OFlag, ) -> Result<()> { - dup3_polyfill(oldfd, newfd, flags) -} - -#[inline] -fn dup3_polyfill( - oldfd: Fd, - newfd: &mut OwnedFd, - flags: OFlag, -) -> Result<()> { - if oldfd.as_fd().as_raw_fd() == newfd.as_raw_fd() { - return Err(Errno::EINVAL); - } + let res = unsafe { + libc::syscall( + libc::SYS_dup3, + oldfd.as_fd().as_raw_fd(), + newfd.as_raw_fd(), + flags.bits(), + ) + }; - dup2(oldfd, newfd)?; + Errno::result(res).map(drop) +} - if flags.contains(OFlag::O_CLOEXEC) { - fcntl(newfd.as_raw_fd(), F_SETFD(FdFlag::FD_CLOEXEC))?; - } +#[cfg(any(target_os = "android", target_os = "linux"))] +pub fn dup3_raw( + oldfd: Fd1, + newfd: Fd2, + flags: crate::fcntl::OFlag, +) -> Result { + let res = unsafe { + libc::syscall( + libc::SYS_dup3, + oldfd.as_fd().as_raw_fd(), + newfd.as_raw_fd(), + flags.bits(), + ) + }; - Ok(()) + Errno::result(res) + .map(|_| unsafe { OwnedFd::from_raw_fd(newfd.into_raw_fd()) }) } /// Change the current working directory of the calling process (see @@ -1264,7 +1284,7 @@ feature! { target_os = "openbsd", target_os = "solaris" ))] -pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { +pub fn pipe2(flags: crate::fcntl::OFlag) -> Result<(OwnedFd, OwnedFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); let res =