diff options
Diffstat (limited to 'third_party/rust/nix/test/sys/test_uio.rs')
-rw-r--r-- | third_party/rust/nix/test/sys/test_uio.rs | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs new file mode 100644 index 0000000000..0f4b8a6568 --- /dev/null +++ b/third_party/rust/nix/test/sys/test_uio.rs @@ -0,0 +1,270 @@ +use nix::sys::uio::*; +use nix::unistd::*; +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; +use std::fs::OpenOptions; +use std::io::IoSlice; +use std::os::unix::io::AsRawFd; +use std::{cmp, iter}; + +#[cfg(not(target_os = "redox"))] +use std::io::IoSliceMut; + +use tempfile::tempdir; +#[cfg(not(target_os = "redox"))] +use tempfile::tempfile; + +#[test] +fn test_writev() { + let mut to_write = Vec::with_capacity(16 * 128); + for _ in 0..16 { + let s: String = thread_rng() + .sample_iter(&Alphanumeric) + .map(char::from) + .take(128) + .collect(); + let b = s.as_bytes(); + to_write.extend(b.iter().cloned()); + } + // Allocate and fill iovecs + let mut iovecs = Vec::new(); + let mut consumed = 0; + while consumed < to_write.len() { + let left = to_write.len() - consumed; + let slice_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; + let b = &to_write[consumed..consumed + slice_len]; + iovecs.push(IoSlice::new(b)); + consumed += slice_len; + } + let pipe_res = pipe(); + let (reader, writer) = pipe_res.expect("Couldn't create pipe"); + // FileDesc will close its filedesc (reader). + let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect(); + // 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 = 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(writer).expect("closed writer"); + close(reader).expect("closed reader"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_readv() { + let s: String = thread_rng() + .sample_iter(&Alphanumeric) + .map(char::from) + .take(128) + .collect(); + let to_write = s.as_bytes().to_vec(); + let mut storage = Vec::new(); + let mut allocated = 0; + while allocated < to_write.len() { + let left = to_write.len() - allocated; + let vec_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; + let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect(); + storage.push(v); + allocated += vec_len; + } + let mut iovecs = Vec::with_capacity(storage.len()); + for v in &mut storage { + iovecs.push(IoSliceMut::new(&mut v[..])); + } + let (reader, writer) = pipe().expect("couldn't create pipe"); + // Blocking io, should write all data. + 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); + // Cccumulate data from iovecs + let mut read_buf = Vec::with_capacity(to_write.len()); + for iovec in &iovecs { + read_buf.extend(iovec.iter().cloned()); + } + // Check whether iovecs contain all written data + assert_eq!(read_buf.len(), to_write.len()); + // Check equality of written and read data + assert_eq!(&read_buf, &to_write); + close(reader).expect("couldn't close reader"); + close(writer).expect("couldn't close writer"); +} + +#[test] +#[cfg(not(target_os = "redox"))] +fn test_pwrite() { + use std::io::Read; + + let mut file = tempfile().unwrap(); + let buf = [1u8; 8]; + assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); + let mut file_content = Vec::new(); + file.read_to_end(&mut file_content).unwrap(); + let mut expected = vec![0u8; 8]; + expected.extend(vec![1; 8]); + assert_eq!(file_content, expected); +} + +#[test] +fn test_pread() { + use std::io::Write; + + let tempdir = tempdir().unwrap(); + + let path = tempdir.path().join("pread_test_file"); + let mut file = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + let file_content: Vec<u8> = (0..64).collect(); + file.write_all(&file_content).unwrap(); + + let mut buf = [0u8; 16]; + assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); + let expected: Vec<_> = (16..32).collect(); + assert_eq!(&buf[..], &expected[..]); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +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 = [ + IoSlice::new(&to_write[0..17]), + IoSlice::new(&to_write[17..64]), + IoSlice::new(&to_write[64..128]), + ]; + + let tempdir = tempdir().unwrap(); + + // pwritev them into a temporary file + let path = tempdir.path().join("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); +} + +#[test] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +fn test_preadv() { + use std::io::Write; + + let to_write: Vec<u8> = (0..200).collect(); + let expected: Vec<u8> = (100..200).collect(); + + let tempdir = tempdir().unwrap(); + + let path = tempdir.path().join("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| IoSliceMut::new(&mut buf[..])) + .collect(); + assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); + } + + let all = buffers.concat(); + assert_eq!(all, expected); +} + +#[test] +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] +// uclibc doesn't implement process_vm_readv +// qemu-user doesn't implement process_vm_readv/writev on most arches +#[cfg_attr(qemu, ignore)] +fn test_process_vm_readv() { + use crate::*; + use nix::sys::signal::*; + use nix::sys::wait::*; + use nix::unistd::ForkResult::*; + + require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock(); + + // Pre-allocate memory in the child, since allocation isn't safe + // post-fork (~= async-signal-safe) + let mut vector = vec![1u8, 2, 3, 4, 5]; + + let (r, w) = pipe().unwrap(); + match unsafe { fork() }.expect("Error: Fork Failed") { + Parent { child } => { + close(w).unwrap(); + // wait for child + read(r, &mut [0u8]).unwrap(); + close(r).unwrap(); + + let ptr = vector.as_ptr() as usize; + let remote_iov = RemoteIoVec { base: ptr, len: 5 }; + let mut buf = vec![0u8; 5]; + + let ret = process_vm_readv( + child, + &mut [IoSliceMut::new(&mut buf)], + &[remote_iov], + ); + + kill(child, SIGTERM).unwrap(); + waitpid(child, None).unwrap(); + + assert_eq!(Ok(5), ret); + assert_eq!(20u8, buf.iter().sum()); + } + Child => { + let _ = close(r); + for i in &mut vector { + *i += 1; + } + let _ = write(w, b"\0"); + let _ = close(w); + loop { + pause(); + } + } + } +} |