1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // REQUIRES: can-create-symlinks |
10 | // UNSUPPORTED: c++03, c++11, c++14 |
11 | |
12 | // The string reported on errors changed, which makes those tests fail when run |
13 | // against a built library that doesn't contain 0aa637b2037d. |
14 | // XFAIL: using-built-library-before-llvm-13 |
15 | |
16 | // <filesystem> |
17 | |
18 | // class directory_entry |
19 | |
20 | // directory_entry& operator=(directory_entry const&) = default; |
21 | // directory_entry& operator=(directory_entry&&) noexcept = default; |
22 | // void assign(path const&); |
23 | // void replace_filename(path const&); |
24 | |
25 | #include <filesystem> |
26 | #include <type_traits> |
27 | #include <cassert> |
28 | |
29 | #include "assert_macros.h" |
30 | #include "test_macros.h" |
31 | #include "filesystem_test_helper.h" |
32 | namespace fs = std::filesystem; |
33 | |
34 | static void test_refresh_method() { |
35 | using namespace fs; |
36 | { |
37 | directory_entry e; |
38 | static_assert(noexcept(e.refresh()) == false, |
39 | "operation cannot be noexcept" ); |
40 | static_assert(std::is_same<decltype(e.refresh()), void>::value, |
41 | "operation must return void" ); |
42 | } |
43 | { |
44 | directory_entry e; |
45 | e.refresh(); |
46 | assert(!e.exists()); |
47 | } |
48 | } |
49 | |
50 | static void test_refresh_ec_method() { |
51 | using namespace fs; |
52 | { |
53 | directory_entry e; |
54 | std::error_code ec; |
55 | static_assert(noexcept(e.refresh(ec&: ec)), "operation should be noexcept" ); |
56 | static_assert(std::is_same<decltype(e.refresh(ec&: ec)), void>::value, |
57 | "operation must return void" ); |
58 | } |
59 | { |
60 | directory_entry e; |
61 | std::error_code ec = GetTestEC(); |
62 | e.refresh(ec&: ec); |
63 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
64 | } |
65 | } |
66 | |
67 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
68 | // Windows doesn't support setting perms::none to trigger failures |
69 | // reading directories. |
70 | static void refresh_on_file_dne() { |
71 | using namespace fs; |
72 | scoped_test_env env; |
73 | const path dir = env.create_dir("dir" ); |
74 | const path file = env.create_file("dir/file" , 42); |
75 | |
76 | const perms old_perms = status(p: dir).permissions(); |
77 | |
78 | // test file doesn't exist |
79 | { |
80 | directory_entry ent(file); |
81 | remove(p: file); |
82 | assert(ent.exists()); |
83 | |
84 | ent.refresh(); |
85 | |
86 | permissions(p: dir, prms: perms::none); |
87 | assert(!ent.exists()); |
88 | } |
89 | permissions(p: dir, prms: old_perms); |
90 | env.create_file("dir/file" , 101); |
91 | { |
92 | directory_entry ent(file); |
93 | remove(p: file); |
94 | assert(ent.exists()); |
95 | |
96 | std::error_code ec = GetTestEC(); |
97 | ent.refresh(ec&: ec); |
98 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
99 | |
100 | permissions(p: dir, prms: perms::none); |
101 | assert(!ent.exists()); |
102 | } |
103 | } |
104 | #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
105 | |
106 | void remove_if_exists(const fs::path& p) { |
107 | std::error_code ec; |
108 | remove(p: p, ec&: ec); |
109 | } |
110 | |
111 | static void refresh_on_bad_symlink() { |
112 | using namespace fs; |
113 | scoped_test_env env; |
114 | const path dir = env.create_dir("dir" ); |
115 | const path file = env.create_file("dir/file" , 42); |
116 | const path sym = env.create_symlink("dir/file" , "sym" ); |
117 | |
118 | const perms old_perms = status(p: dir).permissions(); |
119 | |
120 | // test file doesn't exist |
121 | { |
122 | directory_entry ent(sym); |
123 | LIBCPP_ONLY(remove(p: file)); |
124 | assert(ent.is_symlink()); |
125 | assert(ent.is_regular_file()); |
126 | assert(ent.exists()); |
127 | |
128 | remove_if_exists(p: file); |
129 | ent.refresh(); |
130 | |
131 | LIBCPP_ONLY(permissions(p: dir, prms: perms::none)); |
132 | assert(ent.is_symlink()); |
133 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
134 | assert(!ent.is_regular_file()); |
135 | assert(!ent.exists()); |
136 | #endif |
137 | } |
138 | permissions(p: dir, prms: old_perms); |
139 | env.create_file("dir/file" , 101); |
140 | { |
141 | directory_entry ent(sym); |
142 | LIBCPP_ONLY(remove(p: file)); |
143 | assert(ent.is_symlink()); |
144 | assert(ent.is_regular_file()); |
145 | assert(ent.exists()); |
146 | |
147 | remove_if_exists(p: file); |
148 | |
149 | std::error_code ec = GetTestEC(); |
150 | ent.refresh(ec&: ec); |
151 | assert(!ec); // we don't report bad symlinks as an error. |
152 | |
153 | LIBCPP_ONLY(permissions(p: dir, prms: perms::none)); |
154 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
155 | assert(!ent.exists()); |
156 | #endif |
157 | } |
158 | } |
159 | |
160 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
161 | // Windows doesn't support setting perms::none to trigger failures |
162 | // reading directories. |
163 | static void refresh_cannot_resolve() { |
164 | using namespace fs; |
165 | scoped_test_env env; |
166 | const path dir = env.create_dir("dir" ); |
167 | const path file = env.create_file("dir/file" , 42); |
168 | const path file_out_of_dir = env.create_file("file1" , 99); |
169 | const path sym_out_of_dir = env.create_symlink("dir/file" , "sym" ); |
170 | const path sym_in_dir = env.create_symlink("file1" , "dir/sym1" ); |
171 | perms old_perms = status(p: dir).permissions(); |
172 | |
173 | { |
174 | directory_entry ent(file); |
175 | permissions(p: dir, prms: perms::none); |
176 | |
177 | assert(ent.is_regular_file()); |
178 | |
179 | std::error_code ec = GetTestEC(); |
180 | ent.refresh(ec&: ec); |
181 | |
182 | assert(ErrorIs(ec, std::errc::permission_denied)); |
183 | assert(ent.path() == file); |
184 | |
185 | ExceptionChecker Checker(file, std::errc::permission_denied, |
186 | "directory_entry::refresh" ); |
187 | TEST_VALIDATE_EXCEPTION(filesystem_error, Checker, ent.refresh()); |
188 | } |
189 | permissions(p: dir, prms: old_perms); |
190 | { |
191 | directory_entry ent(sym_in_dir); |
192 | permissions(p: dir, prms: perms::none); |
193 | assert(ent.is_symlink()); |
194 | |
195 | std::error_code ec = GetTestEC(); |
196 | ent.refresh(ec&: ec); |
197 | assert(ErrorIs(ec, std::errc::permission_denied)); |
198 | assert(ent.path() == sym_in_dir); |
199 | |
200 | ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied, |
201 | "directory_entry::refresh" ); |
202 | TEST_VALIDATE_EXCEPTION(filesystem_error, Checker, ent.refresh()); |
203 | } |
204 | permissions(p: dir, prms: old_perms); |
205 | { |
206 | directory_entry ent(sym_out_of_dir); |
207 | permissions(p: dir, prms: perms::none); |
208 | assert(ent.is_symlink()); |
209 | |
210 | // Failure to resolve the linked entity due to permissions is not |
211 | // reported as an error. |
212 | std::error_code ec = GetTestEC(); |
213 | ent.refresh(ec&: ec); |
214 | assert(!ec); |
215 | assert(ent.is_symlink()); |
216 | |
217 | ec = GetTestEC(); |
218 | assert(ent.exists(ec) == false); |
219 | assert(ErrorIs(ec, std::errc::permission_denied)); |
220 | assert(ent.path() == sym_out_of_dir); |
221 | } |
222 | permissions(p: dir, prms: old_perms); |
223 | { |
224 | directory_entry ent_file(file); |
225 | directory_entry ent_sym(sym_in_dir); |
226 | directory_entry ent_sym2(sym_out_of_dir); |
227 | permissions(p: dir, prms: perms::none); |
228 | ((void)ent_file); |
229 | ((void)ent_sym); |
230 | |
231 | TEST_THROWS_TYPE(filesystem_error, ent_file.refresh()); |
232 | TEST_THROWS_TYPE(filesystem_error, ent_sym.refresh()); |
233 | } |
234 | } |
235 | #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
236 | |
237 | static void refresh_doesnt_throw_on_dne_but_reports_it() { |
238 | using namespace fs; |
239 | scoped_test_env env; |
240 | |
241 | const path file = env.create_file("file1" , 42); |
242 | const path sym = env.create_symlink("file1" , "sym" ); |
243 | |
244 | { |
245 | directory_entry ent(file); |
246 | assert(ent.file_size() == 42); |
247 | |
248 | remove(p: file); |
249 | |
250 | std::error_code ec = GetTestEC(); |
251 | ent.refresh(ec&: ec); |
252 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
253 | TEST_DOES_NOT_THROW(ent.refresh()); |
254 | |
255 | ec = GetTestEC(); |
256 | assert(ent.file_size(ec) == std::uintmax_t(-1)); |
257 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
258 | |
259 | // doesn't throw! |
260 | // |
261 | // |
262 | // |
263 | //TEST_THROWS_TYPE(filesystem_error, ent.file_size()); |
264 | } |
265 | env.create_file("file1" , 99); |
266 | { |
267 | directory_entry ent(sym); |
268 | assert(ent.is_symlink()); |
269 | assert(ent.is_regular_file()); |
270 | assert(ent.file_size() == 99); |
271 | |
272 | remove(p: file); |
273 | |
274 | std::error_code ec = GetTestEC(); |
275 | ent.refresh(ec&: ec); |
276 | assert(!ec); |
277 | |
278 | ec = GetTestEC(); |
279 | assert(ent.file_size(ec) == std::uintmax_t(-1)); |
280 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
281 | |
282 | TEST_THROWS_TYPE(filesystem_error, ent.file_size()); |
283 | } |
284 | } |
285 | |
286 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
287 | // Windows doesn't support setting perms::none to trigger failures |
288 | // reading directories. |
289 | static void access_cache_after_refresh_fails() { |
290 | using namespace fs; |
291 | scoped_test_env env; |
292 | const path dir = env.create_dir("dir" ); |
293 | const path file = env.create_file("dir/file" , 42); |
294 | const path file_out_of_dir = env.create_file("file1" , 101); |
295 | const path sym = env.create_symlink("dir/file" , "sym" ); |
296 | const path sym_in_dir = env.create_symlink("dir/file" , "dir/sym2" ); |
297 | |
298 | const perms old_perms = status(p: dir).permissions(); |
299 | |
300 | #define CHECK_ACCESS(func, expect) \ |
301 | ec = GetTestEC(); \ |
302 | assert(ent.func(ec) == expect); \ |
303 | assert(ErrorIs(ec, std::errc::permission_denied)) |
304 | |
305 | // test file doesn't exist |
306 | { |
307 | directory_entry ent(file); |
308 | |
309 | assert(!ent.is_symlink()); |
310 | assert(ent.is_regular_file()); |
311 | assert(ent.exists()); |
312 | |
313 | permissions(p: dir, prms: perms::none); |
314 | std::error_code ec = GetTestEC(); |
315 | ent.refresh(ec&: ec); |
316 | assert(ErrorIs(ec, std::errc::permission_denied)); |
317 | |
318 | CHECK_ACCESS(exists, false); |
319 | CHECK_ACCESS(is_symlink, false); |
320 | CHECK_ACCESS(last_write_time, file_time_type::min()); |
321 | CHECK_ACCESS(hard_link_count, std::uintmax_t(-1)); |
322 | } |
323 | permissions(p: dir, prms: old_perms); |
324 | { |
325 | directory_entry ent(sym_in_dir); |
326 | assert(ent.is_symlink()); |
327 | assert(ent.is_regular_file()); |
328 | assert(ent.exists()); |
329 | |
330 | permissions(p: dir, prms: perms::none); |
331 | std::error_code ec = GetTestEC(); |
332 | ent.refresh(ec&: ec); |
333 | assert(ErrorIs(ec, std::errc::permission_denied)); |
334 | |
335 | CHECK_ACCESS(exists, false); |
336 | CHECK_ACCESS(is_symlink, false); |
337 | CHECK_ACCESS(last_write_time, file_time_type::min()); |
338 | CHECK_ACCESS(hard_link_count, std::uintmax_t(-1)); |
339 | } |
340 | permissions(p: dir, prms: old_perms); |
341 | { |
342 | directory_entry ent(sym); |
343 | assert(ent.is_symlink()); |
344 | assert(ent.is_regular_file()); |
345 | assert(ent.exists()); |
346 | |
347 | permissions(p: dir, prms: perms::none); |
348 | std::error_code ec = GetTestEC(); |
349 | ent.refresh(ec&: ec); |
350 | assert(!ec); |
351 | assert(ent.is_symlink()); |
352 | |
353 | CHECK_ACCESS(exists, false); |
354 | CHECK_ACCESS(is_regular_file, false); |
355 | CHECK_ACCESS(last_write_time, file_time_type::min()); |
356 | CHECK_ACCESS(hard_link_count, std::uintmax_t(-1)); |
357 | } |
358 | #undef CHECK_ACCESS |
359 | } |
360 | #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
361 | |
362 | int main(int, char**) { |
363 | test_refresh_method(); |
364 | test_refresh_ec_method(); |
365 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
366 | refresh_on_file_dne(); |
367 | #endif |
368 | refresh_on_bad_symlink(); |
369 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
370 | refresh_cannot_resolve(); |
371 | #endif |
372 | refresh_doesnt_throw_on_dne_but_reports_it(); |
373 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
374 | access_cache_after_refresh_fails(); |
375 | #endif |
376 | return 0; |
377 | } |
378 | |