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