xref: /third_party/rust/crates/nix/test/sys/test_uio.rs (revision 3da5c369)
1use nix::sys::uio::*;
2use nix::unistd::*;
3use rand::distributions::Alphanumeric;
4use rand::{thread_rng, Rng};
5use std::fs::OpenOptions;
6use std::io::IoSlice;
7use std::os::unix::io::AsRawFd;
8use std::{cmp, iter};
9
10#[cfg(not(target_os = "redox"))]
11use std::io::IoSliceMut;
12
13use tempfile::tempdir;
14#[cfg(not(target_os = "redox"))]
15use tempfile::tempfile;
16
17#[test]
18fn 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"))]
64fn 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"))]
109fn 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]
123fn 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")))]
147fn 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")))]
182fn 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)]
221fn 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