directory_entry.h 14 KB

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