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