1 use rustix::fd::{AsFd, AsRawFd, OwnedFd};
2 use rustix::fs::{cwd, mkdirat, openat, openat2, symlinkat, Mode, OFlags, ResolveFlags};
3 use rustix::{io, path};
4
5 /// Like `openat2`, but keep retrying until it fails or succeeds.
openat2_more<Fd: AsFd, P: path::Arg>( dirfd: Fd, path: P, oflags: OFlags, mode: Mode, resolve: ResolveFlags, ) -> io::Result<OwnedFd>6 fn openat2_more<Fd: AsFd, P: path::Arg>(
7 dirfd: Fd,
8 path: P,
9 oflags: OFlags,
10 mode: Mode,
11 resolve: ResolveFlags,
12 ) -> io::Result<OwnedFd> {
13 let path = path.as_cow_c_str().unwrap().into_owned();
14 loop {
15 match openat2(dirfd.as_fd(), &path, oflags, mode, resolve) {
16 Ok(file) => return Ok(file),
17 Err(io::Errno::AGAIN) => continue,
18 Err(err) => return Err(err),
19 }
20 }
21 }
22
23 #[test]
test_openat2()24 fn test_openat2() {
25 let tmp = tempfile::tempdir().unwrap();
26 let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap();
27
28 // Detect whether `openat2` is available.
29 match openat2(
30 &dir,
31 ".",
32 OFlags::RDONLY | OFlags::CLOEXEC,
33 Mode::empty(),
34 ResolveFlags::empty(),
35 ) {
36 Ok(_file) => (),
37 Err(io::Errno::NOSYS) => return,
38 Err(_err) => return,
39 }
40
41 // Create a file.
42 let _ = openat2_more(
43 &dir,
44 "test.txt",
45 OFlags::WRONLY | OFlags::CREATE | OFlags::TRUNC | OFlags::CLOEXEC,
46 Mode::RUSR,
47 ResolveFlags::empty(),
48 )
49 .unwrap();
50
51 // Test `NO_SYMLINKS`.
52 symlinkat("test.txt", &dir, "symlink.txt").unwrap();
53 let _ = openat2_more(
54 &dir,
55 "symlink.txt",
56 OFlags::RDONLY | OFlags::CLOEXEC,
57 Mode::empty(),
58 ResolveFlags::empty(),
59 )
60 .unwrap();
61 let _ = openat2_more(
62 &dir,
63 "symlink.txt",
64 OFlags::RDONLY | OFlags::CLOEXEC,
65 Mode::empty(),
66 ResolveFlags::NO_MAGICLINKS,
67 )
68 .unwrap();
69 let _ = openat2_more(
70 &dir,
71 "symlink.txt",
72 OFlags::RDONLY | OFlags::CLOEXEC,
73 Mode::empty(),
74 ResolveFlags::NO_SYMLINKS,
75 )
76 .unwrap_err();
77
78 // Test `NO_MAGICLINKS`.
79 let test = openat2_more(
80 &dir,
81 "test.txt",
82 OFlags::RDONLY | OFlags::CLOEXEC,
83 Mode::empty(),
84 ResolveFlags::empty(),
85 )
86 .unwrap();
87 let _ = openat2_more(
88 &dir,
89 &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()),
90 OFlags::RDONLY | OFlags::CLOEXEC,
91 Mode::empty(),
92 ResolveFlags::empty(),
93 )
94 .unwrap();
95 let _ = openat2_more(
96 &dir,
97 &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()),
98 OFlags::RDONLY | OFlags::CLOEXEC,
99 Mode::empty(),
100 ResolveFlags::NO_SYMLINKS,
101 )
102 .unwrap_err();
103 let _ = openat2_more(
104 &dir,
105 &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()),
106 OFlags::RDONLY | OFlags::CLOEXEC,
107 Mode::empty(),
108 ResolveFlags::NO_MAGICLINKS,
109 )
110 .unwrap_err();
111
112 // Test `NO_XDEV`.
113 let root = openat2_more(
114 &dir,
115 "/",
116 OFlags::RDONLY | OFlags::CLOEXEC,
117 Mode::empty(),
118 ResolveFlags::empty(),
119 )
120 .unwrap();
121 let _ = openat2_more(
122 &root,
123 "proc",
124 OFlags::RDONLY | OFlags::CLOEXEC,
125 Mode::empty(),
126 ResolveFlags::empty(),
127 )
128 .unwrap();
129 let _ = openat2_more(
130 &root,
131 "proc",
132 OFlags::RDONLY | OFlags::CLOEXEC,
133 Mode::empty(),
134 ResolveFlags::NO_XDEV,
135 )
136 .unwrap_err();
137
138 // Test `BENEATH`.
139 let _ = openat2_more(
140 &dir,
141 "..",
142 OFlags::RDONLY | OFlags::CLOEXEC,
143 Mode::empty(),
144 ResolveFlags::empty(),
145 )
146 .unwrap();
147 let _ = openat2_more(
148 &dir,
149 "..",
150 OFlags::RDONLY | OFlags::CLOEXEC,
151 Mode::empty(),
152 ResolveFlags::BENEATH,
153 )
154 .unwrap_err();
155
156 // Test `IN_ROOT`.
157 let _ = openat2_more(
158 &dir,
159 "/proc",
160 OFlags::RDONLY | OFlags::CLOEXEC,
161 Mode::empty(),
162 ResolveFlags::empty(),
163 )
164 .unwrap();
165 let _ = openat2_more(
166 &dir,
167 "/proc",
168 OFlags::RDONLY | OFlags::CLOEXEC,
169 Mode::empty(),
170 ResolveFlags::IN_ROOT,
171 )
172 .unwrap_err();
173 mkdirat(&dir, "proc", Mode::RUSR | Mode::XUSR).unwrap();
174 let _ = openat2_more(
175 &dir,
176 "/proc",
177 OFlags::RDONLY | OFlags::CLOEXEC,
178 Mode::empty(),
179 ResolveFlags::IN_ROOT,
180 )
181 .unwrap();
182 }
183