xref: /freebsd/contrib/llvm-project/libcxx/include/__filesystem/directory_entry.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 <__chrono/time_point.h>
14 #include <__compare/ordering.h>
15 #include <__config>
16 #include <__filesystem/file_status.h>
17 #include <__filesystem/file_time_type.h>
18 #include <__filesystem/file_type.h>
19 #include <__filesystem/filesystem_error.h>
20 #include <__filesystem/operations.h>
21 #include <__filesystem/path.h>
22 #include <__filesystem/perms.h>
23 #include <__system_error/errc.h>
24 #include <__system_error/error_code.h>
25 #include <__utility/move.h>
26 #include <__utility/unreachable.h>
27 #include <cstdint>
28 
29 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30 #  pragma GCC system_header
31 #endif
32 
33 _LIBCPP_PUSH_MACROS
34 #include <__undef_macros>
35 
36 #if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
37 
38 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
39 
40 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
41 
42 class directory_entry {
43   typedef filesystem::path _Path;
44 
45 public:
46   // constructors and destructors
47   _LIBCPP_HIDE_FROM_ABI directory_entry() noexcept                  = default;
48   _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry const&)     = default;
49   _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry&&) noexcept = default;
50 
directory_entry(_Path const & __p)51   _LIBCPP_HIDE_FROM_ABI explicit directory_entry(_Path const& __p) : __p_(__p) {
52     error_code __ec;
53     __refresh(&__ec);
54   }
55 
directory_entry(_Path const & __p,error_code & __ec)56   _LIBCPP_HIDE_FROM_ABI directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) { __refresh(&__ec); }
57 
~directory_entry()58   _LIBCPP_HIDE_FROM_ABI ~directory_entry() {}
59 
60   _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry const&)     = default;
61   _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry&&) noexcept = default;
62 
assign(_Path const & __p)63   _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p) {
64     __p_ = __p;
65     error_code __ec;
66     __refresh(&__ec);
67   }
68 
assign(_Path const & __p,error_code & __ec)69   _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p, error_code& __ec) {
70     __p_ = __p;
71     __refresh(&__ec);
72   }
73 
replace_filename(_Path const & __p)74   _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p) {
75     __p_.replace_filename(__p);
76     error_code __ec;
77     __refresh(&__ec);
78   }
79 
replace_filename(_Path const & __p,error_code & __ec)80   _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p, error_code& __ec) {
81     __p_ = __p_.parent_path() / __p;
82     __refresh(&__ec);
83   }
84 
refresh()85   _LIBCPP_HIDE_FROM_ABI void refresh() { __refresh(); }
86 
refresh(error_code & __ec)87   _LIBCPP_HIDE_FROM_ABI void refresh(error_code& __ec) noexcept { __refresh(&__ec); }
88 
path()89   _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; }
90 
91   _LIBCPP_HIDE_FROM_ABI operator const _Path&() const noexcept { return __p_; }
92 
exists()93   _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(file_status{__get_ft()}); }
94 
exists(error_code & __ec)95   _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept {
96     return filesystem::exists(file_status{__get_ft(&__ec)});
97   }
98 
is_block_file()99   _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; }
100 
is_block_file(error_code & __ec)101   _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept {
102     return __get_ft(&__ec) == file_type::block;
103   }
104 
is_character_file()105   _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; }
106 
is_character_file(error_code & __ec)107   _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept {
108     return __get_ft(&__ec) == file_type::character;
109   }
110 
is_directory()111   _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; }
112 
is_directory(error_code & __ec)113   _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept {
114     return __get_ft(&__ec) == file_type::directory;
115   }
116 
is_fifo()117   _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; }
118 
is_fifo(error_code & __ec)119   _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::fifo; }
120 
is_other()121   _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(file_status{__get_ft()}); }
122 
is_other(error_code & __ec)123   _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept {
124     return filesystem::is_other(file_status{__get_ft(&__ec)});
125   }
126 
is_regular_file()127   _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; }
128 
is_regular_file(error_code & __ec)129   _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept {
130     return __get_ft(&__ec) == file_type::regular;
131   }
132 
is_socket()133   _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; }
134 
is_socket(error_code & __ec)135   _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::socket; }
136 
is_symlink()137   _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; }
138 
is_symlink(error_code & __ec)139   _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept {
140     return __get_sym_ft(&__ec) == file_type::symlink;
141   }
file_size()142   _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); }
143 
file_size(error_code & __ec)144   _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(&__ec); }
145 
hard_link_count()146   _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); }
147 
hard_link_count(error_code & __ec)148   _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { return __get_nlink(&__ec); }
149 
last_write_time()150   _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); }
151 
last_write_time(error_code & __ec)152   _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept {
153     return __get_write_time(&__ec);
154   }
155 
status()156   _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); }
157 
status(error_code & __ec)158   _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { return __get_status(&__ec); }
159 
symlink_status()160   _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); }
161 
symlink_status(error_code & __ec)162   _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept {
163     return __get_symlink_status(&__ec);
164   }
165 
166   _LIBCPP_HIDE_FROM_ABI bool operator==(directory_entry const& __rhs) const noexcept { return __p_ == __rhs.__p_; }
167 
168 #  if _LIBCPP_STD_VER <= 17
169   _LIBCPP_HIDE_FROM_ABI bool operator!=(directory_entry const& __rhs) const noexcept { return __p_ != __rhs.__p_; }
170 
171   _LIBCPP_HIDE_FROM_ABI bool operator<(directory_entry const& __rhs) const noexcept { return __p_ < __rhs.__p_; }
172 
173   _LIBCPP_HIDE_FROM_ABI bool operator<=(directory_entry const& __rhs) const noexcept { return __p_ <= __rhs.__p_; }
174 
175   _LIBCPP_HIDE_FROM_ABI bool operator>(directory_entry const& __rhs) const noexcept { return __p_ > __rhs.__p_; }
176 
177   _LIBCPP_HIDE_FROM_ABI bool operator>=(directory_entry const& __rhs) const noexcept { return __p_ >= __rhs.__p_; }
178 
179 #  else // _LIBCPP_STD_VER <= 17
180 
181   _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const directory_entry& __rhs) const noexcept {
182     return __p_ <=> __rhs.__p_;
183   }
184 
185 #  endif // _LIBCPP_STD_VER <= 17
186 
187   template <class _CharT, class _Traits>
188   _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>&
189   operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) {
190     return __os << __d.path();
191   }
192 
193 private:
194   friend class directory_iterator;
195   friend class recursive_directory_iterator;
196   friend class _LIBCPP_HIDDEN __dir_stream;
197 
198   enum _CacheType : unsigned char {
199     _Empty,
200     _IterSymlink,
201     _IterNonSymlink,
202     _RefreshSymlink,
203     _RefreshSymlinkUnresolved,
204     _RefreshNonSymlink
205   };
206 
207   struct __cached_data {
208     uintmax_t __size_;
209     uintmax_t __nlink_;
210     file_time_type __write_time_;
211     perms __sym_perms_;
212     perms __non_sym_perms_;
213     file_type __type_;
214     _CacheType __cache_type_;
215 
__cached_data__cached_data216     _LIBCPP_HIDE_FROM_ABI __cached_data() noexcept { __reset(); }
217 
__reset__cached_data218     _LIBCPP_HIDE_FROM_ABI void __reset() {
219       __cache_type_ = _Empty;
220       __type_       = file_type::none;
221       __sym_perms_ = __non_sym_perms_ = perms::unknown;
222       __size_ = __nlink_ = uintmax_t(-1);
223       __write_time_      = file_time_type::min();
224     }
225   };
226 
__create_iter_result(file_type __ft)227   _LIBCPP_HIDE_FROM_ABI static __cached_data __create_iter_result(file_type __ft) {
228     __cached_data __data;
229     __data.__type_       = __ft;
230     __data.__cache_type_ = [&]() {
231       switch (__ft) {
232       case file_type::none:
233         return _Empty;
234       case file_type::symlink:
235         return _IterSymlink;
236       default:
237         return _IterNonSymlink;
238       }
239     }();
240     return __data;
241   }
242 
__assign_iter_entry(_Path && __p,__cached_data __dt)243   _LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) {
244     __p_    = std::move(__p);
245     __data_ = __dt;
246   }
247 
248   _LIBCPP_EXPORTED_FROM_ABI error_code __do_refresh() noexcept;
249 
__is_dne_error(error_code const & __ec)250   _LIBCPP_HIDE_FROM_ABI static bool __is_dne_error(error_code const& __ec) {
251     if (!__ec)
252       return true;
253     switch (static_cast<errc>(__ec.value())) {
254     case errc::no_such_file_or_directory:
255     case errc::not_a_directory:
256       return true;
257     default:
258       return false;
259     }
260   }
261 
262   _LIBCPP_HIDE_FROM_ABI void
263   __handle_error(const char* __msg, error_code* __dest_ec, error_code const& __ec, bool __allow_dne = false) const {
264     if (__dest_ec) {
265       *__dest_ec = __ec;
266       return;
267     }
268     if (__ec && (!__allow_dne || !__is_dne_error(__ec)))
269       __throw_filesystem_error(__msg, __p_, __ec);
270   }
271 
272   _LIBCPP_HIDE_FROM_ABI void __refresh(error_code* __ec = nullptr) {
273     __handle_error("in directory_entry::refresh",
274                    __ec,
275                    __do_refresh(),
276                    /*allow_dne*/ true);
277   }
278 
279   _LIBCPP_HIDE_FROM_ABI file_type __get_sym_ft(error_code* __ec = nullptr) const {
280     switch (__data_.__cache_type_) {
281     case _Empty:
282       return __symlink_status(__p_, __ec).type();
283     case _IterSymlink:
284     case _RefreshSymlink:
285     case _RefreshSymlinkUnresolved:
286       if (__ec)
287         __ec->clear();
288       return file_type::symlink;
289     case _IterNonSymlink:
290     case _RefreshNonSymlink:
291       file_status __st(__data_.__type_);
292       if (__ec && !filesystem::exists(__st))
293         *__ec = make_error_code(errc::no_such_file_or_directory);
294       else if (__ec)
295         __ec->clear();
296       return __data_.__type_;
297     }
298     __libcpp_unreachable();
299   }
300 
301   _LIBCPP_HIDE_FROM_ABI file_type __get_ft(error_code* __ec = nullptr) const {
302     switch (__data_.__cache_type_) {
303     case _Empty:
304     case _IterSymlink:
305     case _RefreshSymlinkUnresolved:
306       return __status(__p_, __ec).type();
307     case _IterNonSymlink:
308     case _RefreshNonSymlink:
309     case _RefreshSymlink: {
310       file_status __st(__data_.__type_);
311       if (__ec && !filesystem::exists(__st))
312         *__ec = make_error_code(errc::no_such_file_or_directory);
313       else if (__ec)
314         __ec->clear();
315       return __data_.__type_;
316     }
317     }
318     __libcpp_unreachable();
319   }
320 
321   _LIBCPP_HIDE_FROM_ABI file_status __get_status(error_code* __ec = nullptr) const {
322     switch (__data_.__cache_type_) {
323     case _Empty:
324     case _IterNonSymlink:
325     case _IterSymlink:
326     case _RefreshSymlinkUnresolved:
327       return __status(__p_, __ec);
328     case _RefreshNonSymlink:
329     case _RefreshSymlink:
330       return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
331     }
332     __libcpp_unreachable();
333   }
334 
335   _LIBCPP_HIDE_FROM_ABI file_status __get_symlink_status(error_code* __ec = nullptr) const {
336     switch (__data_.__cache_type_) {
337     case _Empty:
338     case _IterNonSymlink:
339     case _IterSymlink:
340       return __symlink_status(__p_, __ec);
341     case _RefreshNonSymlink:
342       return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
343     case _RefreshSymlink:
344     case _RefreshSymlinkUnresolved:
345       return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
346     }
347     __libcpp_unreachable();
348   }
349 
350   _LIBCPP_HIDE_FROM_ABI uintmax_t __get_size(error_code* __ec = nullptr) const {
351     switch (__data_.__cache_type_) {
352     case _Empty:
353     case _IterNonSymlink:
354     case _IterSymlink:
355     case _RefreshSymlinkUnresolved:
356       return filesystem::__file_size(__p_, __ec);
357     case _RefreshSymlink:
358     case _RefreshNonSymlink: {
359       error_code __m_ec;
360       file_status __st(__get_ft(&__m_ec));
361       __handle_error("in directory_entry::file_size", __ec, __m_ec);
362       if (filesystem::exists(__st) && !filesystem::is_regular_file(__st)) {
363         errc __err_kind = filesystem::is_directory(__st) ? errc::is_a_directory : errc::not_supported;
364         __handle_error("in directory_entry::file_size", __ec, make_error_code(__err_kind));
365       }
366       return __data_.__size_;
367     }
368     }
369     __libcpp_unreachable();
370   }
371 
372   _LIBCPP_HIDE_FROM_ABI uintmax_t __get_nlink(error_code* __ec = nullptr) const {
373     switch (__data_.__cache_type_) {
374     case _Empty:
375     case _IterNonSymlink:
376     case _IterSymlink:
377     case _RefreshSymlinkUnresolved:
378       return filesystem::__hard_link_count(__p_, __ec);
379     case _RefreshSymlink:
380     case _RefreshNonSymlink: {
381       error_code __m_ec;
382       (void)__get_ft(&__m_ec);
383       __handle_error("in directory_entry::hard_link_count", __ec, __m_ec);
384       return __data_.__nlink_;
385     }
386     }
387     __libcpp_unreachable();
388   }
389 
390   _LIBCPP_HIDE_FROM_ABI file_time_type __get_write_time(error_code* __ec = nullptr) const {
391     switch (__data_.__cache_type_) {
392     case _Empty:
393     case _IterNonSymlink:
394     case _IterSymlink:
395     case _RefreshSymlinkUnresolved:
396       return filesystem::__last_write_time(__p_, __ec);
397     case _RefreshSymlink:
398     case _RefreshNonSymlink: {
399       error_code __m_ec;
400       file_status __st(__get_ft(&__m_ec));
401       __handle_error("in directory_entry::last_write_time", __ec, __m_ec);
402       if (filesystem::exists(__st) && __data_.__write_time_ == file_time_type::min())
403         __handle_error("in directory_entry::last_write_time", __ec, make_error_code(errc::value_too_large));
404       return __data_.__write_time_;
405     }
406     }
407     __libcpp_unreachable();
408   }
409 
410 private:
411   _Path __p_;
412   __cached_data __data_;
413 };
414 
415 class __dir_element_proxy {
416 public:
417   inline _LIBCPP_HIDE_FROM_ABI directory_entry operator*() { return std::move(__elem_); }
418 
419 private:
420   friend class directory_iterator;
421   friend class recursive_directory_iterator;
__dir_element_proxy(directory_entry const & __e)422   _LIBCPP_HIDE_FROM_ABI explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}
__dir_element_proxy(__dir_element_proxy && __o)423   _LIBCPP_HIDE_FROM_ABI __dir_element_proxy(__dir_element_proxy&& __o) : __elem_(std::move(__o.__elem_)) {}
424   directory_entry __elem_;
425 };
426 
427 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
428 
429 _LIBCPP_END_NAMESPACE_FILESYSTEM
430 
431 #endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
432 
433 _LIBCPP_POP_MACROS
434 
435 #endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
436