]>
Commit | Line | Data |
---|---|---|
641cb5a6 JW |
1 | // Filesystem directory utilities -*- C++ -*- |
2 | ||
8d9254fc | 3 | // Copyright (C) 2014-2020 Free Software Foundation, Inc. |
641cb5a6 JW |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file include/bits/fs_dir.h | |
26 | * This is an internal header file, included by other library headers. | |
27 | * Do not attempt to use it directly. @headername{filesystem} | |
28 | */ | |
29 | ||
30 | #ifndef _GLIBCXX_FS_DIR_H | |
31 | #define _GLIBCXX_FS_DIR_H 1 | |
32 | ||
33 | #if __cplusplus >= 201703L | |
34 | # include <typeinfo> | |
35 | # include <ext/concurrence.h> | |
36 | # include <bits/unique_ptr.h> | |
37 | # include <bits/shared_ptr.h> | |
38 | ||
d43919bf JW |
39 | #if __cplusplus > 201703L |
40 | # include <compare> // std::strong_ordering | |
41 | #endif | |
42 | ||
641cb5a6 JW |
43 | namespace std _GLIBCXX_VISIBILITY(default) |
44 | { | |
45 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
46 | ||
47 | namespace filesystem | |
48 | { | |
d727fdc4 JW |
49 | /** @addtogroup filesystem |
50 | * @{ | |
641cb5a6 JW |
51 | */ |
52 | ||
d727fdc4 | 53 | /// Information about a file's type and permissions. |
641cb5a6 JW |
54 | class file_status |
55 | { | |
56 | public: | |
9a3effa4 JW |
57 | // constructors and destructor |
58 | file_status() noexcept : file_status(file_type::none) {} | |
59 | ||
641cb5a6 | 60 | explicit |
9a3effa4 | 61 | file_status(file_type __ft, perms __prms = perms::unknown) noexcept |
641cb5a6 JW |
62 | : _M_type(__ft), _M_perms(__prms) { } |
63 | ||
64 | file_status(const file_status&) noexcept = default; | |
65 | file_status(file_status&&) noexcept = default; | |
66 | ~file_status() = default; | |
67 | ||
68 | file_status& operator=(const file_status&) noexcept = default; | |
69 | file_status& operator=(file_status&&) noexcept = default; | |
70 | ||
71 | // observers | |
72 | file_type type() const noexcept { return _M_type; } | |
73 | perms permissions() const noexcept { return _M_perms; } | |
74 | ||
75 | // modifiers | |
76 | void type(file_type __ft) noexcept { _M_type = __ft; } | |
77 | void permissions(perms __prms) noexcept { _M_perms = __prms; } | |
78 | ||
d43919bf JW |
79 | #if __cpp_lib_three_way_comparison |
80 | friend bool | |
81 | operator==(const file_status&, const file_status&) noexcept = default; | |
82 | #endif | |
83 | ||
641cb5a6 JW |
84 | private: |
85 | file_type _M_type; | |
86 | perms _M_perms; | |
87 | }; | |
88 | ||
89 | _GLIBCXX_BEGIN_NAMESPACE_CXX11 | |
90 | ||
91 | struct _Dir; | |
92 | class directory_iterator; | |
93 | class recursive_directory_iterator; | |
94 | ||
d727fdc4 | 95 | /// The value type used by directory iterators |
641cb5a6 JW |
96 | class directory_entry |
97 | { | |
98 | public: | |
99 | // constructors and destructor | |
100 | directory_entry() noexcept = default; | |
101 | directory_entry(const directory_entry&) = default; | |
102 | directory_entry(directory_entry&&) noexcept = default; | |
103 | ||
104 | explicit | |
105 | directory_entry(const filesystem::path& __p) | |
106 | : _M_path(__p) | |
107 | { refresh(); } | |
108 | ||
109 | directory_entry(const filesystem::path& __p, error_code& __ec) | |
110 | : _M_path(__p) | |
111 | { | |
112 | refresh(__ec); | |
113 | if (__ec) | |
114 | _M_path.clear(); | |
115 | } | |
116 | ||
117 | ~directory_entry() = default; | |
118 | ||
119 | // modifiers | |
120 | directory_entry& operator=(const directory_entry&) = default; | |
121 | directory_entry& operator=(directory_entry&&) noexcept = default; | |
122 | ||
123 | void | |
124 | assign(const filesystem::path& __p) | |
125 | { | |
126 | _M_path = __p; | |
127 | refresh(); | |
128 | } | |
129 | ||
130 | void | |
131 | assign(const filesystem::path& __p, error_code& __ec) | |
132 | { | |
133 | _M_path = __p; | |
134 | refresh(__ec); | |
135 | } | |
136 | ||
137 | void | |
138 | replace_filename(const filesystem::path& __p) | |
139 | { | |
140 | _M_path.replace_filename(__p); | |
141 | refresh(); | |
142 | } | |
143 | ||
144 | void | |
145 | replace_filename(const filesystem::path& __p, error_code& __ec) | |
146 | { | |
147 | _M_path.replace_filename(__p); | |
148 | refresh(__ec); | |
149 | } | |
150 | ||
bf0086f1 JW |
151 | void |
152 | refresh() | |
153 | { _M_type = symlink_status().type(); } | |
154 | ||
155 | void | |
156 | refresh(error_code& __ec) noexcept | |
157 | { _M_type = symlink_status(__ec).type(); } | |
641cb5a6 JW |
158 | |
159 | // observers | |
160 | const filesystem::path& path() const noexcept { return _M_path; } | |
161 | operator const filesystem::path& () const noexcept { return _M_path; } | |
162 | ||
163 | bool | |
164 | exists() const | |
165 | { return filesystem::exists(file_status{_M_file_type()}); } | |
166 | ||
167 | bool | |
168 | exists(error_code& __ec) const noexcept | |
169 | { return filesystem::exists(file_status{_M_file_type(__ec)}); } | |
170 | ||
171 | bool | |
172 | is_block_file() const | |
173 | { return _M_file_type() == file_type::block; } | |
174 | ||
175 | bool | |
176 | is_block_file(error_code& __ec) const noexcept | |
177 | { return _M_file_type(__ec) == file_type::block; } | |
178 | ||
179 | bool | |
180 | is_character_file() const | |
181 | { return _M_file_type() == file_type::character; } | |
182 | ||
183 | bool | |
184 | is_character_file(error_code& __ec) const noexcept | |
185 | { return _M_file_type(__ec) == file_type::character; } | |
186 | ||
187 | bool | |
188 | is_directory() const | |
189 | { return _M_file_type() == file_type::directory; } | |
190 | ||
191 | bool | |
192 | is_directory(error_code& __ec) const noexcept | |
193 | { return _M_file_type(__ec) == file_type::directory; } | |
194 | ||
195 | bool | |
196 | is_fifo() const | |
197 | { return _M_file_type() == file_type::fifo; } | |
198 | ||
199 | bool | |
200 | is_fifo(error_code& __ec) const noexcept | |
201 | { return _M_file_type(__ec) == file_type::fifo; } | |
202 | ||
203 | bool | |
204 | is_other() const | |
205 | { return filesystem::is_other(file_status{_M_file_type()}); } | |
206 | ||
207 | bool | |
208 | is_other(error_code& __ec) const noexcept | |
209 | { return filesystem::is_other(file_status{_M_file_type(__ec)}); } | |
210 | ||
211 | bool | |
212 | is_regular_file() const | |
213 | { return _M_file_type() == file_type::regular; } | |
214 | ||
215 | bool | |
216 | is_regular_file(error_code& __ec) const noexcept | |
217 | { return _M_file_type(__ec) == file_type::regular; } | |
218 | ||
219 | bool | |
220 | is_socket() const | |
221 | { return _M_file_type() == file_type::socket; } | |
222 | ||
223 | bool | |
224 | is_socket(error_code& __ec) const noexcept | |
225 | { return _M_file_type(__ec) == file_type::socket; } | |
226 | ||
227 | bool | |
228 | is_symlink() const | |
229 | { | |
230 | if (_M_type != file_type::none) | |
231 | return _M_type == file_type::symlink; | |
232 | return symlink_status().type() == file_type::symlink; | |
233 | } | |
234 | ||
235 | bool | |
236 | is_symlink(error_code& __ec) const noexcept | |
237 | { | |
238 | if (_M_type != file_type::none) | |
239 | return _M_type == file_type::symlink; | |
240 | return symlink_status(__ec).type() == file_type::symlink; | |
241 | } | |
242 | ||
243 | uintmax_t | |
244 | file_size() const | |
245 | { return filesystem::file_size(_M_path); } | |
246 | ||
247 | uintmax_t | |
248 | file_size(error_code& __ec) const noexcept | |
249 | { return filesystem::file_size(_M_path, __ec); } | |
250 | ||
251 | uintmax_t | |
252 | hard_link_count() const | |
253 | { return filesystem::hard_link_count(_M_path); } | |
254 | ||
255 | uintmax_t | |
256 | hard_link_count(error_code& __ec) const noexcept | |
257 | { return filesystem::hard_link_count(_M_path, __ec); } | |
258 | ||
259 | file_time_type | |
260 | last_write_time() const | |
261 | { return filesystem::last_write_time(_M_path); } | |
262 | ||
263 | ||
264 | file_time_type | |
265 | last_write_time(error_code& __ec) const noexcept | |
266 | { return filesystem::last_write_time(_M_path, __ec); } | |
267 | ||
268 | file_status | |
269 | status() const | |
270 | { return filesystem::status(_M_path); } | |
271 | ||
272 | file_status | |
273 | status(error_code& __ec) const noexcept | |
274 | { return filesystem::status(_M_path, __ec); } | |
275 | ||
276 | file_status | |
277 | symlink_status() const | |
278 | { return filesystem::symlink_status(_M_path); } | |
279 | ||
280 | file_status | |
281 | symlink_status(error_code& __ec) const noexcept | |
282 | { return filesystem::symlink_status(_M_path, __ec); } | |
283 | ||
641cb5a6 JW |
284 | bool |
285 | operator==(const directory_entry& __rhs) const noexcept | |
286 | { return _M_path == __rhs._M_path; } | |
287 | ||
d43919bf JW |
288 | #if __cpp_lib_three_way_comparison |
289 | strong_ordering | |
290 | operator<=>(const directory_entry& __rhs) const noexcept | |
291 | { return _M_path <=> __rhs._M_path; } | |
292 | #else | |
641cb5a6 JW |
293 | bool |
294 | operator!=(const directory_entry& __rhs) const noexcept | |
295 | { return _M_path != __rhs._M_path; } | |
296 | ||
d43919bf JW |
297 | bool |
298 | operator< (const directory_entry& __rhs) const noexcept | |
299 | { return _M_path < __rhs._M_path; } | |
300 | ||
641cb5a6 JW |
301 | bool |
302 | operator<=(const directory_entry& __rhs) const noexcept | |
303 | { return _M_path <= __rhs._M_path; } | |
304 | ||
305 | bool | |
306 | operator> (const directory_entry& __rhs) const noexcept | |
307 | { return _M_path > __rhs._M_path; } | |
308 | ||
309 | bool | |
310 | operator>=(const directory_entry& __rhs) const noexcept | |
311 | { return _M_path >= __rhs._M_path; } | |
d43919bf | 312 | #endif |
641cb5a6 JW |
313 | |
314 | private: | |
0e5abeb0 | 315 | friend struct _Dir; |
641cb5a6 JW |
316 | friend class directory_iterator; |
317 | friend class recursive_directory_iterator; | |
318 | ||
4894e316 JW |
319 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
320 | // 3171. LWG 2989 breaks directory_entry stream insertion | |
321 | template<typename _CharT, typename _Traits> | |
322 | friend basic_ostream<_CharT, _Traits>& | |
323 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
324 | const directory_entry& __d) | |
325 | { return __os << __d.path(); } | |
326 | ||
641cb5a6 JW |
327 | directory_entry(const filesystem::path& __p, file_type __t) |
328 | : _M_path(__p), _M_type(__t) | |
329 | { } | |
330 | ||
331 | // Equivalent to status().type() but uses cached value, if any. | |
332 | file_type | |
333 | _M_file_type() const | |
334 | { | |
335 | if (_M_type != file_type::none && _M_type != file_type::symlink) | |
336 | return _M_type; | |
337 | return status().type(); | |
338 | } | |
339 | ||
340 | // Equivalent to status(__ec).type() but uses cached value, if any. | |
341 | file_type | |
342 | _M_file_type(error_code& __ec) const noexcept | |
343 | { | |
344 | if (_M_type != file_type::none && _M_type != file_type::symlink) | |
d3f3c680 JW |
345 | { |
346 | __ec.clear(); | |
347 | return _M_type; | |
348 | } | |
641cb5a6 JW |
349 | return status(__ec).type(); |
350 | } | |
351 | ||
352 | filesystem::path _M_path; | |
353 | file_type _M_type = file_type::none; | |
354 | }; | |
355 | ||
d727fdc4 | 356 | /// Proxy returned by post-increment on directory iterators. |
641cb5a6 JW |
357 | struct __directory_iterator_proxy |
358 | { | |
359 | const directory_entry& operator*() const& noexcept { return _M_entry; } | |
360 | ||
361 | directory_entry operator*() && noexcept { return std::move(_M_entry); } | |
362 | ||
363 | private: | |
364 | friend class directory_iterator; | |
365 | friend class recursive_directory_iterator; | |
366 | ||
367 | explicit | |
368 | __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { } | |
369 | ||
370 | directory_entry _M_entry; | |
371 | }; | |
372 | ||
d727fdc4 | 373 | /// Iterator type for traversing the entries in a single directory. |
641cb5a6 JW |
374 | class directory_iterator |
375 | { | |
376 | public: | |
377 | typedef directory_entry value_type; | |
378 | typedef ptrdiff_t difference_type; | |
379 | typedef const directory_entry* pointer; | |
380 | typedef const directory_entry& reference; | |
381 | typedef input_iterator_tag iterator_category; | |
382 | ||
383 | directory_iterator() = default; | |
384 | ||
385 | explicit | |
386 | directory_iterator(const path& __p) | |
387 | : directory_iterator(__p, directory_options::none, nullptr) { } | |
388 | ||
389 | directory_iterator(const path& __p, directory_options __options) | |
390 | : directory_iterator(__p, __options, nullptr) { } | |
391 | ||
29453a9f | 392 | directory_iterator(const path& __p, error_code& __ec) |
641cb5a6 JW |
393 | : directory_iterator(__p, directory_options::none, __ec) { } |
394 | ||
29453a9f JW |
395 | directory_iterator(const path& __p, directory_options __options, |
396 | error_code& __ec) | |
641cb5a6 JW |
397 | : directory_iterator(__p, __options, &__ec) { } |
398 | ||
399 | directory_iterator(const directory_iterator& __rhs) = default; | |
400 | ||
401 | directory_iterator(directory_iterator&& __rhs) noexcept = default; | |
402 | ||
403 | ~directory_iterator() = default; | |
404 | ||
405 | directory_iterator& | |
406 | operator=(const directory_iterator& __rhs) = default; | |
407 | ||
408 | directory_iterator& | |
409 | operator=(directory_iterator&& __rhs) noexcept = default; | |
410 | ||
dd4a309e JW |
411 | const directory_entry& operator*() const noexcept; |
412 | const directory_entry* operator->() const noexcept { return &**this; } | |
641cb5a6 | 413 | directory_iterator& operator++(); |
29453a9f | 414 | directory_iterator& increment(error_code& __ec); |
641cb5a6 JW |
415 | |
416 | __directory_iterator_proxy operator++(int) | |
417 | { | |
418 | __directory_iterator_proxy __pr{**this}; | |
419 | ++*this; | |
420 | return __pr; | |
421 | } | |
422 | ||
423 | private: | |
424 | directory_iterator(const path&, directory_options, error_code*); | |
425 | ||
426 | friend bool | |
427 | operator==(const directory_iterator& __lhs, | |
dd4a309e JW |
428 | const directory_iterator& __rhs) noexcept |
429 | { | |
430 | return !__rhs._M_dir.owner_before(__lhs._M_dir) | |
431 | && !__lhs._M_dir.owner_before(__rhs._M_dir); | |
432 | } | |
433 | ||
434 | friend bool | |
435 | operator!=(const directory_iterator& __lhs, | |
436 | const directory_iterator& __rhs) noexcept | |
437 | { return !(__lhs == __rhs); } | |
641cb5a6 JW |
438 | |
439 | friend class recursive_directory_iterator; | |
440 | ||
da29d2a3 | 441 | std::__shared_ptr<_Dir> _M_dir; |
641cb5a6 JW |
442 | }; |
443 | ||
d727fdc4 JW |
444 | /// @relates std::filesystem::directory_iterator @{ |
445 | ||
446 | /** @brief Enable range-based `for` using directory_iterator. | |
447 | * | |
448 | * e.g. `for (auto& entry : std::filesystem::directory_iterator(".")) ...` | |
449 | */ | |
641cb5a6 JW |
450 | inline directory_iterator |
451 | begin(directory_iterator __iter) noexcept | |
452 | { return __iter; } | |
453 | ||
d727fdc4 | 454 | /// Return a past-the-end directory_iterator |
641cb5a6 JW |
455 | inline directory_iterator |
456 | end(directory_iterator) noexcept | |
457 | { return directory_iterator(); } | |
d727fdc4 | 458 | // @} |
641cb5a6 | 459 | |
d727fdc4 | 460 | /// Iterator type for recursively traversing a directory hierarchy. |
641cb5a6 JW |
461 | class recursive_directory_iterator |
462 | { | |
463 | public: | |
464 | typedef directory_entry value_type; | |
465 | typedef ptrdiff_t difference_type; | |
466 | typedef const directory_entry* pointer; | |
467 | typedef const directory_entry& reference; | |
468 | typedef input_iterator_tag iterator_category; | |
469 | ||
470 | recursive_directory_iterator() = default; | |
471 | ||
472 | explicit | |
473 | recursive_directory_iterator(const path& __p) | |
474 | : recursive_directory_iterator(__p, directory_options::none, nullptr) { } | |
475 | ||
476 | recursive_directory_iterator(const path& __p, directory_options __options) | |
477 | : recursive_directory_iterator(__p, __options, nullptr) { } | |
478 | ||
29453a9f JW |
479 | recursive_directory_iterator(const path& __p, directory_options __options, |
480 | error_code& __ec) | |
641cb5a6 JW |
481 | : recursive_directory_iterator(__p, __options, &__ec) { } |
482 | ||
29453a9f | 483 | recursive_directory_iterator(const path& __p, error_code& __ec) |
641cb5a6 JW |
484 | : recursive_directory_iterator(__p, directory_options::none, &__ec) { } |
485 | ||
486 | recursive_directory_iterator( | |
487 | const recursive_directory_iterator&) = default; | |
488 | ||
489 | recursive_directory_iterator(recursive_directory_iterator&&) = default; | |
490 | ||
491 | ~recursive_directory_iterator(); | |
492 | ||
493 | // observers | |
c7dde4a9 JW |
494 | directory_options options() const noexcept; |
495 | int depth() const noexcept; | |
496 | bool recursion_pending() const noexcept; | |
641cb5a6 | 497 | |
c7dde4a9 JW |
498 | const directory_entry& operator*() const noexcept; |
499 | const directory_entry* operator->() const noexcept { return &**this; } | |
641cb5a6 JW |
500 | |
501 | // modifiers | |
502 | recursive_directory_iterator& | |
503 | operator=(const recursive_directory_iterator& __rhs) noexcept; | |
504 | recursive_directory_iterator& | |
505 | operator=(recursive_directory_iterator&& __rhs) noexcept; | |
506 | ||
507 | recursive_directory_iterator& operator++(); | |
29453a9f | 508 | recursive_directory_iterator& increment(error_code& __ec); |
641cb5a6 JW |
509 | |
510 | __directory_iterator_proxy operator++(int) | |
511 | { | |
512 | __directory_iterator_proxy __pr{**this}; | |
513 | ++*this; | |
514 | return __pr; | |
515 | } | |
516 | ||
517 | void pop(); | |
518 | void pop(error_code&); | |
519 | ||
c7dde4a9 | 520 | void disable_recursion_pending() noexcept; |
641cb5a6 JW |
521 | |
522 | private: | |
523 | recursive_directory_iterator(const path&, directory_options, error_code*); | |
524 | ||
525 | friend bool | |
526 | operator==(const recursive_directory_iterator& __lhs, | |
dd4a309e JW |
527 | const recursive_directory_iterator& __rhs) noexcept |
528 | { | |
529 | return !__rhs._M_dirs.owner_before(__lhs._M_dirs) | |
530 | && !__lhs._M_dirs.owner_before(__rhs._M_dirs); | |
531 | } | |
532 | ||
533 | friend bool | |
534 | operator!=(const recursive_directory_iterator& __lhs, | |
535 | const recursive_directory_iterator& __rhs) noexcept | |
536 | { return !(__lhs == __rhs); } | |
641cb5a6 JW |
537 | |
538 | struct _Dir_stack; | |
da29d2a3 | 539 | std::__shared_ptr<_Dir_stack> _M_dirs; |
641cb5a6 JW |
540 | }; |
541 | ||
d727fdc4 JW |
542 | /// @relates std::filesystem::recursive_directory_iterator @{ |
543 | ||
544 | /** @brief Enable range-based `for` using recursive_directory_iterator. | |
545 | * | |
546 | * e.g. `for (auto& entry : recursive_directory_iterator(".")) ...` | |
547 | */ | |
641cb5a6 JW |
548 | inline recursive_directory_iterator |
549 | begin(recursive_directory_iterator __iter) noexcept | |
550 | { return __iter; } | |
551 | ||
d727fdc4 | 552 | /// Return a past-the-end recursive_directory_iterator |
641cb5a6 JW |
553 | inline recursive_directory_iterator |
554 | end(recursive_directory_iterator) noexcept | |
555 | { return recursive_directory_iterator(); } | |
d727fdc4 | 556 | // @} |
641cb5a6 | 557 | |
641cb5a6 JW |
558 | _GLIBCXX_END_NAMESPACE_CXX11 |
559 | ||
560 | // @} group filesystem | |
561 | } // namespace filesystem | |
562 | ||
da29d2a3 JW |
563 | // Use explicit instantiations of these types. Any inconsistency in the |
564 | // value of __default_lock_policy between code including this header and | |
565 | // the library will cause a linker error. | |
566 | extern template class | |
567 | __shared_ptr<filesystem::_Dir>; | |
568 | extern template class | |
569 | __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>; | |
570 | ||
641cb5a6 JW |
571 | _GLIBCXX_END_NAMESPACE_VERSION |
572 | } // namespace std | |
573 | ||
574 | #endif // C++17 | |
575 | ||
576 | #endif // _GLIBCXX_FS_DIR_H |