1 use nix::sys::uio::*;
2 use nix::unistd::*;
3 use rand::distributions::Alphanumeric;
4 use rand::{thread_rng, Rng};
5 use std::fs::OpenOptions;
6 use std::io::IoSlice;
7 use std::os::unix::io::AsRawFd;
8 use std::{cmp, iter};
9
10 #[cfg(not(target_os = "redox"))]
11 use std::io::IoSliceMut;
12
13 use tempfile::tempdir;
14 #[cfg(not(target_os = "redox"))]
15 use tempfile::tempfile;
16
17 #[test]
test_writev()18 fn 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"))]
test_readv()64 fn 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"))]
test_pwrite()109 fn 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]
test_pread()123 fn 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")))]
test_pwritev()147 fn 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")))]
test_preadv()182 fn 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)]
test_process_vm_readv()221 fn 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