diff options
-rw-r--r-- | src/sys/uio.rs | 38 | ||||
-rw-r--r-- | test/sys/test_uio.rs | 63 |
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(); +} |