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