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