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