From ab5c032e42b4296603263140276f5202b6ea538b Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:50:45 +0800 Subject: feat: I/O safety for 'sys/sendfile' --- src/sys/sendfile.rs | 62 +++++++++++++++++++++++++++++++-------------------- test/test_sendfile.rs | 31 +++++++++++++++++--------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index fb293a4e..9f3c333f 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -1,7 +1,7 @@ //! Send data from a file to a socket, bypassing userland. use cfg_if::cfg_if; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use std::ptr; use libc::{self, off_t}; @@ -23,16 +23,23 @@ use crate::Result; /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile( - out_fd: RawFd, - in_fd: RawFd, +pub fn sendfile( + out_fd: F1, + in_fd: F2, offset: Option<&mut off_t>, count: usize, ) -> Result { let offset = offset .map(|offset| offset as *mut _) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; + let ret = unsafe { + libc::sendfile( + out_fd.as_fd().as_raw_fd(), + in_fd.as_fd().as_raw_fd(), + offset, + count, + ) + }; Errno::result(ret).map(|r| r as usize) } @@ -50,16 +57,23 @@ pub fn sendfile( /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile64( - out_fd: RawFd, - in_fd: RawFd, +pub fn sendfile64( + out_fd: F1, + in_fd: F2, offset: Option<&mut libc::off64_t>, count: usize, ) -> Result { let offset = offset .map(|offset| offset as *mut _) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; + let ret = unsafe { + libc::sendfile64( + out_fd.as_fd().as_raw_fd(), + in_fd.as_fd().as_raw_fd(), + offset, + count, + ) + }; Errno::result(ret).map(|r| r as usize) } @@ -156,9 +170,9 @@ cfg_if! { /// For more information, see /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) #[allow(clippy::too_many_arguments)] - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -175,8 +189,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, count.unwrap_or(0), hdtr_ptr as *mut libc::sf_hdtr, @@ -206,9 +220,9 @@ cfg_if! { /// /// For more information, see /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -218,8 +232,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, count.unwrap_or(0), hdtr_ptr as *mut libc::sf_hdtr, @@ -252,9 +266,9 @@ cfg_if! { /// /// For more information, see /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -264,8 +278,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, &mut len as *mut off_t, hdtr_ptr as *mut libc::sf_hdtr, diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index f73a3b56..c6ac6e6f 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -1,5 +1,6 @@ use std::io::prelude::*; -use std::os::unix::prelude::*; +#[cfg(any(target_os = "android", target_os = "linux"))] +use std::os::unix::io::{FromRawFd, OwnedFd}; use libc::off_t; use nix::sys::sendfile::*; @@ -23,7 +24,12 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + // 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); @@ -33,7 +39,6 @@ fn test_sendfile_linux() { assert_eq!(7, offset); close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "linux")] @@ -45,7 +50,12 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + // 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); @@ -55,7 +65,6 @@ fn test_sendfile64_linux() { assert_eq!(7, offset); close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "freebsd")] @@ -83,8 +92,8 @@ fn test_sendfile_freebsd() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), @@ -134,8 +143,8 @@ fn test_sendfile_dragonfly() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), @@ -183,8 +192,8 @@ fn test_sendfile_darwin() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), -- cgit v1.2.3