libstdc++
bits/fs_dir.h
Go to the documentation of this file.
1 // Filesystem directory utilities -*- C++ -*-
2 
3 // Copyright (C) 2014-2021 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 > 201703L
40 # include <compare> // std::strong_ordering
41 #endif
42 
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 
47 namespace filesystem
48 {
49  /** @addtogroup filesystem
50  * @{
51  */
52 
53  /// Information about a file's type and permissions.
55  {
56  public:
57  // constructors and destructor
58  file_status() noexcept : file_status(file_type::none) {}
59 
60  explicit
61  file_status(file_type __ft, perms __prms = perms::unknown) noexcept
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 
79 #if __cpp_lib_three_way_comparison
80  friend bool
81  operator==(const file_status&, const file_status&) noexcept = default;
82 #endif
83 
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;
94 
95  /// The value type used by directory iterators
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
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 
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(); }
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 
260  last_write_time() const
261  { return filesystem::last_write_time(_M_path); }
262 
263 
265  last_write_time(error_code& __ec) const noexcept
266  { return filesystem::last_write_time(_M_path, __ec); }
267 
269  status() const
270  { return filesystem::status(_M_path); }
271 
273  status(error_code& __ec) const noexcept
274  { return filesystem::status(_M_path, __ec); }
275 
277  symlink_status() const
278  { return filesystem::symlink_status(_M_path); }
279 
281  symlink_status(error_code& __ec) const noexcept
282  { return filesystem::symlink_status(_M_path, __ec); }
283 
284  bool
285  operator==(const directory_entry& __rhs) const noexcept
286  { return _M_path == __rhs._M_path; }
287 
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
293  bool
294  operator!=(const directory_entry& __rhs) const noexcept
295  { return _M_path != __rhs._M_path; }
296 
297  bool
298  operator< (const directory_entry& __rhs) const noexcept
299  { return _M_path < __rhs._M_path; }
300 
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; }
312 #endif
313 
314  private:
315  friend struct _Dir;
316  friend class directory_iterator;
317  friend class recursive_directory_iterator;
318 
319  // _GLIBCXX_RESOLVE_LIB_DEFECTS
320  // 3171. LWG 2989 breaks directory_entry stream insertion
321  template<typename _CharT, typename _Traits>
324  const directory_entry& __d)
325  { return __os << __d.path(); }
326 
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)
345  {
346  __ec.clear();
347  return _M_type;
348  }
349  return status(__ec).type();
350  }
351 
352  filesystem::path _M_path;
353  file_type _M_type = file_type::none;
354  };
355 
356  /// Proxy returned by post-increment on directory iterators.
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 
373  /// Iterator type for traversing the entries in a single directory.
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;
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 
392  directory_iterator(const path& __p, error_code& __ec)
393  : directory_iterator(__p, directory_options::none, __ec) { }
394 
395  directory_iterator(const path& __p, directory_options __options,
396  error_code& __ec)
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 
406  operator=(const directory_iterator& __rhs) = default;
407 
409  operator=(directory_iterator&& __rhs) noexcept = default;
410 
411  const directory_entry& operator*() const noexcept;
412  const directory_entry* operator->() const noexcept { return &**this; }
413  directory_iterator& operator++();
414  directory_iterator& increment(error_code& __ec);
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,
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); }
438 
439  friend class recursive_directory_iterator;
440 
441  std::__shared_ptr<_Dir> _M_dir;
442  };
443 
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  */
450  inline directory_iterator
451  begin(directory_iterator __iter) noexcept
452  { return __iter; }
453 
454  /// Return a past-the-end directory_iterator
455  inline directory_iterator
457  { return directory_iterator(); }
458  /// @}
459 
460  /// Iterator type for recursively traversing a directory hierarchy.
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;
469 
470  recursive_directory_iterator() = default;
471 
472  explicit
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 
479  recursive_directory_iterator(const path& __p, directory_options __options,
480  error_code& __ec)
481  : recursive_directory_iterator(__p, __options, &__ec) { }
482 
483  recursive_directory_iterator(const path& __p, error_code& __ec)
484  : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
485 
487  const recursive_directory_iterator&) = default;
488 
490 
492 
493  // observers
494  directory_options options() const noexcept;
495  int depth() const noexcept;
496  bool recursion_pending() const noexcept;
497 
498  const directory_entry& operator*() const noexcept;
499  const directory_entry* operator->() const noexcept { return &**this; }
500 
501  // modifiers
503  operator=(const recursive_directory_iterator& __rhs) noexcept;
505  operator=(recursive_directory_iterator&& __rhs) noexcept;
506 
507  recursive_directory_iterator& operator++();
508  recursive_directory_iterator& increment(error_code& __ec);
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 
520  void disable_recursion_pending() noexcept;
521 
522  private:
523  recursive_directory_iterator(const path&, directory_options, error_code*);
524 
525  friend bool
526  operator==(const recursive_directory_iterator& __lhs,
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); }
537 
538  struct _Dir_stack;
539  std::__shared_ptr<_Dir_stack> _M_dirs;
540  };
541 
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  */
550  { return __iter; }
551 
552  /// Return a past-the-end recursive_directory_iterator
555  { return recursive_directory_iterator(); }
556  /// @}
557 
558 _GLIBCXX_END_NAMESPACE_CXX11
559 
560  /// @} group filesystem
561 } // namespace filesystem
562 
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 
571 _GLIBCXX_END_NAMESPACE_VERSION
572 } // namespace std
573 
574 #endif // C++17
575 
576 #endif // _GLIBCXX_FS_DIR_H
recursive_directory_iterator end(recursive_directory_iterator) noexcept
Return a past-the-end recursive_directory_iterator.
Definition: bits/fs_dir.h:554
directory_iterator end(directory_iterator) noexcept
Return a past-the-end directory_iterator.
Definition: bits/fs_dir.h:456
directory_iterator begin(directory_iterator __iter) noexcept
Enable range-based for using directory_iterator.
Definition: bits/fs_dir.h:451
recursive_directory_iterator begin(recursive_directory_iterator __iter) noexcept
Enable range-based for using recursive_directory_iterator.
Definition: bits/fs_dir.h:549
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:104
ISO C++ entities toplevel namespace is std.
std::basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1540
perms
Bitmask type.
Definition: bits/fs_fwd.h:134
time_point
Definition: chrono:852
Template class basic_ostream.
Definition: ostream:59
Information about a file's type and permissions.
Definition: bits/fs_dir.h:55
The value type used by directory iterators.
Definition: bits/fs_dir.h:97
Proxy returned by post-increment on directory iterators.
Definition: bits/fs_dir.h:358
Iterator type for traversing the entries in a single directory.
Definition: bits/fs_dir.h:375
Iterator type for recursively traversing a directory hierarchy.
Definition: bits/fs_dir.h:462
A filesystem path.
Definition: bits/fs_path.h:246
Marking input iterators.