summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrip Volpe <trip.volpe@gmail.com>2015-07-07 20:07:24 -0700
committerCarl Lerche <me@carllerche.com>2015-07-13 11:41:48 -0700
commita8182ce667947b33a91e3db03a3688e9f7f565a7 (patch)
tree0b204e59ddb4a79e0bdfeb867ffa21e4d842ac65
parenta5e9cc637b187d5c3446d1b90abea2c67031d9e9 (diff)
downloadnix-a8182ce667947b33a91e3db03a3688e9f7f565a7.zip
Add support for preadv and pwritev to sys/uio on Linux.
-rw-r--r--src/sys/uio.rs38
-rw-r--r--test/sys/test_uio.rs63
2 files changed, 101 insertions, 0 deletions
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index 43f0a23a..605ced4c 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -21,6 +21,18 @@ mod ffi {
// doc: http://man7.org/linux/man-pages/man2/readv.2.html
pub fn readv(fd: RawFd, iov: *const IoVec<&mut [u8]>, iovcnt: c_int) -> ssize_t;
+ // vectorized write at a specified offset
+ // doc: http://man7.org/linux/man-pages/man2/pwritev.2.html
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ pub fn pwritev(fd: RawFd, iov: *const IoVec<&[u8]>, iovcnt: c_int,
+ offset: off_t) -> ssize_t;
+
+ // vectorized read at a specified offset
+ // doc: http://man7.org/linux/man-pages/man2/preadv.2.html
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ pub fn preadv(fd: RawFd, iov: *const IoVec<&mut [u8]>, iovcnt: c_int,
+ offset: off_t) -> ssize_t;
+
// write to a file at a specified offset
// doc: http://man7.org/linux/man-pages/man2/pwrite.2.html
pub fn pwrite(fd: RawFd, buf: *const c_void, nbyte: size_t,
@@ -52,6 +64,32 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
return Ok(res as usize)
}
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
+ offset: off_t) -> Result<usize> {
+ let res = unsafe {
+ ffi::pwritev(fd, iov.as_ptr(), iov.len() as c_int, offset)
+ };
+ if res < 0 {
+ Err(Error::Sys(Errno::last()))
+ } else {
+ Ok(res as usize)
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn preadv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>],
+ offset: off_t) -> Result<usize> {
+ let res = unsafe {
+ ffi::preadv(fd, iov.as_ptr(), iov.len() as c_int, offset)
+ };
+ if res < 0 {
+ Err(Error::Sys(Errno::last()))
+ } else {
+ Ok(res as usize)
+ }
+}
+
pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
let res = unsafe {
ffi::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs
index d3d6d413..b12f1bb6 100644
--- a/test/sys/test_uio.rs
+++ b/test/sys/test_uio.rs
@@ -128,3 +128,66 @@ fn test_pread() {
remove_file(path).unwrap();
}
+
+#[test]
+#[cfg(any(target_os = "linux", target_os = "android"))]
+fn test_pwritev() {
+ use std::io::Read;
+
+ let to_write: Vec<u8> = (0..128).collect();
+ let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();
+
+ let iovecs = [
+ IoVec::from_slice(&to_write[0..17]),
+ IoVec::from_slice(&to_write[17..64]),
+ IoVec::from_slice(&to_write[64..128]),
+ ];
+
+ // pwritev them into a temporary file
+ let path = "pwritev_test_file";
+ let mut file = OpenOptions::new().write(true).read(true).create(true)
+ .truncate(true).open(path).unwrap();
+
+ let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
+ assert_eq!(written, to_write.len());
+
+ // Read the data back and make sure it matches
+ let mut contents = Vec::new();
+ file.read_to_end(&mut contents).unwrap();
+ assert_eq!(contents, expected);
+
+ remove_file(path).unwrap();
+}
+
+#[test]
+#[cfg(any(target_os = "linux", target_os = "android"))]
+fn test_preadv() {
+ use std::io::Write;
+
+ let to_write: Vec<u8> = (0..200).collect();
+ let expected: Vec<u8> = (100..200).collect();
+
+ let path = "preadv_test_file";
+
+ let mut file = OpenOptions::new().read(true).write(true).create(true)
+ .truncate(true).open(path).unwrap();
+ file.write_all(&to_write).unwrap();
+
+ let mut buffers: Vec<Vec<u8>> = vec![
+ vec![0; 24],
+ vec![0; 1],
+ vec![0; 75],
+ ];
+
+ {
+ // Borrow the buffers into IoVecs and preadv into them
+ let mut iovecs: Vec<_> = buffers.iter_mut().map(
+ |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
+ assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
+ }
+
+ let all = buffers.concat();
+ assert_eq!(all, expected);
+
+ remove_file(path).unwrap();
+}