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