fs_dir.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. // Filesystem directory utilities -*- C++ -*-
  2. // Copyright (C) 2014-2018 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file include/bits/fs_dir.h
  21. * This is an internal header file, included by other library headers.
  22. * Do not attempt to use it directly. @headername{filesystem}
  23. */
  24. #ifndef _GLIBCXX_FS_DIR_H
  25. #define _GLIBCXX_FS_DIR_H 1
  26. #if __cplusplus >= 201703L
  27. # include <typeinfo>
  28. # include <ext/concurrence.h>
  29. # include <bits/unique_ptr.h>
  30. # include <bits/shared_ptr.h>
  31. namespace std _GLIBCXX_VISIBILITY(default)
  32. {
  33. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  34. namespace filesystem
  35. {
  36. /**
  37. * @ingroup filesystem
  38. * @{
  39. */
  40. class file_status
  41. {
  42. public:
  43. // constructors and destructor
  44. file_status() noexcept : file_status(file_type::none) {}
  45. explicit
  46. file_status(file_type __ft, perms __prms = perms::unknown) noexcept
  47. : _M_type(__ft), _M_perms(__prms) { }
  48. file_status(const file_status&) noexcept = default;
  49. file_status(file_status&&) noexcept = default;
  50. ~file_status() = default;
  51. file_status& operator=(const file_status&) noexcept = default;
  52. file_status& operator=(file_status&&) noexcept = default;
  53. // observers
  54. file_type type() const noexcept { return _M_type; }
  55. perms permissions() const noexcept { return _M_perms; }
  56. // modifiers
  57. void type(file_type __ft) noexcept { _M_type = __ft; }
  58. void permissions(perms __prms) noexcept { _M_perms = __prms; }
  59. private:
  60. file_type _M_type;
  61. perms _M_perms;
  62. };
  63. _GLIBCXX_BEGIN_NAMESPACE_CXX11
  64. struct _Dir;
  65. class directory_iterator;
  66. class recursive_directory_iterator;
  67. class directory_entry
  68. {
  69. public:
  70. // constructors and destructor
  71. directory_entry() noexcept = default;
  72. directory_entry(const directory_entry&) = default;
  73. directory_entry(directory_entry&&) noexcept = default;
  74. explicit
  75. directory_entry(const filesystem::path& __p)
  76. : _M_path(__p)
  77. { refresh(); }
  78. directory_entry(const filesystem::path& __p, error_code& __ec)
  79. : _M_path(__p)
  80. {
  81. refresh(__ec);
  82. if (__ec)
  83. _M_path.clear();
  84. }
  85. ~directory_entry() = default;
  86. // modifiers
  87. directory_entry& operator=(const directory_entry&) = default;
  88. directory_entry& operator=(directory_entry&&) noexcept = default;
  89. void
  90. assign(const filesystem::path& __p)
  91. {
  92. _M_path = __p;
  93. refresh();
  94. }
  95. void
  96. assign(const filesystem::path& __p, error_code& __ec)
  97. {
  98. _M_path = __p;
  99. refresh(__ec);
  100. }
  101. void
  102. replace_filename(const filesystem::path& __p)
  103. {
  104. _M_path.replace_filename(__p);
  105. refresh();
  106. }
  107. void
  108. replace_filename(const filesystem::path& __p, error_code& __ec)
  109. {
  110. _M_path.replace_filename(__p);
  111. refresh(__ec);
  112. }
  113. void
  114. refresh()
  115. { _M_type = symlink_status().type(); }
  116. void
  117. refresh(error_code& __ec) noexcept
  118. { _M_type = symlink_status(__ec).type(); }
  119. // observers
  120. const filesystem::path& path() const noexcept { return _M_path; }
  121. operator const filesystem::path& () const noexcept { return _M_path; }
  122. bool
  123. exists() const
  124. { return filesystem::exists(file_status{_M_file_type()}); }
  125. bool
  126. exists(error_code& __ec) const noexcept
  127. { return filesystem::exists(file_status{_M_file_type(__ec)}); }
  128. bool
  129. is_block_file() const
  130. { return _M_file_type() == file_type::block; }
  131. bool
  132. is_block_file(error_code& __ec) const noexcept
  133. { return _M_file_type(__ec) == file_type::block; }
  134. bool
  135. is_character_file() const
  136. { return _M_file_type() == file_type::character; }
  137. bool
  138. is_character_file(error_code& __ec) const noexcept
  139. { return _M_file_type(__ec) == file_type::character; }
  140. bool
  141. is_directory() const
  142. { return _M_file_type() == file_type::directory; }
  143. bool
  144. is_directory(error_code& __ec) const noexcept
  145. { return _M_file_type(__ec) == file_type::directory; }
  146. bool
  147. is_fifo() const
  148. { return _M_file_type() == file_type::fifo; }
  149. bool
  150. is_fifo(error_code& __ec) const noexcept
  151. { return _M_file_type(__ec) == file_type::fifo; }
  152. bool
  153. is_other() const
  154. { return filesystem::is_other(file_status{_M_file_type()}); }
  155. bool
  156. is_other(error_code& __ec) const noexcept
  157. { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
  158. bool
  159. is_regular_file() const
  160. { return _M_file_type() == file_type::regular; }
  161. bool
  162. is_regular_file(error_code& __ec) const noexcept
  163. { return _M_file_type(__ec) == file_type::regular; }
  164. bool
  165. is_socket() const
  166. { return _M_file_type() == file_type::socket; }
  167. bool
  168. is_socket(error_code& __ec) const noexcept
  169. { return _M_file_type(__ec) == file_type::socket; }
  170. bool
  171. is_symlink() const
  172. {
  173. if (_M_type != file_type::none)
  174. return _M_type == file_type::symlink;
  175. return symlink_status().type() == file_type::symlink;
  176. }
  177. bool
  178. is_symlink(error_code& __ec) const noexcept
  179. {
  180. if (_M_type != file_type::none)
  181. return _M_type == file_type::symlink;
  182. return symlink_status(__ec).type() == file_type::symlink;
  183. }
  184. uintmax_t
  185. file_size() const
  186. { return filesystem::file_size(_M_path); }
  187. uintmax_t
  188. file_size(error_code& __ec) const noexcept
  189. { return filesystem::file_size(_M_path, __ec); }
  190. uintmax_t
  191. hard_link_count() const
  192. { return filesystem::hard_link_count(_M_path); }
  193. uintmax_t
  194. hard_link_count(error_code& __ec) const noexcept
  195. { return filesystem::hard_link_count(_M_path, __ec); }
  196. file_time_type
  197. last_write_time() const
  198. { return filesystem::last_write_time(_M_path); }
  199. file_time_type
  200. last_write_time(error_code& __ec) const noexcept
  201. { return filesystem::last_write_time(_M_path, __ec); }
  202. file_status
  203. status() const
  204. { return filesystem::status(_M_path); }
  205. file_status
  206. status(error_code& __ec) const noexcept
  207. { return filesystem::status(_M_path, __ec); }
  208. file_status
  209. symlink_status() const
  210. { return filesystem::symlink_status(_M_path); }
  211. file_status
  212. symlink_status(error_code& __ec) const noexcept
  213. { return filesystem::symlink_status(_M_path, __ec); }
  214. bool
  215. operator< (const directory_entry& __rhs) const noexcept
  216. { return _M_path < __rhs._M_path; }
  217. bool
  218. operator==(const directory_entry& __rhs) const noexcept
  219. { return _M_path == __rhs._M_path; }
  220. bool
  221. operator!=(const directory_entry& __rhs) const noexcept
  222. { return _M_path != __rhs._M_path; }
  223. bool
  224. operator<=(const directory_entry& __rhs) const noexcept
  225. { return _M_path <= __rhs._M_path; }
  226. bool
  227. operator> (const directory_entry& __rhs) const noexcept
  228. { return _M_path > __rhs._M_path; }
  229. bool
  230. operator>=(const directory_entry& __rhs) const noexcept
  231. { return _M_path >= __rhs._M_path; }
  232. private:
  233. friend class _Dir;
  234. friend class directory_iterator;
  235. friend class recursive_directory_iterator;
  236. directory_entry(const filesystem::path& __p, file_type __t)
  237. : _M_path(__p), _M_type(__t)
  238. { }
  239. // Equivalent to status().type() but uses cached value, if any.
  240. file_type
  241. _M_file_type() const
  242. {
  243. if (_M_type != file_type::none && _M_type != file_type::symlink)
  244. return _M_type;
  245. return status().type();
  246. }
  247. // Equivalent to status(__ec).type() but uses cached value, if any.
  248. file_type
  249. _M_file_type(error_code& __ec) const noexcept
  250. {
  251. if (_M_type != file_type::none && _M_type != file_type::symlink)
  252. {
  253. __ec.clear();
  254. return _M_type;
  255. }
  256. return status(__ec).type();
  257. }
  258. filesystem::path _M_path;
  259. file_type _M_type = file_type::none;
  260. };
  261. struct __directory_iterator_proxy
  262. {
  263. const directory_entry& operator*() const& noexcept { return _M_entry; }
  264. directory_entry operator*() && noexcept { return std::move(_M_entry); }
  265. private:
  266. friend class directory_iterator;
  267. friend class recursive_directory_iterator;
  268. explicit
  269. __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
  270. directory_entry _M_entry;
  271. };
  272. class directory_iterator
  273. {
  274. public:
  275. typedef directory_entry value_type;
  276. typedef ptrdiff_t difference_type;
  277. typedef const directory_entry* pointer;
  278. typedef const directory_entry& reference;
  279. typedef input_iterator_tag iterator_category;
  280. directory_iterator() = default;
  281. explicit
  282. directory_iterator(const path& __p)
  283. : directory_iterator(__p, directory_options::none, nullptr) { }
  284. directory_iterator(const path& __p, directory_options __options)
  285. : directory_iterator(__p, __options, nullptr) { }
  286. directory_iterator(const path& __p, error_code& __ec)
  287. : directory_iterator(__p, directory_options::none, __ec) { }
  288. directory_iterator(const path& __p, directory_options __options,
  289. error_code& __ec)
  290. : directory_iterator(__p, __options, &__ec) { }
  291. directory_iterator(const directory_iterator& __rhs) = default;
  292. directory_iterator(directory_iterator&& __rhs) noexcept = default;
  293. ~directory_iterator() = default;
  294. directory_iterator&
  295. operator=(const directory_iterator& __rhs) = default;
  296. directory_iterator&
  297. operator=(directory_iterator&& __rhs) noexcept = default;
  298. const directory_entry& operator*() const;
  299. const directory_entry* operator->() const { return &**this; }
  300. directory_iterator& operator++();
  301. directory_iterator& increment(error_code& __ec);
  302. __directory_iterator_proxy operator++(int)
  303. {
  304. __directory_iterator_proxy __pr{**this};
  305. ++*this;
  306. return __pr;
  307. }
  308. private:
  309. directory_iterator(const path&, directory_options, error_code*);
  310. friend bool
  311. operator==(const directory_iterator& __lhs,
  312. const directory_iterator& __rhs);
  313. friend class recursive_directory_iterator;
  314. std::shared_ptr<_Dir> _M_dir;
  315. };
  316. inline directory_iterator
  317. begin(directory_iterator __iter) noexcept
  318. { return __iter; }
  319. inline directory_iterator
  320. end(directory_iterator) noexcept
  321. { return directory_iterator(); }
  322. inline bool
  323. operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
  324. {
  325. return !__rhs._M_dir.owner_before(__lhs._M_dir)
  326. && !__lhs._M_dir.owner_before(__rhs._M_dir);
  327. }
  328. inline bool
  329. operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
  330. { return !(__lhs == __rhs); }
  331. class recursive_directory_iterator
  332. {
  333. public:
  334. typedef directory_entry value_type;
  335. typedef ptrdiff_t difference_type;
  336. typedef const directory_entry* pointer;
  337. typedef const directory_entry& reference;
  338. typedef input_iterator_tag iterator_category;
  339. recursive_directory_iterator() = default;
  340. explicit
  341. recursive_directory_iterator(const path& __p)
  342. : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
  343. recursive_directory_iterator(const path& __p, directory_options __options)
  344. : recursive_directory_iterator(__p, __options, nullptr) { }
  345. recursive_directory_iterator(const path& __p, directory_options __options,
  346. error_code& __ec)
  347. : recursive_directory_iterator(__p, __options, &__ec) { }
  348. recursive_directory_iterator(const path& __p, error_code& __ec)
  349. : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
  350. recursive_directory_iterator(
  351. const recursive_directory_iterator&) = default;
  352. recursive_directory_iterator(recursive_directory_iterator&&) = default;
  353. ~recursive_directory_iterator();
  354. // observers
  355. directory_options options() const { return _M_options; }
  356. int depth() const;
  357. bool recursion_pending() const { return _M_pending; }
  358. const directory_entry& operator*() const;
  359. const directory_entry* operator->() const { return &**this; }
  360. // modifiers
  361. recursive_directory_iterator&
  362. operator=(const recursive_directory_iterator& __rhs) noexcept;
  363. recursive_directory_iterator&
  364. operator=(recursive_directory_iterator&& __rhs) noexcept;
  365. recursive_directory_iterator& operator++();
  366. recursive_directory_iterator& increment(error_code& __ec);
  367. __directory_iterator_proxy operator++(int)
  368. {
  369. __directory_iterator_proxy __pr{**this};
  370. ++*this;
  371. return __pr;
  372. }
  373. void pop();
  374. void pop(error_code&);
  375. void disable_recursion_pending() { _M_pending = false; }
  376. private:
  377. recursive_directory_iterator(const path&, directory_options, error_code*);
  378. friend bool
  379. operator==(const recursive_directory_iterator& __lhs,
  380. const recursive_directory_iterator& __rhs);
  381. struct _Dir_stack;
  382. std::shared_ptr<_Dir_stack> _M_dirs;
  383. directory_options _M_options = {};
  384. bool _M_pending = false;
  385. };
  386. inline recursive_directory_iterator
  387. begin(recursive_directory_iterator __iter) noexcept
  388. { return __iter; }
  389. inline recursive_directory_iterator
  390. end(recursive_directory_iterator) noexcept
  391. { return recursive_directory_iterator(); }
  392. inline bool
  393. operator==(const recursive_directory_iterator& __lhs,
  394. const recursive_directory_iterator& __rhs)
  395. {
  396. return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
  397. && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
  398. }
  399. inline bool
  400. operator!=(const recursive_directory_iterator& __lhs,
  401. const recursive_directory_iterator& __rhs)
  402. { return !(__lhs == __rhs); }
  403. _GLIBCXX_END_NAMESPACE_CXX11
  404. // @} group filesystem
  405. } // namespace filesystem
  406. _GLIBCXX_END_NAMESPACE_VERSION
  407. } // namespace std
  408. #endif // C++17
  409. #endif // _GLIBCXX_FS_DIR_H