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