1 | // Filesystem directory utilities -*- C++ -*-  |
2 |   |
3 | // Copyright (C) 2014-2019 Free Software Foundation, Inc.  |
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 |   |
39 | namespace std _GLIBCXX_VISIBILITY(default)  |
40 | {  |
41 | _GLIBCXX_BEGIN_NAMESPACE_VERSION  |
42 |   |
43 | namespace filesystem  |
44 | {  |
45 | /**  |
46 | * @ingroup filesystem  |
47 | * @{  |
48 | */  |
49 |   |
50 | class file_status  |
51 | {  |
52 | public:  |
53 | // constructors and destructor  |
54 | file_status() noexcept : file_status(file_type::none) {}  |
55 |   |
56 | explicit  |
57 | file_status(file_type __ft, perms __prms = perms::unknown) noexcept  |
58 | : _M_type(__ft), _M_perms(__prms) { }  |
59 |   |
60 | file_status(const file_status&) noexcept = default;  |
61 | file_status(file_status&&) noexcept = default;  |
62 | ~file_status() = default;  |
63 |   |
64 | file_status& operator=(const file_status&) noexcept = default;  |
65 | file_status& operator=(file_status&&) noexcept = default;  |
66 |   |
67 | // observers  |
68 | file_type type() const noexcept { return _M_type; }  |
69 | perms permissions() const noexcept { return _M_perms; }  |
70 |   |
71 | // modifiers  |
72 | void type(file_type __ft) noexcept { _M_type = __ft; }  |
73 | void permissions(perms __prms) noexcept { _M_perms = __prms; }  |
74 |   |
75 | private:  |
76 | file_type _M_type;  |
77 | perms _M_perms;  |
78 | };  |
79 |   |
80 | _GLIBCXX_BEGIN_NAMESPACE_CXX11  |
81 |   |
82 | struct _Dir;  |
83 | class directory_iterator;  |
84 | class recursive_directory_iterator;  |
85 |   |
86 | class directory_entry  |
87 | {  |
88 | public:  |
89 | // constructors and destructor  |
90 | directory_entry() noexcept = default;  |
91 | directory_entry(const directory_entry&) = default;  |
92 | directory_entry(directory_entry&&) noexcept = default;  |
93 |   |
94 | explicit  |
95 | directory_entry(const filesystem::path& __p)  |
96 | : _M_path(__p)  |
97 | { refresh(); }  |
98 |   |
99 | directory_entry(const filesystem::path& __p, error_code& __ec)  |
100 | : _M_path(__p)  |
101 | {  |
102 | refresh(__ec);  |
103 | if (__ec)  |
104 | _M_path.clear();  |
105 | }  |
106 |   |
107 | ~directory_entry() = default;  |
108 |   |
109 | // modifiers  |
110 | directory_entry& operator=(const directory_entry&) = default;  |
111 | directory_entry& operator=(directory_entry&&) noexcept = default;  |
112 |   |
113 | void  |
114 | assign(const filesystem::path& __p)  |
115 | {  |
116 | _M_path = __p;  |
117 | refresh();  |
118 | }  |
119 |   |
120 | void  |
121 | assign(const filesystem::path& __p, error_code& __ec)  |
122 | {  |
123 | _M_path = __p;  |
124 | refresh(__ec);  |
125 | }  |
126 |   |
127 | void  |
128 | replace_filename(const filesystem::path& __p)  |
129 | {  |
130 | _M_path.replace_filename(__p);  |
131 | refresh();  |
132 | }  |
133 |   |
134 | void  |
135 | replace_filename(const filesystem::path& __p, error_code& __ec)  |
136 | {  |
137 | _M_path.replace_filename(__p);  |
138 | refresh(__ec);  |
139 | }  |
140 |   |
141 | void  |
142 | refresh()  |
143 | { _M_type = symlink_status().type(); }  |
144 |   |
145 | void  |
146 | refresh(error_code& __ec) noexcept  |
147 | { _M_type = symlink_status(__ec).type(); }  |
148 |   |
149 | // observers  |
150 | const filesystem::path& path() const noexcept { return _M_path; }  |
151 | operator const filesystem::path& () const noexcept { return _M_path; }  |
152 |   |
153 | bool  |
154 | exists() const  |
155 | { return filesystem::exists(file_status{_M_file_type()}); }  |
156 |   |
157 | bool  |
158 | exists(error_code& __ec) const noexcept  |
159 | { return filesystem::exists(file_status{_M_file_type(__ec)}); }  |
160 |   |
161 | bool  |
162 | is_block_file() const  |
163 | { return _M_file_type() == file_type::block; }  |
164 |   |
165 | bool  |
166 | is_block_file(error_code& __ec) const noexcept  |
167 | { return _M_file_type(__ec) == file_type::block; }  |
168 |   |
169 | bool  |
170 | is_character_file() const  |
171 | { return _M_file_type() == file_type::character; }  |
172 |   |
173 | bool  |
174 | is_character_file(error_code& __ec) const noexcept  |
175 | { return _M_file_type(__ec) == file_type::character; }  |
176 |   |
177 | bool  |
178 | is_directory() const  |
179 | { return _M_file_type() == file_type::directory; }  |
180 |   |
181 | bool  |
182 | is_directory(error_code& __ec) const noexcept  |
183 | { return _M_file_type(__ec) == file_type::directory; }  |
184 |   |
185 | bool  |
186 | is_fifo() const  |
187 | { return _M_file_type() == file_type::fifo; }  |
188 |   |
189 | bool  |
190 | is_fifo(error_code& __ec) const noexcept  |
191 | { return _M_file_type(__ec) == file_type::fifo; }  |
192 |   |
193 | bool  |
194 | is_other() const  |
195 | { return filesystem::is_other(file_status{_M_file_type()}); }  |
196 |   |
197 | bool  |
198 | is_other(error_code& __ec) const noexcept  |
199 | { return filesystem::is_other(file_status{_M_file_type(__ec)}); }  |
200 |   |
201 | bool  |
202 | is_regular_file() const  |
203 | { return _M_file_type() == file_type::regular; }  |
204 |   |
205 | bool  |
206 | is_regular_file(error_code& __ec) const noexcept  |
207 | { return _M_file_type(__ec) == file_type::regular; }  |
208 |   |
209 | bool  |
210 | is_socket() const  |
211 | { return _M_file_type() == file_type::socket; }  |
212 |   |
213 | bool  |
214 | is_socket(error_code& __ec) const noexcept  |
215 | { return _M_file_type(__ec) == file_type::socket; }  |
216 |   |
217 | bool  |
218 | is_symlink() const  |
219 | {  |
220 | if (_M_type != file_type::none)  |
221 | return _M_type == file_type::symlink;  |
222 | return symlink_status().type() == file_type::symlink;  |
223 | }  |
224 |   |
225 | bool  |
226 | is_symlink(error_code& __ec) const noexcept  |
227 | {  |
228 | if (_M_type != file_type::none)  |
229 | return _M_type == file_type::symlink;  |
230 | return symlink_status(__ec).type() == file_type::symlink;  |
231 | }  |
232 |   |
233 | uintmax_t  |
234 | file_size() const  |
235 | { return filesystem::file_size(_M_path); }  |
236 |   |
237 | uintmax_t  |
238 | file_size(error_code& __ec) const noexcept  |
239 | { return filesystem::file_size(_M_path, __ec); }  |
240 |   |
241 | uintmax_t  |
242 | hard_link_count() const  |
243 | { return filesystem::hard_link_count(_M_path); }  |
244 |   |
245 | uintmax_t  |
246 | hard_link_count(error_code& __ec) const noexcept  |
247 | { return filesystem::hard_link_count(_M_path, __ec); }  |
248 |   |
249 | file_time_type  |
250 | last_write_time() const  |
251 | { return filesystem::last_write_time(_M_path); }  |
252 |   |
253 |   |
254 | file_time_type  |
255 | last_write_time(error_code& __ec) const noexcept  |
256 | { return filesystem::last_write_time(_M_path, __ec); }  |
257 |   |
258 | file_status  |
259 | status() const  |
260 | { return filesystem::status(_M_path); }  |
261 |   |
262 | file_status  |
263 | status(error_code& __ec) const noexcept  |
264 | { return filesystem::status(_M_path, __ec); }  |
265 |   |
266 | file_status  |
267 | symlink_status() const  |
268 | { return filesystem::symlink_status(_M_path); }  |
269 |   |
270 | file_status  |
271 | symlink_status(error_code& __ec) const noexcept  |
272 | { return filesystem::symlink_status(_M_path, __ec); }  |
273 |   |
274 | bool  |
275 | operator< (const directory_entry& __rhs) const noexcept  |
276 | { return _M_path < __rhs._M_path; }  |
277 |   |
278 | bool  |
279 | operator==(const directory_entry& __rhs) const noexcept  |
280 | { return _M_path == __rhs._M_path; }  |
281 |   |
282 | bool  |
283 | operator!=(const directory_entry& __rhs) const noexcept  |
284 | { return _M_path != __rhs._M_path; }  |
285 |   |
286 | bool  |
287 | operator<=(const directory_entry& __rhs) const noexcept  |
288 | { return _M_path <= __rhs._M_path; }  |
289 |   |
290 | bool  |
291 | operator> (const directory_entry& __rhs) const noexcept  |
292 | { return _M_path > __rhs._M_path; }  |
293 |   |
294 | bool  |
295 | operator>=(const directory_entry& __rhs) const noexcept  |
296 | { return _M_path >= __rhs._M_path; }  |
297 |   |
298 | private:  |
299 | friend class _Dir;  |
300 | friend class directory_iterator;  |
301 | friend class recursive_directory_iterator;  |
302 |   |
303 | // _GLIBCXX_RESOLVE_LIB_DEFECTS  |
304 | // 3171. LWG 2989 breaks directory_entry stream insertion  |
305 | template<typename _CharT, typename _Traits>  |
306 | friend basic_ostream<_CharT, _Traits>&  |
307 | operator<<(basic_ostream<_CharT, _Traits>& __os,  |
308 | const directory_entry& __d)  |
309 | { return __os << __d.path(); }  |
310 |   |
311 | directory_entry(const filesystem::path& __p, file_type __t)  |
312 | : _M_path(__p), _M_type(__t)  |
313 | { }  |
314 |   |
315 | // Equivalent to status().type() but uses cached value, if any.  |
316 | file_type  |
317 | _M_file_type() const  |
318 | {  |
319 | if (_M_type != file_type::none && _M_type != file_type::symlink)  |
320 | return _M_type;  |
321 | return status().type();  |
322 | }  |
323 |   |
324 | // Equivalent to status(__ec).type() but uses cached value, if any.  |
325 | file_type  |
326 | _M_file_type(error_code& __ec) const noexcept  |
327 | {  |
328 | if (_M_type != file_type::none && _M_type != file_type::symlink)  |
329 | {  |
330 | __ec.clear();  |
331 | return _M_type;  |
332 | }  |
333 | return status(__ec).type();  |
334 | }  |
335 |   |
336 | filesystem::path _M_path;  |
337 | file_type _M_type = file_type::none;  |
338 | };  |
339 |   |
340 | struct __directory_iterator_proxy  |
341 | {  |
342 | const directory_entry& operator*() const& noexcept { return _M_entry; }  |
343 |   |
344 | directory_entry operator*() && noexcept { return std::move(_M_entry); }  |
345 |   |
346 | private:  |
347 | friend class directory_iterator;  |
348 | friend class recursive_directory_iterator;  |
349 |   |
350 | explicit  |
351 | __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }  |
352 |   |
353 | directory_entry _M_entry;  |
354 | };  |
355 |   |
356 | class directory_iterator  |
357 | {  |
358 | public:  |
359 | typedef directory_entry value_type;  |
360 | typedef ptrdiff_t difference_type;  |
361 | typedef const directory_entry* pointer;  |
362 | typedef const directory_entry& reference;  |
363 | typedef input_iterator_tag iterator_category;  |
364 |   |
365 | directory_iterator() = default;  |
366 |   |
367 | explicit  |
368 | directory_iterator(const path& __p)  |
369 | : directory_iterator(__p, directory_options::none, nullptr) { }  |
370 |   |
371 | directory_iterator(const path& __p, directory_options __options)  |
372 | : directory_iterator(__p, __options, nullptr) { }  |
373 |   |
374 | directory_iterator(const path& __p, error_code& __ec)  |
375 | : directory_iterator(__p, directory_options::none, __ec) { }  |
376 |   |
377 | directory_iterator(const path& __p, directory_options __options,  |
378 | error_code& __ec)  |
379 | : directory_iterator(__p, __options, &__ec) { }  |
380 |   |
381 | directory_iterator(const directory_iterator& __rhs) = default;  |
382 |   |
383 | directory_iterator(directory_iterator&& __rhs) noexcept = default;  |
384 |   |
385 | ~directory_iterator() = default;  |
386 |   |
387 | directory_iterator&  |
388 | operator=(const directory_iterator& __rhs) = default;  |
389 |   |
390 | directory_iterator&  |
391 | operator=(directory_iterator&& __rhs) noexcept = default;  |
392 |   |
393 | const directory_entry& operator*() const noexcept;  |
394 | const directory_entry* operator->() const noexcept { return &**this; }  |
395 | directory_iterator& operator++();  |
396 | directory_iterator& increment(error_code& __ec);  |
397 |   |
398 | __directory_iterator_proxy operator++(int)  |
399 | {  |
400 | __directory_iterator_proxy __pr{**this};  |
401 | ++*this;  |
402 | return __pr;  |
403 | }  |
404 |   |
405 | private:  |
406 | directory_iterator(const path&, directory_options, error_code*);  |
407 |   |
408 | friend bool  |
409 | operator==(const directory_iterator& __lhs,  |
410 | const directory_iterator& __rhs) noexcept  |
411 | {  |
412 | return !__rhs._M_dir.owner_before(__lhs._M_dir)  |
413 | && !__lhs._M_dir.owner_before(__rhs._M_dir);  |
414 | }  |
415 |   |
416 | friend bool  |
417 | operator!=(const directory_iterator& __lhs,  |
418 | const directory_iterator& __rhs) noexcept  |
419 | { return !(__lhs == __rhs); }  |
420 |   |
421 | friend class recursive_directory_iterator;  |
422 |   |
423 | std::__shared_ptr<_Dir> _M_dir;  |
424 | };  |
425 |   |
426 | inline directory_iterator  |
427 | begin(directory_iterator __iter) noexcept  |
428 | { return __iter; }  |
429 |   |
430 | inline directory_iterator  |
431 | end(directory_iterator) noexcept  |
432 | { return directory_iterator(); }  |
433 |   |
434 | class recursive_directory_iterator  |
435 | {  |
436 | public:  |
437 | typedef directory_entry value_type;  |
438 | typedef ptrdiff_t difference_type;  |
439 | typedef const directory_entry* pointer;  |
440 | typedef const directory_entry& reference;  |
441 | typedef input_iterator_tag iterator_category;  |
442 |   |
443 | recursive_directory_iterator() = default;  |
444 |   |
445 | explicit  |
446 | recursive_directory_iterator(const path& __p)  |
447 | : recursive_directory_iterator(__p, directory_options::none, nullptr) { }  |
448 |   |
449 | recursive_directory_iterator(const path& __p, directory_options __options)  |
450 | : recursive_directory_iterator(__p, __options, nullptr) { }  |
451 |   |
452 | recursive_directory_iterator(const path& __p, directory_options __options,  |
453 | error_code& __ec)  |
454 | : recursive_directory_iterator(__p, __options, &__ec) { }  |
455 |   |
456 | recursive_directory_iterator(const path& __p, error_code& __ec)  |
457 | : recursive_directory_iterator(__p, directory_options::none, &__ec) { }  |
458 |   |
459 | recursive_directory_iterator(  |
460 | const recursive_directory_iterator&) = default;  |
461 |   |
462 | recursive_directory_iterator(recursive_directory_iterator&&) = default;  |
463 |   |
464 | ~recursive_directory_iterator();  |
465 |   |
466 | // observers  |
467 | directory_options options() const noexcept;  |
468 | int depth() const noexcept;  |
469 | bool recursion_pending() const noexcept;  |
470 |   |
471 | const directory_entry& operator*() const noexcept;  |
472 | const directory_entry* operator->() const noexcept { return &**this; }  |
473 |   |
474 | // modifiers  |
475 | recursive_directory_iterator&  |
476 | operator=(const recursive_directory_iterator& __rhs) noexcept;  |
477 | recursive_directory_iterator&  |
478 | operator=(recursive_directory_iterator&& __rhs) noexcept;  |
479 |   |
480 | recursive_directory_iterator& operator++();  |
481 | recursive_directory_iterator& increment(error_code& __ec);  |
482 |   |
483 | __directory_iterator_proxy operator++(int)  |
484 | {  |
485 | __directory_iterator_proxy __pr{**this};  |
486 | ++*this;  |
487 | return __pr;  |
488 | }  |
489 |   |
490 | void pop();  |
491 | void pop(error_code&);  |
492 |   |
493 | void disable_recursion_pending() noexcept;  |
494 |   |
495 | private:  |
496 | recursive_directory_iterator(const path&, directory_options, error_code*);  |
497 |   |
498 | friend bool  |
499 | operator==(const recursive_directory_iterator& __lhs,  |
500 | const recursive_directory_iterator& __rhs) noexcept  |
501 | {  |
502 | return !__rhs._M_dirs.owner_before(__lhs._M_dirs)  |
503 | && !__lhs._M_dirs.owner_before(__rhs._M_dirs);  |
504 | }  |
505 |   |
506 | friend bool  |
507 | operator!=(const recursive_directory_iterator& __lhs,  |
508 | const recursive_directory_iterator& __rhs) noexcept  |
509 | { return !(__lhs == __rhs); }  |
510 |   |
511 | struct _Dir_stack;  |
512 | std::__shared_ptr<_Dir_stack> _M_dirs;  |
513 | };  |
514 |   |
515 | inline recursive_directory_iterator  |
516 | begin(recursive_directory_iterator __iter) noexcept  |
517 | { return __iter; }  |
518 |   |
519 | inline recursive_directory_iterator  |
520 | end(recursive_directory_iterator) noexcept  |
521 | { return recursive_directory_iterator(); }  |
522 |   |
523 | _GLIBCXX_END_NAMESPACE_CXX11  |
524 |   |
525 | // @} group filesystem  |
526 | } // namespace filesystem  |
527 |   |
528 | // Use explicit instantiations of these types. Any inconsistency in the  |
529 | // value of __default_lock_policy between code including this header and  |
530 | // the library will cause a linker error.  |
531 | extern template class  |
532 | __shared_ptr<filesystem::_Dir>;  |
533 | extern template class  |
534 | __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>;  |
535 |   |
536 | _GLIBCXX_END_NAMESPACE_VERSION  |
537 | } // namespace std  |
538 |   |
539 | #endif // C++17  |
540 |   |
541 | #endif // _GLIBCXX_FS_DIR_H  |
542 | |