• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
11 #define _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
12 
13 #include <__availability>
14 #include <__chrono/time_point.h>
15 #include <__compare/ordering.h>
16 #include <__config>
17 #include <__filesystem/file_status.h>
18 #include <__filesystem/file_time_type.h>
19 #include <__filesystem/file_type.h>
20 #include <__filesystem/filesystem_error.h>
21 #include <__filesystem/operations.h>
22 #include <__filesystem/path.h>
23 #include <__filesystem/perms.h>
24 #include <__system_error/errc.h>
25 #include <__system_error/error_code.h>
26 #include <__utility/move.h>
27 #include <__utility/unreachable.h>
28 #include <cstdint>
29 #include <iosfwd>
30 
31 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
32 #  pragma GCC system_header
33 #endif
34 
35 _LIBCPP_PUSH_MACROS
36 #include <__undef_macros>
37 
38 #ifndef _LIBCPP_CXX03_LANG
39 
40 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
41 
42 _LIBCPP_AVAILABILITY_FILESYSTEM_PUSH
43 
44 
45 class directory_entry {
46   typedef _VSTD_FS::path _Path;
47 
48 public:
49   // constructors and destructors
50   _LIBCPP_HIDE_FROM_ABI directory_entry() noexcept = default;
51   _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry const&) = default;
52   _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry&&) noexcept = default;
53 
54   _LIBCPP_INLINE_VISIBILITY
directory_entry(_Path const & __p)55   explicit directory_entry(_Path const& __p) : __p_(__p) {
56     error_code __ec;
57     __refresh(&__ec);
58   }
59 
60   _LIBCPP_INLINE_VISIBILITY
directory_entry(_Path const & __p,error_code & __ec)61   directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) {
62     __refresh(&__ec);
63   }
64 
~directory_entry()65   _LIBCPP_HIDE_FROM_ABI ~directory_entry() {}
66 
67   _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry const&) = default;
68   _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry&&) noexcept = default;
69 
70   _LIBCPP_INLINE_VISIBILITY
assign(_Path const & __p)71   void assign(_Path const& __p) {
72     __p_ = __p;
73     error_code __ec;
74     __refresh(&__ec);
75   }
76 
77   _LIBCPP_INLINE_VISIBILITY
assign(_Path const & __p,error_code & __ec)78   void assign(_Path const& __p, error_code& __ec) {
79     __p_ = __p;
80     __refresh(&__ec);
81   }
82 
83   _LIBCPP_INLINE_VISIBILITY
replace_filename(_Path const & __p)84   void replace_filename(_Path const& __p) {
85     __p_.replace_filename(__p);
86     error_code __ec;
87     __refresh(&__ec);
88   }
89 
90   _LIBCPP_INLINE_VISIBILITY
replace_filename(_Path const & __p,error_code & __ec)91   void replace_filename(_Path const& __p, error_code& __ec) {
92     __p_ = __p_.parent_path() / __p;
93     __refresh(&__ec);
94   }
95 
96   _LIBCPP_INLINE_VISIBILITY
refresh()97   void refresh() { __refresh(); }
98 
99   _LIBCPP_INLINE_VISIBILITY
refresh(error_code & __ec)100   void refresh(error_code& __ec) noexcept { __refresh(&__ec); }
101 
102   _LIBCPP_INLINE_VISIBILITY
path()103   _Path const& path() const noexcept { return __p_; }
104 
105   _LIBCPP_INLINE_VISIBILITY
106   operator const _Path&() const noexcept { return __p_; }
107 
108   _LIBCPP_INLINE_VISIBILITY
exists()109   bool exists() const { return _VSTD_FS::exists(file_status{__get_ft()}); }
110 
111   _LIBCPP_INLINE_VISIBILITY
exists(error_code & __ec)112   bool exists(error_code& __ec) const noexcept {
113     return _VSTD_FS::exists(file_status{__get_ft(&__ec)});
114   }
115 
116   _LIBCPP_INLINE_VISIBILITY
is_block_file()117   bool is_block_file() const { return __get_ft() == file_type::block; }
118 
119   _LIBCPP_INLINE_VISIBILITY
is_block_file(error_code & __ec)120   bool is_block_file(error_code& __ec) const noexcept {
121     return __get_ft(&__ec) == file_type::block;
122   }
123 
124   _LIBCPP_INLINE_VISIBILITY
is_character_file()125   bool is_character_file() const { return __get_ft() == file_type::character; }
126 
127   _LIBCPP_INLINE_VISIBILITY
is_character_file(error_code & __ec)128   bool is_character_file(error_code& __ec) const noexcept {
129     return __get_ft(&__ec) == file_type::character;
130   }
131 
132   _LIBCPP_INLINE_VISIBILITY
is_directory()133   bool is_directory() const { return __get_ft() == file_type::directory; }
134 
135   _LIBCPP_INLINE_VISIBILITY
is_directory(error_code & __ec)136   bool is_directory(error_code& __ec) const noexcept {
137     return __get_ft(&__ec) == file_type::directory;
138   }
139 
140   _LIBCPP_INLINE_VISIBILITY
is_fifo()141   bool is_fifo() const { return __get_ft() == file_type::fifo; }
142 
143   _LIBCPP_INLINE_VISIBILITY
is_fifo(error_code & __ec)144   bool is_fifo(error_code& __ec) const noexcept {
145     return __get_ft(&__ec) == file_type::fifo;
146   }
147 
148   _LIBCPP_INLINE_VISIBILITY
is_other()149   bool is_other() const { return _VSTD_FS::is_other(file_status{__get_ft()}); }
150 
151   _LIBCPP_INLINE_VISIBILITY
is_other(error_code & __ec)152   bool is_other(error_code& __ec) const noexcept {
153     return _VSTD_FS::is_other(file_status{__get_ft(&__ec)});
154   }
155 
156   _LIBCPP_INLINE_VISIBILITY
is_regular_file()157   bool is_regular_file() const { return __get_ft() == file_type::regular; }
158 
159   _LIBCPP_INLINE_VISIBILITY
is_regular_file(error_code & __ec)160   bool is_regular_file(error_code& __ec) const noexcept {
161     return __get_ft(&__ec) == file_type::regular;
162   }
163 
164   _LIBCPP_INLINE_VISIBILITY
is_socket()165   bool is_socket() const { return __get_ft() == file_type::socket; }
166 
167   _LIBCPP_INLINE_VISIBILITY
is_socket(error_code & __ec)168   bool is_socket(error_code& __ec) const noexcept {
169     return __get_ft(&__ec) == file_type::socket;
170   }
171 
172   _LIBCPP_INLINE_VISIBILITY
is_symlink()173   bool is_symlink() const { return __get_sym_ft() == file_type::symlink; }
174 
175   _LIBCPP_INLINE_VISIBILITY
is_symlink(error_code & __ec)176   bool is_symlink(error_code& __ec) const noexcept {
177     return __get_sym_ft(&__ec) == file_type::symlink;
178   }
179   _LIBCPP_INLINE_VISIBILITY
file_size()180   uintmax_t file_size() const { return __get_size(); }
181 
182   _LIBCPP_INLINE_VISIBILITY
file_size(error_code & __ec)183   uintmax_t file_size(error_code& __ec) const noexcept {
184     return __get_size(&__ec);
185   }
186 
187   _LIBCPP_INLINE_VISIBILITY
hard_link_count()188   uintmax_t hard_link_count() const { return __get_nlink(); }
189 
190   _LIBCPP_INLINE_VISIBILITY
hard_link_count(error_code & __ec)191   uintmax_t hard_link_count(error_code& __ec) const noexcept {
192     return __get_nlink(&__ec);
193   }
194 
195   _LIBCPP_INLINE_VISIBILITY
last_write_time()196   file_time_type last_write_time() const { return __get_write_time(); }
197 
198   _LIBCPP_INLINE_VISIBILITY
last_write_time(error_code & __ec)199   file_time_type last_write_time(error_code& __ec) const noexcept {
200     return __get_write_time(&__ec);
201   }
202 
203   _LIBCPP_INLINE_VISIBILITY
status()204   file_status status() const { return __get_status(); }
205 
206   _LIBCPP_INLINE_VISIBILITY
status(error_code & __ec)207   file_status status(error_code& __ec) const noexcept {
208     return __get_status(&__ec);
209   }
210 
211   _LIBCPP_INLINE_VISIBILITY
symlink_status()212   file_status symlink_status() const { return __get_symlink_status(); }
213 
214   _LIBCPP_INLINE_VISIBILITY
symlink_status(error_code & __ec)215   file_status symlink_status(error_code& __ec) const noexcept {
216     return __get_symlink_status(&__ec);
217   }
218 
219 
220   _LIBCPP_INLINE_VISIBILITY
221   bool operator==(directory_entry const& __rhs) const noexcept {
222     return __p_ == __rhs.__p_;
223   }
224 
225 #if _LIBCPP_STD_VER <= 17
226   _LIBCPP_INLINE_VISIBILITY
227   bool operator!=(directory_entry const& __rhs) const noexcept {
228     return __p_ != __rhs.__p_;
229   }
230 
231   _LIBCPP_INLINE_VISIBILITY
232   bool operator<(directory_entry const& __rhs) const noexcept {
233     return __p_ < __rhs.__p_;
234   }
235 
236   _LIBCPP_INLINE_VISIBILITY
237   bool operator<=(directory_entry const& __rhs) const noexcept {
238     return __p_ <= __rhs.__p_;
239   }
240 
241   _LIBCPP_INLINE_VISIBILITY
242   bool operator>(directory_entry const& __rhs) const noexcept {
243     return __p_ > __rhs.__p_;
244   }
245 
246   _LIBCPP_INLINE_VISIBILITY
247   bool operator>=(directory_entry const& __rhs) const noexcept {
248     return __p_ >= __rhs.__p_;
249   }
250 
251 #else // _LIBCPP_STD_VER <= 17
252 
253   _LIBCPP_HIDE_FROM_ABI
254   strong_ordering operator<=>(const directory_entry& __rhs) const noexcept {
255     return __p_ <=> __rhs.__p_;
256   }
257 
258 #endif // _LIBCPP_STD_VER <= 17
259 
260   template <class _CharT, class _Traits>
261   _LIBCPP_INLINE_VISIBILITY
262   friend basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) {
263     return __os << __d.path();
264   }
265 
266 private:
267   friend class directory_iterator;
268   friend class recursive_directory_iterator;
269   friend class _LIBCPP_HIDDEN __dir_stream;
270 
271   enum _CacheType : unsigned char {
272     _Empty,
273     _IterSymlink,
274     _IterNonSymlink,
275     _RefreshSymlink,
276     _RefreshSymlinkUnresolved,
277     _RefreshNonSymlink
278   };
279 
280   struct __cached_data {
281     uintmax_t __size_;
282     uintmax_t __nlink_;
283     file_time_type __write_time_;
284     perms __sym_perms_;
285     perms __non_sym_perms_;
286     file_type __type_;
287     _CacheType __cache_type_;
288 
289     _LIBCPP_INLINE_VISIBILITY
__cached_data__cached_data290     __cached_data() noexcept { __reset(); }
291 
292     _LIBCPP_INLINE_VISIBILITY
__reset__cached_data293     void __reset() {
294       __cache_type_ = _Empty;
295       __type_ = file_type::none;
296       __sym_perms_ = __non_sym_perms_ = perms::unknown;
297       __size_ = __nlink_ = uintmax_t(-1);
298       __write_time_ = file_time_type::min();
299     }
300   };
301 
302   _LIBCPP_INLINE_VISIBILITY
__create_iter_result(file_type __ft)303   static __cached_data __create_iter_result(file_type __ft) {
304     __cached_data __data;
305     __data.__type_ = __ft;
306     __data.__cache_type_ = [&]() {
307       switch (__ft) {
308       case file_type::none:
309         return _Empty;
310       case file_type::symlink:
311         return _IterSymlink;
312       default:
313         return _IterNonSymlink;
314       }
315     }();
316     return __data;
317   }
318 
319   _LIBCPP_INLINE_VISIBILITY
__assign_iter_entry(_Path && __p,__cached_data __dt)320   void __assign_iter_entry(_Path&& __p, __cached_data __dt) {
321     __p_ = _VSTD::move(__p);
322     __data_ = __dt;
323   }
324 
325   _LIBCPP_FUNC_VIS
326   error_code __do_refresh() noexcept;
327 
328   _LIBCPP_INLINE_VISIBILITY
__is_dne_error(error_code const & __ec)329   static bool __is_dne_error(error_code const& __ec) {
330     if (!__ec)
331       return true;
332     switch (static_cast<errc>(__ec.value())) {
333     case errc::no_such_file_or_directory:
334     case errc::not_a_directory:
335       return true;
336     default:
337       return false;
338     }
339   }
340 
341   _LIBCPP_INLINE_VISIBILITY
342   void __handle_error(const char* __msg, error_code* __dest_ec,
343                       error_code const& __ec, bool __allow_dne = false) const {
344     if (__dest_ec) {
345       *__dest_ec = __ec;
346       return;
347     }
348     if (__ec && (!__allow_dne || !__is_dne_error(__ec)))
349       __throw_filesystem_error(__msg, __p_, __ec);
350   }
351 
352   _LIBCPP_INLINE_VISIBILITY
353   void __refresh(error_code* __ec = nullptr) {
354     __handle_error("in directory_entry::refresh", __ec, __do_refresh(),
355                    /*allow_dne*/ true);
356   }
357 
358   _LIBCPP_INLINE_VISIBILITY
359   file_type __get_sym_ft(error_code* __ec = nullptr) const {
360     switch (__data_.__cache_type_) {
361     case _Empty:
362       return __symlink_status(__p_, __ec).type();
363     case _IterSymlink:
364     case _RefreshSymlink:
365     case _RefreshSymlinkUnresolved:
366       if (__ec)
367         __ec->clear();
368       return file_type::symlink;
369     case _IterNonSymlink:
370     case _RefreshNonSymlink:
371       file_status __st(__data_.__type_);
372       if (__ec && !_VSTD_FS::exists(__st))
373         *__ec = make_error_code(errc::no_such_file_or_directory);
374       else if (__ec)
375         __ec->clear();
376       return __data_.__type_;
377     }
378     __libcpp_unreachable();
379   }
380 
381   _LIBCPP_INLINE_VISIBILITY
382   file_type __get_ft(error_code* __ec = nullptr) const {
383     switch (__data_.__cache_type_) {
384     case _Empty:
385     case _IterSymlink:
386     case _RefreshSymlinkUnresolved:
387       return __status(__p_, __ec).type();
388     case _IterNonSymlink:
389     case _RefreshNonSymlink:
390     case _RefreshSymlink: {
391       file_status __st(__data_.__type_);
392       if (__ec && !_VSTD_FS::exists(__st))
393         *__ec = make_error_code(errc::no_such_file_or_directory);
394       else if (__ec)
395         __ec->clear();
396       return __data_.__type_;
397     }
398     }
399     __libcpp_unreachable();
400   }
401 
402   _LIBCPP_INLINE_VISIBILITY
403   file_status __get_status(error_code* __ec = nullptr) const {
404     switch (__data_.__cache_type_) {
405     case _Empty:
406     case _IterNonSymlink:
407     case _IterSymlink:
408     case _RefreshSymlinkUnresolved:
409       return __status(__p_, __ec);
410     case _RefreshNonSymlink:
411     case _RefreshSymlink:
412       return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
413     }
414     __libcpp_unreachable();
415   }
416 
417   _LIBCPP_INLINE_VISIBILITY
418   file_status __get_symlink_status(error_code* __ec = nullptr) const {
419     switch (__data_.__cache_type_) {
420     case _Empty:
421     case _IterNonSymlink:
422     case _IterSymlink:
423       return __symlink_status(__p_, __ec);
424     case _RefreshNonSymlink:
425       return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
426     case _RefreshSymlink:
427     case _RefreshSymlinkUnresolved:
428       return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
429     }
430     __libcpp_unreachable();
431   }
432 
433   _LIBCPP_INLINE_VISIBILITY
434   uintmax_t __get_size(error_code* __ec = nullptr) const {
435     switch (__data_.__cache_type_) {
436     case _Empty:
437     case _IterNonSymlink:
438     case _IterSymlink:
439     case _RefreshSymlinkUnresolved:
440       return _VSTD_FS::__file_size(__p_, __ec);
441     case _RefreshSymlink:
442     case _RefreshNonSymlink: {
443       error_code __m_ec;
444       file_status __st(__get_ft(&__m_ec));
445       __handle_error("in directory_entry::file_size", __ec, __m_ec);
446       if (_VSTD_FS::exists(__st) && !_VSTD_FS::is_regular_file(__st)) {
447         errc __err_kind = _VSTD_FS::is_directory(__st) ? errc::is_a_directory
448                                                        : errc::not_supported;
449         __handle_error("in directory_entry::file_size", __ec,
450                        make_error_code(__err_kind));
451       }
452       return __data_.__size_;
453     }
454     }
455     __libcpp_unreachable();
456   }
457 
458   _LIBCPP_INLINE_VISIBILITY
459   uintmax_t __get_nlink(error_code* __ec = nullptr) const {
460     switch (__data_.__cache_type_) {
461     case _Empty:
462     case _IterNonSymlink:
463     case _IterSymlink:
464     case _RefreshSymlinkUnresolved:
465       return _VSTD_FS::__hard_link_count(__p_, __ec);
466     case _RefreshSymlink:
467     case _RefreshNonSymlink: {
468       error_code __m_ec;
469       (void)__get_ft(&__m_ec);
470       __handle_error("in directory_entry::hard_link_count", __ec, __m_ec);
471       return __data_.__nlink_;
472     }
473     }
474     __libcpp_unreachable();
475   }
476 
477   _LIBCPP_INLINE_VISIBILITY
478   file_time_type __get_write_time(error_code* __ec = nullptr) const {
479     switch (__data_.__cache_type_) {
480     case _Empty:
481     case _IterNonSymlink:
482     case _IterSymlink:
483     case _RefreshSymlinkUnresolved:
484       return _VSTD_FS::__last_write_time(__p_, __ec);
485     case _RefreshSymlink:
486     case _RefreshNonSymlink: {
487       error_code __m_ec;
488       file_status __st(__get_ft(&__m_ec));
489       __handle_error("in directory_entry::last_write_time", __ec, __m_ec);
490       if (_VSTD_FS::exists(__st) &&
491           __data_.__write_time_ == file_time_type::min())
492         __handle_error("in directory_entry::last_write_time", __ec,
493                        make_error_code(errc::value_too_large));
494       return __data_.__write_time_;
495     }
496     }
497     __libcpp_unreachable();
498   }
499 
500 private:
501   _Path __p_;
502   __cached_data __data_;
503 };
504 
505 class __dir_element_proxy {
506 public:
507   inline _LIBCPP_INLINE_VISIBILITY directory_entry operator*() {
508     return _VSTD::move(__elem_);
509   }
510 
511 private:
512   friend class directory_iterator;
513   friend class recursive_directory_iterator;
__dir_element_proxy(directory_entry const & __e)514   _LIBCPP_HIDE_FROM_ABI explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}
__dir_element_proxy(__dir_element_proxy && __o)515   _LIBCPP_HIDE_FROM_ABI __dir_element_proxy(__dir_element_proxy&& __o)
516       : __elem_(_VSTD::move(__o.__elem_)) {}
517   directory_entry __elem_;
518 };
519 
520 _LIBCPP_AVAILABILITY_FILESYSTEM_POP
521 
522 _LIBCPP_END_NAMESPACE_FILESYSTEM
523 
524 #endif // _LIBCPP_CXX03_LANG
525 
526 _LIBCPP_POP_MACROS
527 
528 #endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
529