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 <__cxx03/__chrono/time_point.h>
14 #include <__cxx03/__compare/ordering.h>
15 #include <__cxx03/__config>
16 #include <__cxx03/__filesystem/file_status.h>
17 #include <__cxx03/__filesystem/file_time_type.h>
18 #include <__cxx03/__filesystem/file_type.h>
19 #include <__cxx03/__filesystem/filesystem_error.h>
20 #include <__cxx03/__filesystem/operations.h>
21 #include <__cxx03/__filesystem/path.h>
22 #include <__cxx03/__filesystem/perms.h>
23 #include <__cxx03/__system_error/errc.h>
24 #include <__cxx03/__system_error/error_code.h>
25 #include <__cxx03/__utility/move.h>
26 #include <__cxx03/__utility/unreachable.h>
27 #include <__cxx03/cstdint>
29 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30 # pragma GCC system_header
34 #include <__cxx03/__undef_macros>
36 #if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
38 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
40 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
42 class directory_entry
{
43 typedef filesystem::path _Path
;
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;
51 _LIBCPP_HIDE_FROM_ABI
explicit directory_entry(_Path
const& __p
) : __p_(__p
) {
56 _LIBCPP_HIDE_FROM_ABI
directory_entry(_Path
const& __p
, error_code
& __ec
) : __p_(__p
) { __refresh(&__ec
); }
58 _LIBCPP_HIDE_FROM_ABI
~directory_entry() {}
60 _LIBCPP_HIDE_FROM_ABI directory_entry
& operator=(directory_entry
const&) = default;
61 _LIBCPP_HIDE_FROM_ABI directory_entry
& operator=(directory_entry
&&) noexcept
= default;
63 _LIBCPP_HIDE_FROM_ABI
void assign(_Path
const& __p
) {
69 _LIBCPP_HIDE_FROM_ABI
void assign(_Path
const& __p
, error_code
& __ec
) {
74 _LIBCPP_HIDE_FROM_ABI
void replace_filename(_Path
const& __p
) {
75 __p_
.replace_filename(__p
);
80 _LIBCPP_HIDE_FROM_ABI
void replace_filename(_Path
const& __p
, error_code
& __ec
) {
81 __p_
= __p_
.parent_path() / __p
;
85 _LIBCPP_HIDE_FROM_ABI
void refresh() { __refresh(); }
87 _LIBCPP_HIDE_FROM_ABI
void refresh(error_code
& __ec
) noexcept
{ __refresh(&__ec
); }
89 _LIBCPP_HIDE_FROM_ABI _Path
const& path() const noexcept
{ return __p_
; }
91 _LIBCPP_HIDE_FROM_ABI
operator const _Path
&() const noexcept
{ return __p_
; }
93 _LIBCPP_HIDE_FROM_ABI
bool exists() const { return filesystem::exists(file_status
{__get_ft()}); }
95 _LIBCPP_HIDE_FROM_ABI
bool exists(error_code
& __ec
) const noexcept
{
96 return filesystem::exists(file_status
{__get_ft(&__ec
)});
99 _LIBCPP_HIDE_FROM_ABI
bool is_block_file() const { return __get_ft() == file_type::block
; }
101 _LIBCPP_HIDE_FROM_ABI
bool is_block_file(error_code
& __ec
) const noexcept
{
102 return __get_ft(&__ec
) == file_type::block
;
105 _LIBCPP_HIDE_FROM_ABI
bool is_character_file() const { return __get_ft() == file_type::character
; }
107 _LIBCPP_HIDE_FROM_ABI
bool is_character_file(error_code
& __ec
) const noexcept
{
108 return __get_ft(&__ec
) == file_type::character
;
111 _LIBCPP_HIDE_FROM_ABI
bool is_directory() const { return __get_ft() == file_type::directory
; }
113 _LIBCPP_HIDE_FROM_ABI
bool is_directory(error_code
& __ec
) const noexcept
{
114 return __get_ft(&__ec
) == file_type::directory
;
117 _LIBCPP_HIDE_FROM_ABI
bool is_fifo() const { return __get_ft() == file_type::fifo
; }
119 _LIBCPP_HIDE_FROM_ABI
bool is_fifo(error_code
& __ec
) const noexcept
{ return __get_ft(&__ec
) == file_type::fifo
; }
121 _LIBCPP_HIDE_FROM_ABI
bool is_other() const { return filesystem::is_other(file_status
{__get_ft()}); }
123 _LIBCPP_HIDE_FROM_ABI
bool is_other(error_code
& __ec
) const noexcept
{
124 return filesystem::is_other(file_status
{__get_ft(&__ec
)});
127 _LIBCPP_HIDE_FROM_ABI
bool is_regular_file() const { return __get_ft() == file_type::regular
; }
129 _LIBCPP_HIDE_FROM_ABI
bool is_regular_file(error_code
& __ec
) const noexcept
{
130 return __get_ft(&__ec
) == file_type::regular
;
133 _LIBCPP_HIDE_FROM_ABI
bool is_socket() const { return __get_ft() == file_type::socket
; }
135 _LIBCPP_HIDE_FROM_ABI
bool is_socket(error_code
& __ec
) const noexcept
{ return __get_ft(&__ec
) == file_type::socket
; }
137 _LIBCPP_HIDE_FROM_ABI
bool is_symlink() const { return __get_sym_ft() == file_type::symlink
; }
139 _LIBCPP_HIDE_FROM_ABI
bool is_symlink(error_code
& __ec
) const noexcept
{
140 return __get_sym_ft(&__ec
) == file_type::symlink
;
142 _LIBCPP_HIDE_FROM_ABI
uintmax_t file_size() const { return __get_size(); }
144 _LIBCPP_HIDE_FROM_ABI
uintmax_t file_size(error_code
& __ec
) const noexcept
{ return __get_size(&__ec
); }
146 _LIBCPP_HIDE_FROM_ABI
uintmax_t hard_link_count() const { return __get_nlink(); }
148 _LIBCPP_HIDE_FROM_ABI
uintmax_t hard_link_count(error_code
& __ec
) const noexcept
{ return __get_nlink(&__ec
); }
150 _LIBCPP_HIDE_FROM_ABI file_time_type
last_write_time() const { return __get_write_time(); }
152 _LIBCPP_HIDE_FROM_ABI file_time_type
last_write_time(error_code
& __ec
) const noexcept
{
153 return __get_write_time(&__ec
);
156 _LIBCPP_HIDE_FROM_ABI file_status
status() const { return __get_status(); }
158 _LIBCPP_HIDE_FROM_ABI file_status
status(error_code
& __ec
) const noexcept
{ return __get_status(&__ec
); }
160 _LIBCPP_HIDE_FROM_ABI file_status
symlink_status() const { return __get_symlink_status(); }
162 _LIBCPP_HIDE_FROM_ABI file_status
symlink_status(error_code
& __ec
) const noexcept
{
163 return __get_symlink_status(&__ec
);
166 _LIBCPP_HIDE_FROM_ABI
bool operator==(directory_entry
const& __rhs
) const noexcept
{ return __p_
== __rhs
.__p_
; }
168 # if _LIBCPP_STD_VER <= 17
169 _LIBCPP_HIDE_FROM_ABI
bool operator!=(directory_entry
const& __rhs
) const noexcept
{ return __p_
!= __rhs
.__p_
; }
171 _LIBCPP_HIDE_FROM_ABI
bool operator<(directory_entry
const& __rhs
) const noexcept
{ return __p_
< __rhs
.__p_
; }
173 _LIBCPP_HIDE_FROM_ABI
bool operator<=(directory_entry
const& __rhs
) const noexcept
{ return __p_
<= __rhs
.__p_
; }
175 _LIBCPP_HIDE_FROM_ABI
bool operator>(directory_entry
const& __rhs
) const noexcept
{ return __p_
> __rhs
.__p_
; }
177 _LIBCPP_HIDE_FROM_ABI
bool operator>=(directory_entry
const& __rhs
) const noexcept
{ return __p_
>= __rhs
.__p_
; }
179 # else // _LIBCPP_STD_VER <= 17
181 _LIBCPP_HIDE_FROM_ABI strong_ordering
operator<=>(const directory_entry
& __rhs
) const noexcept
{
182 return __p_
<=> __rhs
.__p_
;
185 # endif // _LIBCPP_STD_VER <= 17
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();
194 friend class directory_iterator
;
195 friend class recursive_directory_iterator
;
196 friend class _LIBCPP_HIDDEN __dir_stream
;
198 enum _CacheType
: unsigned char {
203 _RefreshSymlinkUnresolved
,
207 struct __cached_data
{
210 file_time_type __write_time_
;
212 perms __non_sym_perms_
;
214 _CacheType __cache_type_
;
216 _LIBCPP_HIDE_FROM_ABI
__cached_data() noexcept
{ __reset(); }
218 _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();
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_
= [&]() {
232 case file_type::none
:
234 case file_type::symlink
:
237 return _IterNonSymlink
;
243 _LIBCPP_HIDE_FROM_ABI
void __assign_iter_entry(_Path
&& __p
, __cached_data __dt
) {
244 __p_
= std::move(__p
);
248 _LIBCPP_EXPORTED_FROM_ABI error_code
__do_refresh() noexcept
;
250 _LIBCPP_HIDE_FROM_ABI
static bool __is_dne_error(error_code
const& __ec
) {
253 switch (static_cast<errc
>(__ec
.value())) {
254 case errc::no_such_file_or_directory
:
255 case errc::not_a_directory
:
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 {
268 if (__ec
&& (!__allow_dne
|| !__is_dne_error(__ec
)))
269 __throw_filesystem_error(__msg
, __p_
, __ec
);
272 _LIBCPP_HIDE_FROM_ABI
void __refresh(error_code
* __ec
= nullptr) {
273 __handle_error("in directory_entry::refresh",
279 _LIBCPP_HIDE_FROM_ABI file_type
__get_sym_ft(error_code
* __ec
= nullptr) const {
280 switch (__data_
.__cache_type_
) {
282 return __symlink_status(__p_
, __ec
).type();
284 case _RefreshSymlink
:
285 case _RefreshSymlinkUnresolved
:
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
);
296 return __data_
.__type_
;
298 __libcpp_unreachable();
301 _LIBCPP_HIDE_FROM_ABI file_type
__get_ft(error_code
* __ec
= nullptr) const {
302 switch (__data_
.__cache_type_
) {
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
);
315 return __data_
.__type_
;
318 __libcpp_unreachable();
321 _LIBCPP_HIDE_FROM_ABI file_status
__get_status(error_code
* __ec
= nullptr) const {
322 switch (__data_
.__cache_type_
) {
324 case _IterNonSymlink
:
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_
);
332 __libcpp_unreachable();
335 _LIBCPP_HIDE_FROM_ABI file_status
__get_symlink_status(error_code
* __ec
= nullptr) const {
336 switch (__data_
.__cache_type_
) {
338 case _IterNonSymlink
:
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_
);
347 __libcpp_unreachable();
350 _LIBCPP_HIDE_FROM_ABI
uintmax_t __get_size(error_code
* __ec
= nullptr) const {
351 switch (__data_
.__cache_type_
) {
353 case _IterNonSymlink
:
355 case _RefreshSymlinkUnresolved
:
356 return filesystem::__file_size(__p_
, __ec
);
357 case _RefreshSymlink
:
358 case _RefreshNonSymlink
: {
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
));
366 return __data_
.__size_
;
369 __libcpp_unreachable();
372 _LIBCPP_HIDE_FROM_ABI
uintmax_t __get_nlink(error_code
* __ec
= nullptr) const {
373 switch (__data_
.__cache_type_
) {
375 case _IterNonSymlink
:
377 case _RefreshSymlinkUnresolved
:
378 return filesystem::__hard_link_count(__p_
, __ec
);
379 case _RefreshSymlink
:
380 case _RefreshNonSymlink
: {
382 (void)__get_ft(&__m_ec
);
383 __handle_error("in directory_entry::hard_link_count", __ec
, __m_ec
);
384 return __data_
.__nlink_
;
387 __libcpp_unreachable();
390 _LIBCPP_HIDE_FROM_ABI file_time_type
__get_write_time(error_code
* __ec
= nullptr) const {
391 switch (__data_
.__cache_type_
) {
393 case _IterNonSymlink
:
395 case _RefreshSymlinkUnresolved
:
396 return filesystem::__last_write_time(__p_
, __ec
);
397 case _RefreshSymlink
:
398 case _RefreshNonSymlink
: {
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_
;
407 __libcpp_unreachable();
412 __cached_data __data_
;
415 class __dir_element_proxy
{
417 inline _LIBCPP_HIDE_FROM_ABI directory_entry
operator*() { return std::move(__elem_
); }
420 friend class directory_iterator
;
421 friend class recursive_directory_iterator
;
422 _LIBCPP_HIDE_FROM_ABI
explicit __dir_element_proxy(directory_entry
const& __e
) : __elem_(__e
) {}
423 _LIBCPP_HIDE_FROM_ABI
__dir_element_proxy(__dir_element_proxy
&& __o
) : __elem_(std::move(__o
.__elem_
)) {}
424 directory_entry __elem_
;
427 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
429 _LIBCPP_END_NAMESPACE_FILESYSTEM
431 #endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
435 #endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H