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