directory_entry.h 16 KB

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