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