2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
11 #define _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H
13 #include <__availability>
14 #include <__chrono/time_point.h>
15 #include <__compare/ordering.h>
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>
30 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
31 # pragma GCC system_header
35 #include <__undef_macros>
37 #if !defined(_LIBCPP_CXX03_LANG) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
39 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
41 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
43 class directory_entry
{
44 typedef _VSTD_FS::path _Path
;
47 // constructors and destructors
48 _LIBCPP_HIDE_FROM_ABI
directory_entry() noexcept
= default;
49 _LIBCPP_HIDE_FROM_ABI
directory_entry(directory_entry
const&) = default;
50 _LIBCPP_HIDE_FROM_ABI
directory_entry(directory_entry
&&) noexcept
= default;
52 _LIBCPP_INLINE_VISIBILITY
53 explicit directory_entry(_Path
const& __p
) : __p_(__p
) {
58 _LIBCPP_INLINE_VISIBILITY
59 directory_entry(_Path
const& __p
, error_code
& __ec
) : __p_(__p
) {
63 _LIBCPP_HIDE_FROM_ABI
~directory_entry() {}
65 _LIBCPP_HIDE_FROM_ABI directory_entry
& operator=(directory_entry
const&) = default;
66 _LIBCPP_HIDE_FROM_ABI directory_entry
& operator=(directory_entry
&&) noexcept
= default;
68 _LIBCPP_INLINE_VISIBILITY
69 void assign(_Path
const& __p
) {
75 _LIBCPP_INLINE_VISIBILITY
76 void assign(_Path
const& __p
, error_code
& __ec
) {
81 _LIBCPP_INLINE_VISIBILITY
82 void replace_filename(_Path
const& __p
) {
83 __p_
.replace_filename(__p
);
88 _LIBCPP_INLINE_VISIBILITY
89 void replace_filename(_Path
const& __p
, error_code
& __ec
) {
90 __p_
= __p_
.parent_path() / __p
;
94 _LIBCPP_INLINE_VISIBILITY
95 void refresh() { __refresh(); }
97 _LIBCPP_INLINE_VISIBILITY
98 void refresh(error_code
& __ec
) noexcept
{ __refresh(&__ec
); }
100 _LIBCPP_INLINE_VISIBILITY
101 _Path
const& path() const noexcept
{ return __p_
; }
103 _LIBCPP_INLINE_VISIBILITY
104 operator const _Path
&() const noexcept
{ return __p_
; }
106 _LIBCPP_INLINE_VISIBILITY
107 bool exists() const { return _VSTD_FS::exists(file_status
{__get_ft()}); }
109 _LIBCPP_INLINE_VISIBILITY
110 bool exists(error_code
& __ec
) const noexcept
{
111 return _VSTD_FS::exists(file_status
{__get_ft(&__ec
)});
114 _LIBCPP_INLINE_VISIBILITY
115 bool is_block_file() const { return __get_ft() == file_type::block
; }
117 _LIBCPP_INLINE_VISIBILITY
118 bool is_block_file(error_code
& __ec
) const noexcept
{
119 return __get_ft(&__ec
) == file_type::block
;
122 _LIBCPP_INLINE_VISIBILITY
123 bool is_character_file() const { return __get_ft() == file_type::character
; }
125 _LIBCPP_INLINE_VISIBILITY
126 bool is_character_file(error_code
& __ec
) const noexcept
{
127 return __get_ft(&__ec
) == file_type::character
;
130 _LIBCPP_INLINE_VISIBILITY
131 bool is_directory() const { return __get_ft() == file_type::directory
; }
133 _LIBCPP_INLINE_VISIBILITY
134 bool is_directory(error_code
& __ec
) const noexcept
{
135 return __get_ft(&__ec
) == file_type::directory
;
138 _LIBCPP_INLINE_VISIBILITY
139 bool is_fifo() const { return __get_ft() == file_type::fifo
; }
141 _LIBCPP_INLINE_VISIBILITY
142 bool is_fifo(error_code
& __ec
) const noexcept
{
143 return __get_ft(&__ec
) == file_type::fifo
;
146 _LIBCPP_INLINE_VISIBILITY
147 bool is_other() const { return _VSTD_FS::is_other(file_status
{__get_ft()}); }
149 _LIBCPP_INLINE_VISIBILITY
150 bool is_other(error_code
& __ec
) const noexcept
{
151 return _VSTD_FS::is_other(file_status
{__get_ft(&__ec
)});
154 _LIBCPP_INLINE_VISIBILITY
155 bool is_regular_file() const { return __get_ft() == file_type::regular
; }
157 _LIBCPP_INLINE_VISIBILITY
158 bool is_regular_file(error_code
& __ec
) const noexcept
{
159 return __get_ft(&__ec
) == file_type::regular
;
162 _LIBCPP_INLINE_VISIBILITY
163 bool is_socket() const { return __get_ft() == file_type::socket
; }
165 _LIBCPP_INLINE_VISIBILITY
166 bool is_socket(error_code
& __ec
) const noexcept
{
167 return __get_ft(&__ec
) == file_type::socket
;
170 _LIBCPP_INLINE_VISIBILITY
171 bool is_symlink() const { return __get_sym_ft() == file_type::symlink
; }
173 _LIBCPP_INLINE_VISIBILITY
174 bool is_symlink(error_code
& __ec
) const noexcept
{
175 return __get_sym_ft(&__ec
) == file_type::symlink
;
177 _LIBCPP_INLINE_VISIBILITY
178 uintmax_t file_size() const { return __get_size(); }
180 _LIBCPP_INLINE_VISIBILITY
181 uintmax_t file_size(error_code
& __ec
) const noexcept
{
182 return __get_size(&__ec
);
185 _LIBCPP_INLINE_VISIBILITY
186 uintmax_t hard_link_count() const { return __get_nlink(); }
188 _LIBCPP_INLINE_VISIBILITY
189 uintmax_t hard_link_count(error_code
& __ec
) const noexcept
{
190 return __get_nlink(&__ec
);
193 _LIBCPP_INLINE_VISIBILITY
194 file_time_type
last_write_time() const { return __get_write_time(); }
196 _LIBCPP_INLINE_VISIBILITY
197 file_time_type
last_write_time(error_code
& __ec
) const noexcept
{
198 return __get_write_time(&__ec
);
201 _LIBCPP_INLINE_VISIBILITY
202 file_status
status() const { return __get_status(); }
204 _LIBCPP_INLINE_VISIBILITY
205 file_status
status(error_code
& __ec
) const noexcept
{
206 return __get_status(&__ec
);
209 _LIBCPP_INLINE_VISIBILITY
210 file_status
symlink_status() const { return __get_symlink_status(); }
212 _LIBCPP_INLINE_VISIBILITY
213 file_status
symlink_status(error_code
& __ec
) const noexcept
{
214 return __get_symlink_status(&__ec
);
218 _LIBCPP_INLINE_VISIBILITY
219 bool operator==(directory_entry
const& __rhs
) const noexcept
{
220 return __p_
== __rhs
.__p_
;
223 #if _LIBCPP_STD_VER <= 17
224 _LIBCPP_INLINE_VISIBILITY
225 bool operator!=(directory_entry
const& __rhs
) const noexcept
{
226 return __p_
!= __rhs
.__p_
;
229 _LIBCPP_INLINE_VISIBILITY
230 bool operator<(directory_entry
const& __rhs
) const noexcept
{
231 return __p_
< __rhs
.__p_
;
234 _LIBCPP_INLINE_VISIBILITY
235 bool operator<=(directory_entry
const& __rhs
) const noexcept
{
236 return __p_
<= __rhs
.__p_
;
239 _LIBCPP_INLINE_VISIBILITY
240 bool operator>(directory_entry
const& __rhs
) const noexcept
{
241 return __p_
> __rhs
.__p_
;
244 _LIBCPP_INLINE_VISIBILITY
245 bool operator>=(directory_entry
const& __rhs
) const noexcept
{
246 return __p_
>= __rhs
.__p_
;
249 #else // _LIBCPP_STD_VER <= 17
251 _LIBCPP_HIDE_FROM_ABI
252 strong_ordering
operator<=>(const directory_entry
& __rhs
) const noexcept
{
253 return __p_
<=> __rhs
.__p_
;
256 #endif // _LIBCPP_STD_VER <= 17
258 template <class _CharT
, class _Traits
>
259 _LIBCPP_INLINE_VISIBILITY
260 friend basic_ostream
<_CharT
, _Traits
>& operator<<(basic_ostream
<_CharT
, _Traits
>& __os
, const directory_entry
& __d
) {
261 return __os
<< __d
.path();
265 friend class directory_iterator
;
266 friend class recursive_directory_iterator
;
267 friend class _LIBCPP_HIDDEN __dir_stream
;
269 enum _CacheType
: unsigned char {
274 _RefreshSymlinkUnresolved
,
278 struct __cached_data
{
281 file_time_type __write_time_
;
283 perms __non_sym_perms_
;
285 _CacheType __cache_type_
;
287 _LIBCPP_INLINE_VISIBILITY
288 __cached_data() noexcept
{ __reset(); }
290 _LIBCPP_INLINE_VISIBILITY
292 __cache_type_
= _Empty
;
293 __type_
= file_type::none
;
294 __sym_perms_
= __non_sym_perms_
= perms::unknown
;
295 __size_
= __nlink_
= uintmax_t(-1);
296 __write_time_
= file_time_type::min();
300 _LIBCPP_INLINE_VISIBILITY
301 static __cached_data
__create_iter_result(file_type __ft
) {
302 __cached_data __data
;
303 __data
.__type_
= __ft
;
304 __data
.__cache_type_
= [&]() {
306 case file_type::none
:
308 case file_type::symlink
:
311 return _IterNonSymlink
;
317 _LIBCPP_INLINE_VISIBILITY
318 void __assign_iter_entry(_Path
&& __p
, __cached_data __dt
) {
319 __p_
= _VSTD::move(__p
);
323 _LIBCPP_EXPORTED_FROM_ABI error_code
__do_refresh() noexcept
;
325 _LIBCPP_INLINE_VISIBILITY
326 static bool __is_dne_error(error_code
const& __ec
) {
329 switch (static_cast<errc
>(__ec
.value())) {
330 case errc::no_such_file_or_directory
:
331 case errc::not_a_directory
:
338 _LIBCPP_INLINE_VISIBILITY
339 void __handle_error(const char* __msg
, error_code
* __dest_ec
,
340 error_code
const& __ec
, bool __allow_dne
= false) const {
345 if (__ec
&& (!__allow_dne
|| !__is_dne_error(__ec
)))
346 __throw_filesystem_error(__msg
, __p_
, __ec
);
349 _LIBCPP_INLINE_VISIBILITY
350 void __refresh(error_code
* __ec
= nullptr) {
351 __handle_error("in directory_entry::refresh", __ec
, __do_refresh(),
355 _LIBCPP_INLINE_VISIBILITY
356 file_type
__get_sym_ft(error_code
* __ec
= nullptr) const {
357 switch (__data_
.__cache_type_
) {
359 return __symlink_status(__p_
, __ec
).type();
361 case _RefreshSymlink
:
362 case _RefreshSymlinkUnresolved
:
365 return file_type::symlink
;
366 case _IterNonSymlink
:
367 case _RefreshNonSymlink
:
368 file_status
__st(__data_
.__type_
);
369 if (__ec
&& !_VSTD_FS::exists(__st
))
370 *__ec
= make_error_code(errc::no_such_file_or_directory
);
373 return __data_
.__type_
;
375 __libcpp_unreachable();
378 _LIBCPP_INLINE_VISIBILITY
379 file_type
__get_ft(error_code
* __ec
= nullptr) const {
380 switch (__data_
.__cache_type_
) {
383 case _RefreshSymlinkUnresolved
:
384 return __status(__p_
, __ec
).type();
385 case _IterNonSymlink
:
386 case _RefreshNonSymlink
:
387 case _RefreshSymlink
: {
388 file_status
__st(__data_
.__type_
);
389 if (__ec
&& !_VSTD_FS::exists(__st
))
390 *__ec
= make_error_code(errc::no_such_file_or_directory
);
393 return __data_
.__type_
;
396 __libcpp_unreachable();
399 _LIBCPP_INLINE_VISIBILITY
400 file_status
__get_status(error_code
* __ec
= nullptr) const {
401 switch (__data_
.__cache_type_
) {
403 case _IterNonSymlink
:
405 case _RefreshSymlinkUnresolved
:
406 return __status(__p_
, __ec
);
407 case _RefreshNonSymlink
:
408 case _RefreshSymlink
:
409 return file_status(__get_ft(__ec
), __data_
.__non_sym_perms_
);
411 __libcpp_unreachable();
414 _LIBCPP_INLINE_VISIBILITY
415 file_status
__get_symlink_status(error_code
* __ec
= nullptr) const {
416 switch (__data_
.__cache_type_
) {
418 case _IterNonSymlink
:
420 return __symlink_status(__p_
, __ec
);
421 case _RefreshNonSymlink
:
422 return file_status(__get_sym_ft(__ec
), __data_
.__non_sym_perms_
);
423 case _RefreshSymlink
:
424 case _RefreshSymlinkUnresolved
:
425 return file_status(__get_sym_ft(__ec
), __data_
.__sym_perms_
);
427 __libcpp_unreachable();
430 _LIBCPP_INLINE_VISIBILITY
431 uintmax_t __get_size(error_code
* __ec
= nullptr) const {
432 switch (__data_
.__cache_type_
) {
434 case _IterNonSymlink
:
436 case _RefreshSymlinkUnresolved
:
437 return _VSTD_FS::__file_size(__p_
, __ec
);
438 case _RefreshSymlink
:
439 case _RefreshNonSymlink
: {
441 file_status
__st(__get_ft(&__m_ec
));
442 __handle_error("in directory_entry::file_size", __ec
, __m_ec
);
443 if (_VSTD_FS::exists(__st
) && !_VSTD_FS::is_regular_file(__st
)) {
444 errc __err_kind
= _VSTD_FS::is_directory(__st
) ? errc::is_a_directory
445 : errc::not_supported
;
446 __handle_error("in directory_entry::file_size", __ec
,
447 make_error_code(__err_kind
));
449 return __data_
.__size_
;
452 __libcpp_unreachable();
455 _LIBCPP_INLINE_VISIBILITY
456 uintmax_t __get_nlink(error_code
* __ec
= nullptr) const {
457 switch (__data_
.__cache_type_
) {
459 case _IterNonSymlink
:
461 case _RefreshSymlinkUnresolved
:
462 return _VSTD_FS::__hard_link_count(__p_
, __ec
);
463 case _RefreshSymlink
:
464 case _RefreshNonSymlink
: {
466 (void)__get_ft(&__m_ec
);
467 __handle_error("in directory_entry::hard_link_count", __ec
, __m_ec
);
468 return __data_
.__nlink_
;
471 __libcpp_unreachable();
474 _LIBCPP_INLINE_VISIBILITY
475 file_time_type
__get_write_time(error_code
* __ec
= nullptr) const {
476 switch (__data_
.__cache_type_
) {
478 case _IterNonSymlink
:
480 case _RefreshSymlinkUnresolved
:
481 return _VSTD_FS::__last_write_time(__p_
, __ec
);
482 case _RefreshSymlink
:
483 case _RefreshNonSymlink
: {
485 file_status
__st(__get_ft(&__m_ec
));
486 __handle_error("in directory_entry::last_write_time", __ec
, __m_ec
);
487 if (_VSTD_FS::exists(__st
) &&
488 __data_
.__write_time_
== file_time_type::min())
489 __handle_error("in directory_entry::last_write_time", __ec
,
490 make_error_code(errc::value_too_large
));
491 return __data_
.__write_time_
;
494 __libcpp_unreachable();
499 __cached_data __data_
;
502 class __dir_element_proxy
{
504 inline _LIBCPP_INLINE_VISIBILITY directory_entry
operator*() {
505 return _VSTD::move(__elem_
);
509 friend class directory_iterator
;
510 friend class recursive_directory_iterator
;
511 _LIBCPP_HIDE_FROM_ABI
explicit __dir_element_proxy(directory_entry
const& __e
) : __elem_(__e
) {}
512 _LIBCPP_HIDE_FROM_ABI
__dir_element_proxy(__dir_element_proxy
&& __o
)
513 : __elem_(_VSTD::move(__o
.__elem_
)) {}
514 directory_entry __elem_
;
517 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
519 _LIBCPP_END_NAMESPACE_FILESYSTEM
521 #endif // !defined(_LIBCPP_CXX03_LANG) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
525 #endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H