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