1 //===----------------------------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // UNSUPPORTED: c++98, c++03
11
12 // <filesystem>
13
14 // class directory_entry
15
16 // directory_entry& operator=(directory_entry const&) = default;
17 // directory_entry& operator=(directory_entry&&) noexcept = default;
18 // void assign(path const&);
19 // void replace_filename(path const&);
20
21 #include "filesystem_include.hpp"
22 #include <type_traits>
23 #include <cassert>
24
25 #include "test_macros.h"
26 #include "rapid-cxx-test.hpp"
27 #include "filesystem_test_helper.hpp"
28
29 TEST_SUITE(directory_entry_mods_suite)
30
TEST_CASE(test_refresh_method)31 TEST_CASE(test_refresh_method) {
32 using namespace fs;
33 {
34 directory_entry e;
35 static_assert(noexcept(e.refresh()) == false,
36 "operation cannot be noexcept");
37 static_assert(std::is_same<decltype(e.refresh()), void>::value,
38 "operation must return void");
39 }
40 {
41 directory_entry e;
42 e.refresh();
43 TEST_CHECK(!e.exists());
44 }
45 }
46
TEST_CASE(test_refresh_ec_method)47 TEST_CASE(test_refresh_ec_method) {
48 using namespace fs;
49 {
50 directory_entry e;
51 std::error_code ec;
52 static_assert(noexcept(e.refresh(ec)), "operation should be noexcept");
53 static_assert(std::is_same<decltype(e.refresh(ec)), void>::value,
54 "operation must return void");
55 }
56 {
57 directory_entry e;
58 std::error_code ec = GetTestEC();
59 e.refresh(ec);
60 TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
61 }
62 }
63
TEST_CASE(refresh_on_file_dne)64 TEST_CASE(refresh_on_file_dne) {
65 using namespace fs;
66 scoped_test_env env;
67 const path dir = env.create_dir("dir");
68 const path file = env.create_file("dir/file", 42);
69
70 const perms old_perms = status(dir).permissions();
71
72 // test file doesn't exist
73 {
74 directory_entry ent(file);
75 remove(file);
76 TEST_CHECK(ent.exists());
77
78 ent.refresh();
79
80 permissions(dir, perms::none);
81 TEST_CHECK(!ent.exists());
82 }
83 permissions(dir, old_perms);
84 env.create_file("dir/file", 101);
85 {
86 directory_entry ent(file);
87 remove(file);
88 TEST_CHECK(ent.exists());
89
90 std::error_code ec = GetTestEC();
91 ent.refresh(ec);
92 TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
93
94 permissions(dir, perms::none);
95 TEST_CHECK(!ent.exists());
96 }
97 }
98
remove_if_exists(const fs::path & p)99 void remove_if_exists(const fs::path& p) {
100 std::error_code ec;
101 remove(p, ec);
102 }
103
TEST_CASE(refresh_on_bad_symlink)104 TEST_CASE(refresh_on_bad_symlink) {
105 using namespace fs;
106 scoped_test_env env;
107 const path dir = env.create_dir("dir");
108 const path file = env.create_file("dir/file", 42);
109 const path sym = env.create_symlink("dir/file", "sym");
110
111 const perms old_perms = status(dir).permissions();
112
113 // test file doesn't exist
114 {
115 directory_entry ent(sym);
116 LIBCPP_ONLY(remove(file));
117 TEST_CHECK(ent.is_symlink());
118 TEST_CHECK(ent.is_regular_file());
119 TEST_CHECK(ent.exists());
120
121 remove_if_exists(file);
122 ent.refresh();
123
124 LIBCPP_ONLY(permissions(dir, perms::none));
125 TEST_CHECK(ent.is_symlink());
126 TEST_CHECK(!ent.is_regular_file());
127 TEST_CHECK(!ent.exists());
128 }
129 permissions(dir, old_perms);
130 env.create_file("dir/file", 101);
131 {
132 directory_entry ent(sym);
133 LIBCPP_ONLY(remove(file));
134 TEST_CHECK(ent.is_symlink());
135 TEST_CHECK(ent.is_regular_file());
136 TEST_CHECK(ent.exists());
137
138 remove_if_exists(file);
139
140 std::error_code ec = GetTestEC();
141 ent.refresh(ec);
142 TEST_CHECK(!ec); // we don't report bad symlinks as an error.
143
144 LIBCPP_ONLY(permissions(dir, perms::none));
145 TEST_CHECK(!ent.exists());
146 }
147 }
148
TEST_CASE(refresh_cannot_resolve)149 TEST_CASE(refresh_cannot_resolve) {
150 using namespace fs;
151 scoped_test_env env;
152 const path dir = env.create_dir("dir");
153 const path file = env.create_file("dir/file", 42);
154 const path file_out_of_dir = env.create_file("file1", 99);
155 const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
156 const path sym_in_dir = env.create_symlink("file1", "dir/sym1");
157 perms old_perms = status(dir).permissions();
158
159 {
160 directory_entry ent(file);
161 permissions(dir, perms::none);
162
163 TEST_CHECK(ent.is_regular_file());
164
165 std::error_code ec = GetTestEC();
166 ent.refresh(ec);
167
168 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
169 TEST_CHECK(ent.path() == file);
170
171 ExceptionChecker Checker(file, std::errc::permission_denied,
172 "directory_entry::refresh");
173 TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
174 }
175 permissions(dir, old_perms);
176 {
177 directory_entry ent(sym_in_dir);
178 permissions(dir, perms::none);
179 TEST_CHECK(ent.is_symlink());
180
181 std::error_code ec = GetTestEC();
182 ent.refresh(ec);
183 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
184 TEST_CHECK(ent.path() == sym_in_dir);
185
186 ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
187 "directory_entry::refresh");
188 TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
189 }
190 permissions(dir, old_perms);
191 {
192 directory_entry ent(sym_out_of_dir);
193 permissions(dir, perms::none);
194 TEST_CHECK(ent.is_symlink());
195
196 // Failure to resolve the linked entity due to permissions is not
197 // reported as an error.
198 std::error_code ec = GetTestEC();
199 ent.refresh(ec);
200 TEST_CHECK(!ec);
201 TEST_CHECK(ent.is_symlink());
202
203 ec = GetTestEC();
204 TEST_CHECK(ent.exists(ec) == false);
205 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
206 TEST_CHECK(ent.path() == sym_out_of_dir);
207 }
208 permissions(dir, old_perms);
209 {
210 directory_entry ent_file(file);
211 directory_entry ent_sym(sym_in_dir);
212 directory_entry ent_sym2(sym_out_of_dir);
213 permissions(dir, perms::none);
214 ((void)ent_file);
215 ((void)ent_sym);
216
217 TEST_CHECK_THROW(filesystem_error, ent_file.refresh());
218 TEST_CHECK_THROW(filesystem_error, ent_sym.refresh());
219 TEST_CHECK_NO_THROW(ent_sym2);
220 }
221 }
222
TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it)223 TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it) {
224 using namespace fs;
225 scoped_test_env env;
226
227 const path file = env.create_file("file1", 42);
228 const path sym = env.create_symlink("file1", "sym");
229
230 {
231 directory_entry ent(file);
232 TEST_CHECK(ent.file_size() == 42);
233
234 remove(file);
235
236 std::error_code ec = GetTestEC();
237 ent.refresh(ec);
238 TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
239 TEST_CHECK_NO_THROW(ent.refresh());
240
241 ec = GetTestEC();
242 TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
243 TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
244
245 // doesn't throw!
246 TEST_CHECK_THROW(filesystem_error, ent.file_size());
247 }
248 env.create_file("file1", 99);
249 {
250 directory_entry ent(sym);
251 TEST_CHECK(ent.is_symlink());
252 TEST_CHECK(ent.is_regular_file());
253 TEST_CHECK(ent.file_size() == 99);
254
255 remove(file);
256
257 std::error_code ec = GetTestEC();
258 ent.refresh(ec);
259 TEST_CHECK(!ec);
260
261 ec = GetTestEC();
262 TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
263 TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
264
265 TEST_CHECK_THROW(filesystem_error, ent.file_size());
266 }
267 }
268
TEST_CASE(access_cache_after_refresh_fails)269 TEST_CASE(access_cache_after_refresh_fails) {
270 using namespace fs;
271 scoped_test_env env;
272 const path dir = env.create_dir("dir");
273 const path file = env.create_file("dir/file", 42);
274 const path file_out_of_dir = env.create_file("file1", 101);
275 const path sym = env.create_symlink("dir/file", "sym");
276 const path sym_in_dir = env.create_symlink("dir/file", "dir/sym2");
277
278 const perms old_perms = status(dir).permissions();
279
280 #define CHECK_ACCESS(func, expect) \
281 ec = GetTestEC(); \
282 TEST_CHECK(ent.func(ec) == expect); \
283 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied))
284
285 // test file doesn't exist
286 {
287 directory_entry ent(file);
288
289 TEST_CHECK(!ent.is_symlink());
290 TEST_CHECK(ent.is_regular_file());
291 TEST_CHECK(ent.exists());
292
293 permissions(dir, perms::none);
294 std::error_code ec = GetTestEC();
295 ent.refresh(ec);
296 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
297
298 CHECK_ACCESS(exists, false);
299 CHECK_ACCESS(is_symlink, false);
300 CHECK_ACCESS(last_write_time, file_time_type::min());
301 CHECK_ACCESS(hard_link_count, uintmax_t(-1));
302 }
303 permissions(dir, old_perms);
304 {
305 directory_entry ent(sym_in_dir);
306 TEST_CHECK(ent.is_symlink());
307 TEST_CHECK(ent.is_regular_file());
308 TEST_CHECK(ent.exists());
309
310 permissions(dir, perms::none);
311 std::error_code ec = GetTestEC();
312 ent.refresh(ec);
313 TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
314
315 CHECK_ACCESS(exists, false);
316 CHECK_ACCESS(is_symlink, false);
317 CHECK_ACCESS(last_write_time, file_time_type::min());
318 CHECK_ACCESS(hard_link_count, uintmax_t(-1));
319 }
320 permissions(dir, old_perms);
321 {
322 directory_entry ent(sym);
323 TEST_CHECK(ent.is_symlink());
324 TEST_CHECK(ent.is_regular_file());
325 TEST_CHECK(ent.exists());
326
327 permissions(dir, perms::none);
328 std::error_code ec = GetTestEC();
329 ent.refresh(ec);
330 TEST_CHECK(!ec);
331 TEST_CHECK(ent.is_symlink());
332
333 CHECK_ACCESS(exists, false);
334 CHECK_ACCESS(is_regular_file, false);
335 CHECK_ACCESS(last_write_time, file_time_type::min());
336 CHECK_ACCESS(hard_link_count, uintmax_t(-1));
337 }
338 #undef CHECK_ACCESS
339 }
340
341 TEST_SUITE_END()
342