1use nix::sys::uio::*; 2use nix::unistd::*; 3use rand::distributions::Alphanumeric; 4use rand::{thread_rng, Rng}; 5use std::fs::OpenOptions; 6use std::io::IoSlice; 7use std::os::unix::io::AsRawFd; 8use std::{cmp, iter}; 9 10#[cfg(not(target_os = "redox"))] 11use std::io::IoSliceMut; 12 13use tempfile::tempdir; 14#[cfg(not(target_os = "redox"))] 15use tempfile::tempfile; 16 17#[test] 18fn test_writev() { 19 let mut to_write = Vec::with_capacity(16 * 128); 20 for _ in 0..16 { 21 let s: String = thread_rng() 22 .sample_iter(&Alphanumeric) 23 .map(char::from) 24 .take(128) 25 .collect(); 26 let b = s.as_bytes(); 27 to_write.extend(b.iter().cloned()); 28 } 29 // Allocate and fill iovecs 30 let mut iovecs = Vec::new(); 31 let mut consumed = 0; 32 while consumed < to_write.len() { 33 let left = to_write.len() - consumed; 34 let slice_len = if left <= 64 { 35 left 36 } else { 37 thread_rng().gen_range(64..cmp::min(256, left)) 38 }; 39 let b = &to_write[consumed..consumed + slice_len]; 40 iovecs.push(IoSlice::new(b)); 41 consumed += slice_len; 42 } 43 let pipe_res = pipe(); 44 let (reader, writer) = pipe_res.expect("Couldn't create pipe"); 45 // FileDesc will close its filedesc (reader). 46 let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect(); 47 // Blocking io, should write all data. 48 let write_res = writev(writer, &iovecs); 49 let written = write_res.expect("couldn't write"); 50 // Check whether we written all data 51 assert_eq!(to_write.len(), written); 52 let read_res = read(reader, &mut read_buf[..]); 53 let read = read_res.expect("couldn't read"); 54 // Check we have read as much as we written 55 assert_eq!(read, written); 56 // Check equality of written and read data 57 assert_eq!(&to_write, &read_buf); 58 close(writer).expect("closed writer"); 59 close(reader).expect("closed reader"); 60} 61 62#[test] 63#[cfg(not(target_os = "redox"))] 64fn test_readv() { 65 let s: String = thread_rng() 66 .sample_iter(&Alphanumeric) 67 .map(char::from) 68 .take(128) 69 .collect(); 70 let to_write = s.as_bytes().to_vec(); 71 let mut storage = Vec::new(); 72 let mut allocated = 0; 73 while allocated < to_write.len() { 74 let left = to_write.len() - allocated; 75 let vec_len = if left <= 64 { 76 left 77 } else { 78 thread_rng().gen_range(64..cmp::min(256, left)) 79 }; 80 let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect(); 81 storage.push(v); 82 allocated += vec_len; 83 } 84 let mut iovecs = Vec::with_capacity(storage.len()); 85 for v in &mut storage { 86 iovecs.push(IoSliceMut::new(&mut v[..])); 87 } 88 let (reader, writer) = pipe().expect("couldn't create pipe"); 89 // Blocking io, should write all data. 90 write(writer, &to_write).expect("write failed"); 91 let read = readv(reader, &mut iovecs[..]).expect("read failed"); 92 // Check whether we've read all data 93 assert_eq!(to_write.len(), read); 94 // Cccumulate data from iovecs 95 let mut read_buf = Vec::with_capacity(to_write.len()); 96 for iovec in &iovecs { 97 read_buf.extend(iovec.iter().cloned()); 98 } 99 // Check whether iovecs contain all written data 100 assert_eq!(read_buf.len(), to_write.len()); 101 // Check equality of written and read data 102 assert_eq!(&read_buf, &to_write); 103 close(reader).expect("couldn't close reader"); 104 close(writer).expect("couldn't close writer"); 105} 106 107#[test] 108#[cfg(not(target_os = "redox"))] 109fn test_pwrite() { 110 use std::io::Read; 111 112 let mut file = tempfile().unwrap(); 113 let buf = [1u8; 8]; 114 assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); 115 let mut file_content = Vec::new(); 116 file.read_to_end(&mut file_content).unwrap(); 117 let mut expected = vec![0u8; 8]; 118 expected.extend(vec![1; 8]); 119 assert_eq!(file_content, expected); 120} 121 122#[test] 123fn test_pread() { 124 use std::io::Write; 125 126 let tempdir = tempdir().unwrap(); 127 128 let path = tempdir.path().join("pread_test_file"); 129 let mut file = OpenOptions::new() 130 .write(true) 131 .read(true) 132 .create(true) 133 .truncate(true) 134 .open(path) 135 .unwrap(); 136 let file_content: Vec<u8> = (0..64).collect(); 137 file.write_all(&file_content).unwrap(); 138 139 let mut buf = [0u8; 16]; 140 assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); 141 let expected: Vec<_> = (16..32).collect(); 142 assert_eq!(&buf[..], &expected[..]); 143} 144 145#[test] 146#[cfg(not(any(target_os = "redox", target_os = "haiku")))] 147fn test_pwritev() { 148 use std::io::Read; 149 150 let to_write: Vec<u8> = (0..128).collect(); 151 let expected: Vec<u8> = [vec![0; 100], to_write.clone()].concat(); 152 153 let iovecs = [ 154 IoSlice::new(&to_write[0..17]), 155 IoSlice::new(&to_write[17..64]), 156 IoSlice::new(&to_write[64..128]), 157 ]; 158 159 let tempdir = tempdir().unwrap(); 160 161 // pwritev them into a temporary file 162 let path = tempdir.path().join("pwritev_test_file"); 163 let mut file = OpenOptions::new() 164 .write(true) 165 .read(true) 166 .create(true) 167 .truncate(true) 168 .open(path) 169 .unwrap(); 170 171 let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); 172 assert_eq!(written, to_write.len()); 173 174 // Read the data back and make sure it matches 175 let mut contents = Vec::new(); 176 file.read_to_end(&mut contents).unwrap(); 177 assert_eq!(contents, expected); 178} 179 180#[test] 181#[cfg(not(any(target_os = "redox", target_os = "haiku")))] 182fn test_preadv() { 183 use std::io::Write; 184 185 let to_write: Vec<u8> = (0..200).collect(); 186 let expected: Vec<u8> = (100..200).collect(); 187 188 let tempdir = tempdir().unwrap(); 189 190 let path = tempdir.path().join("preadv_test_file"); 191 192 let mut file = OpenOptions::new() 193 .read(true) 194 .write(true) 195 .create(true) 196 .truncate(true) 197 .open(path) 198 .unwrap(); 199 file.write_all(&to_write).unwrap(); 200 201 let mut buffers: Vec<Vec<u8>> = vec![vec![0; 24], vec![0; 1], vec![0; 75]]; 202 203 { 204 // Borrow the buffers into IoVecs and preadv into them 205 let mut iovecs: Vec<_> = buffers 206 .iter_mut() 207 .map(|buf| IoSliceMut::new(&mut buf[..])) 208 .collect(); 209 assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); 210 } 211 212 let all = buffers.concat(); 213 assert_eq!(all, expected); 214} 215 216#[test] 217#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] 218// uclibc doesn't implement process_vm_readv 219// qemu-user doesn't implement process_vm_readv/writev on most arches 220#[cfg_attr(qemu, ignore)] 221fn test_process_vm_readv() { 222 use crate::*; 223 use nix::sys::signal::*; 224 use nix::sys::wait::*; 225 use nix::unistd::ForkResult::*; 226 227 require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); 228 let _m = crate::FORK_MTX.lock(); 229 230 // Pre-allocate memory in the child, since allocation isn't safe 231 // post-fork (~= async-signal-safe) 232 let mut vector = vec![1u8, 2, 3, 4, 5]; 233 234 let (r, w) = pipe().unwrap(); 235 match unsafe { fork() }.expect("Error: Fork Failed") { 236 Parent { child } => { 237 close(w).unwrap(); 238 // wait for child 239 read(r, &mut [0u8]).unwrap(); 240 close(r).unwrap(); 241 242 let ptr = vector.as_ptr() as usize; 243 let remote_iov = RemoteIoVec { base: ptr, len: 5 }; 244 let mut buf = vec![0u8; 5]; 245 246 let ret = process_vm_readv( 247 child, 248 &mut [IoSliceMut::new(&mut buf)], 249 &[remote_iov], 250 ); 251 252 kill(child, SIGTERM).unwrap(); 253 waitpid(child, None).unwrap(); 254 255 assert_eq!(Ok(5), ret); 256 assert_eq!(20u8, buf.iter().sum()); 257 } 258 Child => { 259 let _ = close(r); 260 for i in &mut vector { 261 *i += 1; 262 } 263 let _ = write(w, b"\0"); 264 let _ = close(w); 265 loop { 266 pause(); 267 } 268 } 269 } 270} 271