1 use nix::fcntl::{openat, open, OFlag, readlink, readlinkat};
2 use nix::sys::stat::Mode;
3 use nix::unistd::{close, read};
4 use tempdir::TempDir;
5 use tempfile::NamedTempFile;
6 use std::io::prelude::*;
7 use std::os::unix::fs;
8 
9 #[test]
test_openat()10 fn test_openat() {
11     const CONTENTS: &[u8] = b"abcd";
12     let mut tmp = NamedTempFile::new().unwrap();
13     tmp.write_all(CONTENTS).unwrap();
14 
15     let dirfd = open(tmp.path().parent().unwrap(),
16                      OFlag::empty(),
17                      Mode::empty()).unwrap();
18     let fd = openat(dirfd,
19                     tmp.path().file_name().unwrap(),
20                     OFlag::O_RDONLY,
21                     Mode::empty()).unwrap();
22 
23     let mut buf = [0u8; 1024];
24     assert_eq!(4, read(fd, &mut buf).unwrap());
25     assert_eq!(CONTENTS, &buf[0..4]);
26 
27     close(fd).unwrap();
28     close(dirfd).unwrap();
29 }
30 
31 #[test]
test_readlink()32 fn test_readlink() {
33     let tempdir = TempDir::new("nix-test_readdir")
34         .unwrap_or_else(|e| panic!("tempdir failed: {}", e));
35     let src = tempdir.path().join("a");
36     let dst = tempdir.path().join("b");
37     println!("a: {:?}, b: {:?}", &src, &dst);
38     fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
39     let dirfd = open(tempdir.path(),
40                      OFlag::empty(),
41                      Mode::empty()).unwrap();
42 
43     let mut buf = vec![0; src.to_str().unwrap().len() + 1];
44     assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
45                src.to_str().unwrap());
46     assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
47                src.to_str().unwrap());
48 }
49 
50 #[cfg(any(target_os = "linux", target_os = "android"))]
51 mod linux_android {
52     use std::io::prelude::*;
53     use std::os::unix::prelude::*;
54 
55     use libc::loff_t;
56 
57     use nix::fcntl::{SpliceFFlags, FallocateFlags, fallocate, splice, tee, vmsplice};
58     use nix::sys::uio::IoVec;
59     use nix::unistd::{close, pipe, read, write};
60 
61     use tempfile::{tempfile, NamedTempFile};
62 
63     #[test]
test_splice()64     fn test_splice() {
65         const CONTENTS: &[u8] = b"abcdef123456";
66         let mut tmp = tempfile().unwrap();
67         tmp.write_all(CONTENTS).unwrap();
68 
69         let (rd, wr) = pipe().unwrap();
70         let mut offset: loff_t = 5;
71         let res = splice(tmp.as_raw_fd(), Some(&mut offset),
72             wr, None, 2, SpliceFFlags::empty()).unwrap();
73 
74         assert_eq!(2, res);
75 
76         let mut buf = [0u8; 1024];
77         assert_eq!(2, read(rd, &mut buf).unwrap());
78         assert_eq!(b"f1", &buf[0..2]);
79         assert_eq!(7, offset);
80 
81         close(rd).unwrap();
82         close(wr).unwrap();
83     }
84 
85     #[test]
test_tee()86     fn test_tee() {
87         let (rd1, wr1) = pipe().unwrap();
88         let (rd2, wr2) = pipe().unwrap();
89 
90         write(wr1, b"abc").unwrap();
91         let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
92 
93         assert_eq!(2, res);
94 
95         let mut buf = [0u8; 1024];
96 
97         // Check the tee'd bytes are at rd2.
98         assert_eq!(2, read(rd2, &mut buf).unwrap());
99         assert_eq!(b"ab", &buf[0..2]);
100 
101         // Check all the bytes are still at rd1.
102         assert_eq!(3, read(rd1, &mut buf).unwrap());
103         assert_eq!(b"abc", &buf[0..3]);
104 
105         close(rd1).unwrap();
106         close(wr1).unwrap();
107         close(rd2).unwrap();
108         close(wr2).unwrap();
109     }
110 
111     #[test]
test_vmsplice()112     fn test_vmsplice() {
113         let (rd, wr) = pipe().unwrap();
114 
115         let buf1 = b"abcdef";
116         let buf2 = b"defghi";
117         let mut iovecs = Vec::with_capacity(2);
118         iovecs.push(IoVec::from_slice(&buf1[0..3]));
119         iovecs.push(IoVec::from_slice(&buf2[0..3]));
120 
121         let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
122 
123         assert_eq!(6, res);
124 
125         // Check the bytes can be read at rd.
126         let mut buf = [0u8; 32];
127         assert_eq!(6, read(rd, &mut buf).unwrap());
128         assert_eq!(b"abcdef", &buf[0..6]);
129 
130         close(rd).unwrap();
131         close(wr).unwrap();
132     }
133 
134     #[test]
test_fallocate()135     fn test_fallocate() {
136         let tmp = NamedTempFile::new().unwrap();
137 
138         let fd = tmp.as_raw_fd();
139         fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();
140 
141         // Check if we read exactly 100 bytes
142         let mut buf = [0u8; 200];
143         assert_eq!(100, read(fd, &mut buf).unwrap());
144     }
145 }
146