summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Lau <stevelauc@outlook.com>2022-12-09 11:50:45 +0800
committerSteve Lau <stevelauc@outlook.com>2022-12-09 11:50:45 +0800
commitab5c032e42b4296603263140276f5202b6ea538b (patch)
treec91b92e9c16e68de63d6eb3b665b7f1261267106
parent7f18847f4d59390698c62e2fd5a609cef2439673 (diff)
downloadnix-ab5c032e42b4296603263140276f5202b6ea538b.zip
feat: I/O safety for 'sys/sendfile'
-rw-r--r--src/sys/sendfile.rs62
-rw-r--r--test/test_sendfile.rs31
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<F1: AsFd, F2: AsFd>(
+ out_fd: F1,
+ in_fd: F2,
offset: Option<&mut off_t>,
count: usize,
) -> Result<usize> {
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<F1: AsFd, F2: AsFd>(
+ out_fd: F1,
+ in_fd: F2,
offset: Option<&mut libc::off64_t>,
count: usize,
) -> Result<usize> {
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<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<usize>,
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&section=2)
- pub fn sendfile(
- in_fd: RawFd,
- out_sock: RawFd,
+ pub fn sendfile<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<usize>,
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<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<off_t>,
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()),