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