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