467 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H11#define _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H12 13#include <__chrono/time_point.h>14#include <__compare/ordering.h>15#include <__config>16#include <__filesystem/file_status.h>17#include <__filesystem/file_time_type.h>18#include <__filesystem/file_type.h>19#include <__filesystem/filesystem_error.h>20#include <__filesystem/operations.h>21#include <__filesystem/path.h>22#include <__filesystem/perms.h>23#include <__fwd/ostream.h>24#include <__system_error/errc.h>25#include <__system_error/error_category.h>26#include <__system_error/error_code.h>27#include <__system_error/error_condition.h>28#include <__utility/move.h>29#include <__utility/unreachable.h>30#include <cstdint>31 32#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)33# pragma GCC system_header34#endif35 36_LIBCPP_PUSH_MACROS37#include <__undef_macros>38 39#if _LIBCPP_STD_VER >= 17 && _LIBCPP_HAS_FILESYSTEM40 41_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM42 43class directory_entry {44 typedef filesystem::path _Path;45 46public:47 // constructors and destructors48 _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 explicit directory_entry(_Path const& __p) : __p_(__p) {53 error_code __ec;54 __refresh(&__ec);55 }56 57 _LIBCPP_HIDE_FROM_ABI directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) { __refresh(&__ec); }58 59 _LIBCPP_HIDE_FROM_ABI ~directory_entry() {}60 61 _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry const&) = default;62 _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry&&) noexcept = default;63 64 _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p) {65 __p_ = __p;66 error_code __ec;67 __refresh(&__ec);68 }69 70 _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p, error_code& __ec) {71 __p_ = __p;72 __refresh(&__ec);73 }74 75 _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p) {76 __p_.replace_filename(__p);77 error_code __ec;78 __refresh(&__ec);79 }80 81 _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p, error_code& __ec) {82 __p_ = __p_.parent_path() / __p;83 __refresh(&__ec);84 }85 86 _LIBCPP_HIDE_FROM_ABI void refresh() { __refresh(); }87 88 _LIBCPP_HIDE_FROM_ABI void refresh(error_code& __ec) noexcept { __refresh(&__ec); }89 90 _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; }91 92 _LIBCPP_HIDE_FROM_ABI operator const _Path&() const noexcept { return __p_; }93 94 _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(file_status{__get_ft()}); }95 96 _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept {97 return filesystem::exists(file_status{__get_ft(&__ec)});98 }99 100 _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; }101 102 _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept {103 return __get_ft(&__ec) == file_type::block;104 }105 106 _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; }107 108 _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept {109 return __get_ft(&__ec) == file_type::character;110 }111 112 _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; }113 114 _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept {115 return __get_ft(&__ec) == file_type::directory;116 }117 118 _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; }119 120 _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::fifo; }121 122 _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(file_status{__get_ft()}); }123 124 _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept {125 return filesystem::is_other(file_status{__get_ft(&__ec)});126 }127 128 _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; }129 130 _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept {131 return __get_ft(&__ec) == file_type::regular;132 }133 134 _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; }135 136 _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::socket; }137 138 _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; }139 140 _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept {141 return __get_sym_ft(&__ec) == file_type::symlink;142 }143 _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); }144 145 _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(&__ec); }146 147 _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); }148 149 _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { return __get_nlink(&__ec); }150 151 _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); }152 153 _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept {154 return __get_write_time(&__ec);155 }156 157 _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); }158 159 _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { return __get_status(&__ec); }160 161 _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); }162 163 _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept {164 return __get_symlink_status(&__ec);165 }166 167 _LIBCPP_HIDE_FROM_ABI bool operator==(directory_entry const& __rhs) const noexcept { return __p_ == __rhs.__p_; }168 169# if _LIBCPP_STD_VER <= 17170 _LIBCPP_HIDE_FROM_ABI bool operator!=(directory_entry const& __rhs) const noexcept { return __p_ != __rhs.__p_; }171 172 _LIBCPP_HIDE_FROM_ABI bool operator<(directory_entry const& __rhs) const noexcept { return __p_ < __rhs.__p_; }173 174 _LIBCPP_HIDE_FROM_ABI bool operator<=(directory_entry const& __rhs) const noexcept { return __p_ <= __rhs.__p_; }175 176 _LIBCPP_HIDE_FROM_ABI bool operator>(directory_entry const& __rhs) const noexcept { return __p_ > __rhs.__p_; }177 178 _LIBCPP_HIDE_FROM_ABI bool operator>=(directory_entry const& __rhs) const noexcept { return __p_ >= __rhs.__p_; }179 180# else // _LIBCPP_STD_VER <= 17181 182 _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const directory_entry& __rhs) const noexcept {183 return __p_ <=> __rhs.__p_;184 }185 186# endif // _LIBCPP_STD_VER <= 17187 188 template <class _CharT, class _Traits>189 _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>&190 operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) {191 return __os << __d.path();192 }193 194private:195 friend class directory_iterator;196 friend class recursive_directory_iterator;197 friend class _LIBCPP_HIDDEN __dir_stream;198 199 enum _CacheType : unsigned char {200 _Empty,201 _IterSymlink,202 _IterNonSymlink,203 _RefreshSymlink,204 _RefreshSymlinkUnresolved,205 _RefreshNonSymlink,206 _IterCachedSymlink,207 _IterCachedNonSymlink208 };209 210 struct __cached_data {211 uintmax_t __size_;212 uintmax_t __nlink_;213 file_time_type __write_time_;214 perms __sym_perms_;215 perms __non_sym_perms_;216 file_type __type_;217 _CacheType __cache_type_;218 219 _LIBCPP_HIDE_FROM_ABI __cached_data() noexcept { __reset(); }220 221 _LIBCPP_HIDE_FROM_ABI void __reset() {222 __cache_type_ = _Empty;223 __type_ = file_type::none;224 __sym_perms_ = __non_sym_perms_ = perms::unknown;225 __size_ = __nlink_ = uintmax_t(-1);226 __write_time_ = file_time_type::min();227 }228 };229 230 _LIBCPP_HIDE_FROM_ABI static __cached_data __create_iter_result(file_type __ft) {231 __cached_data __data;232 __data.__type_ = __ft;233 __data.__cache_type_ = [&]() {234 switch (__ft) {235 case file_type::none:236 return _Empty;237 case file_type::symlink:238 return _IterSymlink;239 default:240 return _IterNonSymlink;241 }242 }();243 return __data;244 }245 246 _LIBCPP_HIDE_FROM_ABI static __cached_data247 __create_iter_cached_result(file_type __ft, uintmax_t __size, perms __perm, file_time_type __write_time) {248 __cached_data __data;249 __data.__type_ = __ft;250 __data.__size_ = __size;251 __data.__write_time_ = __write_time;252 if (__ft == file_type::symlink)253 __data.__sym_perms_ = __perm;254 else255 __data.__non_sym_perms_ = __perm;256 __data.__cache_type_ = [&]() {257 switch (__ft) {258 case file_type::none:259 return _Empty;260 case file_type::symlink:261 return _IterCachedSymlink;262 default:263 return _IterCachedNonSymlink;264 }265 }();266 return __data;267 }268 269 _LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) {270 __p_ = std::move(__p);271 __data_ = __dt;272 }273 274 _LIBCPP_EXPORTED_FROM_ABI error_code __do_refresh() noexcept;275 276 _LIBCPP_HIDE_FROM_ABI static bool __is_dne_error(error_code const& __ec) {277 return !__ec || __ec == errc::no_such_file_or_directory || __ec == errc::not_a_directory;278 }279 280 _LIBCPP_HIDE_FROM_ABI void281 __handle_error(const char* __msg, error_code* __dest_ec, error_code const& __ec, bool __allow_dne = false) const {282 if (__dest_ec) {283 *__dest_ec = __ec;284 return;285 }286 if (__ec && (!__allow_dne || !__is_dne_error(__ec)))287 filesystem::__throw_filesystem_error(__msg, __p_, __ec);288 }289 290 _LIBCPP_HIDE_FROM_ABI void __refresh(error_code* __ec = nullptr) {291 __handle_error("in directory_entry::refresh",292 __ec,293 __do_refresh(),294 /*allow_dne*/ true);295 }296 297 _LIBCPP_HIDE_FROM_ABI file_type __get_sym_ft(error_code* __ec = nullptr) const {298 switch (__data_.__cache_type_) {299 case _Empty:300 return __symlink_status(__p_, __ec).type();301 case _IterSymlink:302 case _IterCachedSymlink:303 case _RefreshSymlink:304 case _RefreshSymlinkUnresolved:305 if (__ec)306 __ec->clear();307 return file_type::symlink;308 case _IterCachedNonSymlink:309 case _IterNonSymlink:310 case _RefreshNonSymlink: {311 file_status __st(__data_.__type_);312 if (__ec && !filesystem::exists(__st))313 *__ec = make_error_code(errc::no_such_file_or_directory);314 else if (__ec)315 __ec->clear();316 return __data_.__type_;317 }318 }319 __libcpp_unreachable();320 }321 322 _LIBCPP_HIDE_FROM_ABI file_type __get_ft(error_code* __ec = nullptr) const {323 switch (__data_.__cache_type_) {324 case _Empty:325 case _IterSymlink:326 case _IterCachedSymlink:327 case _RefreshSymlinkUnresolved:328 return __status(__p_, __ec).type();329 case _IterCachedNonSymlink:330 case _IterNonSymlink:331 case _RefreshNonSymlink:332 case _RefreshSymlink: {333 file_status __st(__data_.__type_);334 if (__ec && !filesystem::exists(__st))335 *__ec = make_error_code(errc::no_such_file_or_directory);336 else if (__ec)337 __ec->clear();338 return __data_.__type_;339 }340 }341 __libcpp_unreachable();342 }343 344 _LIBCPP_HIDE_FROM_ABI file_status __get_status(error_code* __ec = nullptr) const {345 switch (__data_.__cache_type_) {346 case _Empty:347 case _IterNonSymlink:348 case _IterSymlink:349 case _IterCachedSymlink:350 case _RefreshSymlinkUnresolved:351 return __status(__p_, __ec);352 case _IterCachedNonSymlink:353 case _RefreshNonSymlink:354 case _RefreshSymlink:355 return file_status(__get_ft(__ec), __data_.__non_sym_perms_);356 }357 __libcpp_unreachable();358 }359 360 _LIBCPP_HIDE_FROM_ABI file_status __get_symlink_status(error_code* __ec = nullptr) const {361 switch (__data_.__cache_type_) {362 case _Empty:363 case _IterNonSymlink:364 case _IterSymlink:365 return __symlink_status(__p_, __ec);366 case _IterCachedNonSymlink:367 case _RefreshNonSymlink:368 return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);369 case _IterCachedSymlink:370 case _RefreshSymlink:371 case _RefreshSymlinkUnresolved:372 return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);373 }374 __libcpp_unreachable();375 }376 377 _LIBCPP_HIDE_FROM_ABI uintmax_t __get_size(error_code* __ec = nullptr) const {378 switch (__data_.__cache_type_) {379 case _Empty:380 case _IterNonSymlink:381 case _IterSymlink:382 case _IterCachedSymlink:383 case _RefreshSymlinkUnresolved:384 return filesystem::__file_size(__p_, __ec);385 case _IterCachedNonSymlink:386 case _RefreshSymlink:387 case _RefreshNonSymlink: {388 error_code __m_ec;389 file_status __st(__get_ft(&__m_ec));390 __handle_error("in directory_entry::file_size", __ec, __m_ec);391 if (filesystem::exists(__st) && !filesystem::is_regular_file(__st)) {392 errc __err_kind = filesystem::is_directory(__st) ? errc::is_a_directory : errc::not_supported;393 __handle_error("in directory_entry::file_size", __ec, make_error_code(__err_kind));394 }395 return __data_.__size_;396 }397 }398 __libcpp_unreachable();399 }400 401 _LIBCPP_HIDE_FROM_ABI uintmax_t __get_nlink(error_code* __ec = nullptr) const {402 switch (__data_.__cache_type_) {403 case _Empty:404 case _IterNonSymlink:405 case _IterSymlink:406 case _IterCachedNonSymlink:407 case _IterCachedSymlink:408 case _RefreshSymlinkUnresolved:409 return filesystem::__hard_link_count(__p_, __ec);410 case _RefreshSymlink:411 case _RefreshNonSymlink: {412 error_code __m_ec;413 (void)__get_ft(&__m_ec);414 __handle_error("in directory_entry::hard_link_count", __ec, __m_ec);415 return __data_.__nlink_;416 }417 }418 __libcpp_unreachable();419 }420 421 _LIBCPP_HIDE_FROM_ABI file_time_type __get_write_time(error_code* __ec = nullptr) const {422 switch (__data_.__cache_type_) {423 case _Empty:424 case _IterNonSymlink:425 case _IterSymlink:426 case _IterCachedSymlink:427 case _RefreshSymlinkUnresolved:428 return filesystem::__last_write_time(__p_, __ec);429 case _IterCachedNonSymlink:430 case _RefreshSymlink:431 case _RefreshNonSymlink: {432 error_code __m_ec;433 file_status __st(__get_ft(&__m_ec));434 __handle_error("in directory_entry::last_write_time", __ec, __m_ec);435 if (filesystem::exists(__st) && __data_.__write_time_ == file_time_type::min())436 __handle_error("in directory_entry::last_write_time", __ec, make_error_code(errc::value_too_large));437 return __data_.__write_time_;438 }439 }440 __libcpp_unreachable();441 }442 443private:444 _Path __p_;445 __cached_data __data_;446};447 448class __dir_element_proxy {449public:450 inline _LIBCPP_HIDE_FROM_ABI directory_entry operator*() { return std::move(__elem_); }451 452private:453 friend class directory_iterator;454 friend class recursive_directory_iterator;455 _LIBCPP_HIDE_FROM_ABI explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}456 _LIBCPP_HIDE_FROM_ABI __dir_element_proxy(__dir_element_proxy&& __o) : __elem_(std::move(__o.__elem_)) {}457 directory_entry __elem_;458};459 460_LIBCPP_END_NAMESPACE_FILESYSTEM461 462#endif // _LIBCPP_STD_VER >= 17 && _LIBCPP_HAS_FILESYSTEM463 464_LIBCPP_POP_MACROS465 466#endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H467