• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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