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 // UNSUPPORTED: c++03
10 
11 // The string reported on errors changed, which makes those tests fail when run
12 // against already-released libc++'s.
13 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.15|11.0}}
14 
15 // <filesystem>
16 
17 // class directory_entry
18 
19 // directory_entry& operator=(directory_entry const&) = default;
20 // directory_entry& operator=(directory_entry&&) noexcept = default;
21 // void assign(path const&);
22 // void replace_filename(path const&);
23 
24 #include "filesystem_include.h"
25 #include <type_traits>
26 #include <cassert>
27 
28 #include "test_macros.h"
29 #include "rapid-cxx-test.h"
30 #include "filesystem_test_helper.h"
31 
32 TEST_SUITE(directory_entry_mods_suite)
33 
TEST_CASE(test_refresh_method)34 TEST_CASE(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     TEST_CHECK(!e.exists());
47   }
48 }
49 
TEST_CASE(test_refresh_ec_method)50 TEST_CASE(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)), "operation should be noexcept");
56     static_assert(std::is_same<decltype(e.refresh(ec)), void>::value,
57                   "operation must return void");
58   }
59   {
60     directory_entry e;
61     std::error_code ec = GetTestEC();
62     e.refresh(ec);
63     TEST_CHECK(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.
TEST_CASE(refresh_on_file_dne)70 TEST_CASE(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(dir).permissions();
77 
78   // test file doesn't exist
79   {
80     directory_entry ent(file);
81     remove(file);
82     TEST_CHECK(ent.exists());
83 
84     ent.refresh();
85 
86     permissions(dir, perms::none);
87     TEST_CHECK(!ent.exists());
88   }
89   permissions(dir, old_perms);
90   env.create_file("dir/file", 101);
91   {
92     directory_entry ent(file);
93     remove(file);
94     TEST_CHECK(ent.exists());
95 
96     std::error_code ec = GetTestEC();
97     ent.refresh(ec);
98     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
99 
100     permissions(dir, perms::none);
101     TEST_CHECK(!ent.exists());
102   }
103 }
104 #endif
105 
remove_if_exists(const fs::path & p)106 void remove_if_exists(const fs::path& p) {
107   std::error_code ec;
108   remove(p, ec);
109 }
110 
TEST_CASE(refresh_on_bad_symlink)111 TEST_CASE(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(dir).permissions();
119 
120   // test file doesn't exist
121   {
122     directory_entry ent(sym);
123     LIBCPP_ONLY(remove(file));
124     TEST_CHECK(ent.is_symlink());
125     TEST_CHECK(ent.is_regular_file());
126     TEST_CHECK(ent.exists());
127 
128     remove_if_exists(file);
129     ent.refresh();
130 
131     LIBCPP_ONLY(permissions(dir, perms::none));
132     TEST_CHECK(ent.is_symlink());
133 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
134     TEST_CHECK(!ent.is_regular_file());
135     TEST_CHECK(!ent.exists());
136 #endif
137   }
138   permissions(dir, old_perms);
139   env.create_file("dir/file", 101);
140   {
141     directory_entry ent(sym);
142     LIBCPP_ONLY(remove(file));
143     TEST_CHECK(ent.is_symlink());
144     TEST_CHECK(ent.is_regular_file());
145     TEST_CHECK(ent.exists());
146 
147     remove_if_exists(file);
148 
149     std::error_code ec = GetTestEC();
150     ent.refresh(ec);
151     TEST_CHECK(!ec); // we don't report bad symlinks as an error.
152 
153     LIBCPP_ONLY(permissions(dir, perms::none));
154 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
155     TEST_CHECK(!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.
TEST_CASE(refresh_cannot_resolve)163 TEST_CASE(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(dir).permissions();
172 
173   {
174     directory_entry ent(file);
175     permissions(dir, perms::none);
176 
177     TEST_CHECK(ent.is_regular_file());
178 
179     std::error_code ec = GetTestEC();
180     ent.refresh(ec);
181 
182     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
183     TEST_CHECK(ent.path() == file);
184 
185     ExceptionChecker Checker(file, std::errc::permission_denied,
186                              "directory_entry::refresh");
187     TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
188   }
189   permissions(dir, old_perms);
190   {
191     directory_entry ent(sym_in_dir);
192     permissions(dir, perms::none);
193     TEST_CHECK(ent.is_symlink());
194 
195     std::error_code ec = GetTestEC();
196     ent.refresh(ec);
197     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
198     TEST_CHECK(ent.path() == sym_in_dir);
199 
200     ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
201                              "directory_entry::refresh");
202     TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
203   }
204   permissions(dir, old_perms);
205   {
206     directory_entry ent(sym_out_of_dir);
207     permissions(dir, perms::none);
208     TEST_CHECK(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);
214     TEST_CHECK(!ec);
215     TEST_CHECK(ent.is_symlink());
216 
217     ec = GetTestEC();
218     TEST_CHECK(ent.exists(ec) == false);
219     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
220     TEST_CHECK(ent.path() == sym_out_of_dir);
221   }
222   permissions(dir, 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(dir, perms::none);
228     ((void)ent_file);
229     ((void)ent_sym);
230 
231     TEST_CHECK_THROW(filesystem_error, ent_file.refresh());
232     TEST_CHECK_THROW(filesystem_error, ent_sym.refresh());
233     TEST_CHECK_NO_THROW(ent_sym2);
234   }
235 }
236 #endif
237 
TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it)238 TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it) {
239   using namespace fs;
240   scoped_test_env env;
241 
242   const path file = env.create_file("file1", 42);
243   const path sym = env.create_symlink("file1", "sym");
244 
245   {
246     directory_entry ent(file);
247     TEST_CHECK(ent.file_size() == 42);
248 
249     remove(file);
250 
251     std::error_code ec = GetTestEC();
252     ent.refresh(ec);
253     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
254     TEST_CHECK_NO_THROW(ent.refresh());
255 
256     ec = GetTestEC();
257     TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
258     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
259 
260     // doesn't throw!
261     TEST_CHECK_THROW(filesystem_error, ent.file_size());
262   }
263   env.create_file("file1", 99);
264   {
265     directory_entry ent(sym);
266     TEST_CHECK(ent.is_symlink());
267     TEST_CHECK(ent.is_regular_file());
268     TEST_CHECK(ent.file_size() == 99);
269 
270     remove(file);
271 
272     std::error_code ec = GetTestEC();
273     ent.refresh(ec);
274     TEST_CHECK(!ec);
275 
276     ec = GetTestEC();
277     TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
278     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
279 
280     TEST_CHECK_THROW(filesystem_error, ent.file_size());
281   }
282 }
283 
284 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
285 // Windows doesn't support setting perms::none to trigger failures
286 // reading directories.
TEST_CASE(access_cache_after_refresh_fails)287 TEST_CASE(access_cache_after_refresh_fails) {
288   using namespace fs;
289   scoped_test_env env;
290   const path dir = env.create_dir("dir");
291   const path file = env.create_file("dir/file", 42);
292   const path file_out_of_dir = env.create_file("file1", 101);
293   const path sym = env.create_symlink("dir/file", "sym");
294   const path sym_in_dir = env.create_symlink("dir/file", "dir/sym2");
295 
296   const perms old_perms = status(dir).permissions();
297 
298 #define CHECK_ACCESS(func, expect)                                             \
299   ec = GetTestEC();                                                            \
300   TEST_CHECK(ent.func(ec) == expect);                                          \
301   TEST_CHECK(ErrorIs(ec, std::errc::permission_denied))
302 
303   // test file doesn't exist
304   {
305     directory_entry ent(file);
306 
307     TEST_CHECK(!ent.is_symlink());
308     TEST_CHECK(ent.is_regular_file());
309     TEST_CHECK(ent.exists());
310 
311     permissions(dir, perms::none);
312     std::error_code ec = GetTestEC();
313     ent.refresh(ec);
314     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
315 
316     CHECK_ACCESS(exists, false);
317     CHECK_ACCESS(is_symlink, false);
318     CHECK_ACCESS(last_write_time, file_time_type::min());
319     CHECK_ACCESS(hard_link_count, uintmax_t(-1));
320   }
321   permissions(dir, old_perms);
322   {
323     directory_entry ent(sym_in_dir);
324     TEST_CHECK(ent.is_symlink());
325     TEST_CHECK(ent.is_regular_file());
326     TEST_CHECK(ent.exists());
327 
328     permissions(dir, perms::none);
329     std::error_code ec = GetTestEC();
330     ent.refresh(ec);
331     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
332 
333     CHECK_ACCESS(exists, false);
334     CHECK_ACCESS(is_symlink, false);
335     CHECK_ACCESS(last_write_time, file_time_type::min());
336     CHECK_ACCESS(hard_link_count, uintmax_t(-1));
337   }
338   permissions(dir, old_perms);
339   {
340     directory_entry ent(sym);
341     TEST_CHECK(ent.is_symlink());
342     TEST_CHECK(ent.is_regular_file());
343     TEST_CHECK(ent.exists());
344 
345     permissions(dir, perms::none);
346     std::error_code ec = GetTestEC();
347     ent.refresh(ec);
348     TEST_CHECK(!ec);
349     TEST_CHECK(ent.is_symlink());
350 
351     CHECK_ACCESS(exists, false);
352     CHECK_ACCESS(is_regular_file, false);
353     CHECK_ACCESS(last_write_time, file_time_type::min());
354     CHECK_ACCESS(hard_link_count, uintmax_t(-1));
355   }
356 #undef CHECK_ACCESS
357 }
358 #endif
359 
360 TEST_SUITE_END()
361