No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

577 líneas
16KB

  1. // Filesystem directory utilities -*- C++ -*-
  2. // Copyright (C) 2014-2020 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. #if __cplusplus > 201703L
  32. # include <compare> // std::strong_ordering
  33. #endif
  34. namespace std _GLIBCXX_VISIBILITY(default)
  35. {
  36. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  37. namespace filesystem
  38. {
  39. /** @addtogroup filesystem
  40. * @{
  41. */
  42. /// Information about a file's type and permissions.
  43. class file_status
  44. {
  45. public:
  46. // constructors and destructor
  47. file_status() noexcept : file_status(file_type::none) {}
  48. explicit
  49. file_status(file_type __ft, perms __prms = perms::unknown) noexcept
  50. : _M_type(__ft), _M_perms(__prms) { }
  51. file_status(const file_status&) noexcept = default;
  52. file_status(file_status&&) noexcept = default;
  53. ~file_status() = default;
  54. file_status& operator=(const file_status&) noexcept = default;
  55. file_status& operator=(file_status&&) noexcept = default;
  56. // observers
  57. file_type type() const noexcept { return _M_type; }
  58. perms permissions() const noexcept { return _M_perms; }
  59. // modifiers
  60. void type(file_type __ft) noexcept { _M_type = __ft; }
  61. void permissions(perms __prms) noexcept { _M_perms = __prms; }
  62. #if __cpp_lib_three_way_comparison
  63. friend bool
  64. operator==(const file_status&, const file_status&) noexcept = default;
  65. #endif
  66. private:
  67. file_type _M_type;
  68. perms _M_perms;
  69. };
  70. _GLIBCXX_BEGIN_NAMESPACE_CXX11
  71. struct _Dir;
  72. class directory_iterator;
  73. class recursive_directory_iterator;
  74. /// The value type used by directory iterators
  75. class directory_entry
  76. {
  77. public:
  78. // constructors and destructor
  79. directory_entry() noexcept = default;
  80. directory_entry(const directory_entry&) = default;
  81. directory_entry(directory_entry&&) noexcept = default;
  82. explicit
  83. directory_entry(const filesystem::path& __p)
  84. : _M_path(__p)
  85. { refresh(); }
  86. directory_entry(const filesystem::path& __p, error_code& __ec)
  87. : _M_path(__p)
  88. {
  89. refresh(__ec);
  90. if (__ec)
  91. _M_path.clear();
  92. }
  93. ~directory_entry() = default;
  94. // modifiers
  95. directory_entry& operator=(const directory_entry&) = default;
  96. directory_entry& operator=(directory_entry&&) noexcept = default;
  97. void
  98. assign(const filesystem::path& __p)
  99. {
  100. _M_path = __p;
  101. refresh();
  102. }
  103. void
  104. assign(const filesystem::path& __p, error_code& __ec)
  105. {
  106. _M_path = __p;
  107. refresh(__ec);
  108. }
  109. void
  110. replace_filename(const filesystem::path& __p)
  111. {
  112. _M_path.replace_filename(__p);
  113. refresh();
  114. }
  115. void
  116. replace_filename(const filesystem::path& __p, error_code& __ec)
  117. {
  118. _M_path.replace_filename(__p);
  119. refresh(__ec);
  120. }
  121. void
  122. refresh()
  123. { _M_type = symlink_status().type(); }
  124. void
  125. refresh(error_code& __ec) noexcept
  126. { _M_type = symlink_status(__ec).type(); }
  127. // observers
  128. const filesystem::path& path() const noexcept { return _M_path; }
  129. operator const filesystem::path& () const noexcept { return _M_path; }
  130. bool
  131. exists() const
  132. { return filesystem::exists(file_status{_M_file_type()}); }
  133. bool
  134. exists(error_code& __ec) const noexcept
  135. { return filesystem::exists(file_status{_M_file_type(__ec)}); }
  136. bool
  137. is_block_file() const
  138. { return _M_file_type() == file_type::block; }
  139. bool
  140. is_block_file(error_code& __ec) const noexcept
  141. { return _M_file_type(__ec) == file_type::block; }
  142. bool
  143. is_character_file() const
  144. { return _M_file_type() == file_type::character; }
  145. bool
  146. is_character_file(error_code& __ec) const noexcept
  147. { return _M_file_type(__ec) == file_type::character; }
  148. bool
  149. is_directory() const
  150. { return _M_file_type() == file_type::directory; }
  151. bool
  152. is_directory(error_code& __ec) const noexcept
  153. { return _M_file_type(__ec) == file_type::directory; }
  154. bool
  155. is_fifo() const
  156. { return _M_file_type() == file_type::fifo; }
  157. bool
  158. is_fifo(error_code& __ec) const noexcept
  159. { return _M_file_type(__ec) == file_type::fifo; }
  160. bool
  161. is_other() const
  162. { return filesystem::is_other(file_status{_M_file_type()}); }
  163. bool
  164. is_other(error_code& __ec) const noexcept
  165. { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
  166. bool
  167. is_regular_file() const
  168. { return _M_file_type() == file_type::regular; }
  169. bool
  170. is_regular_file(error_code& __ec) const noexcept
  171. { return _M_file_type(__ec) == file_type::regular; }
  172. bool
  173. is_socket() const
  174. { return _M_file_type() == file_type::socket; }
  175. bool
  176. is_socket(error_code& __ec) const noexcept
  177. { return _M_file_type(__ec) == file_type::socket; }
  178. bool
  179. is_symlink() const
  180. {
  181. if (_M_type != file_type::none)
  182. return _M_type == file_type::symlink;
  183. return symlink_status().type() == file_type::symlink;
  184. }
  185. bool
  186. is_symlink(error_code& __ec) const noexcept
  187. {
  188. if (_M_type != file_type::none)
  189. return _M_type == file_type::symlink;
  190. return symlink_status(__ec).type() == file_type::symlink;
  191. }
  192. uintmax_t
  193. file_size() const
  194. { return filesystem::file_size(_M_path); }
  195. uintmax_t
  196. file_size(error_code& __ec) const noexcept
  197. { return filesystem::file_size(_M_path, __ec); }
  198. uintmax_t
  199. hard_link_count() const
  200. { return filesystem::hard_link_count(_M_path); }
  201. uintmax_t
  202. hard_link_count(error_code& __ec) const noexcept
  203. { return filesystem::hard_link_count(_M_path, __ec); }
  204. file_time_type
  205. last_write_time() const
  206. { return filesystem::last_write_time(_M_path); }
  207. file_time_type
  208. last_write_time(error_code& __ec) const noexcept
  209. { return filesystem::last_write_time(_M_path, __ec); }
  210. file_status
  211. status() const
  212. { return filesystem::status(_M_path); }
  213. file_status
  214. status(error_code& __ec) const noexcept
  215. { return filesystem::status(_M_path, __ec); }
  216. file_status
  217. symlink_status() const
  218. { return filesystem::symlink_status(_M_path); }
  219. file_status
  220. symlink_status(error_code& __ec) const noexcept
  221. { return filesystem::symlink_status(_M_path, __ec); }
  222. bool
  223. operator==(const directory_entry& __rhs) const noexcept
  224. { return _M_path == __rhs._M_path; }
  225. #if __cpp_lib_three_way_comparison
  226. strong_ordering
  227. operator<=>(const directory_entry& __rhs) const noexcept
  228. { return _M_path <=> __rhs._M_path; }
  229. #else
  230. bool
  231. operator!=(const directory_entry& __rhs) const noexcept
  232. { return _M_path != __rhs._M_path; }
  233. bool
  234. operator< (const directory_entry& __rhs) const noexcept
  235. { return _M_path < __rhs._M_path; }
  236. bool
  237. operator<=(const directory_entry& __rhs) const noexcept
  238. { return _M_path <= __rhs._M_path; }
  239. bool
  240. operator> (const directory_entry& __rhs) const noexcept
  241. { return _M_path > __rhs._M_path; }
  242. bool
  243. operator>=(const directory_entry& __rhs) const noexcept
  244. { return _M_path >= __rhs._M_path; }
  245. #endif
  246. private:
  247. friend class _Dir;
  248. friend class directory_iterator;
  249. friend class recursive_directory_iterator;
  250. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  251. // 3171. LWG 2989 breaks directory_entry stream insertion
  252. template<typename _CharT, typename _Traits>
  253. friend basic_ostream<_CharT, _Traits>&
  254. operator<<(basic_ostream<_CharT, _Traits>& __os,
  255. const directory_entry& __d)
  256. { return __os << __d.path(); }
  257. directory_entry(const filesystem::path& __p, file_type __t)
  258. : _M_path(__p), _M_type(__t)
  259. { }
  260. // Equivalent to status().type() but uses cached value, if any.
  261. file_type
  262. _M_file_type() const
  263. {
  264. if (_M_type != file_type::none && _M_type != file_type::symlink)
  265. return _M_type;
  266. return status().type();
  267. }
  268. // Equivalent to status(__ec).type() but uses cached value, if any.
  269. file_type
  270. _M_file_type(error_code& __ec) const noexcept
  271. {
  272. if (_M_type != file_type::none && _M_type != file_type::symlink)
  273. {
  274. __ec.clear();
  275. return _M_type;
  276. }
  277. return status(__ec).type();
  278. }
  279. filesystem::path _M_path;
  280. file_type _M_type = file_type::none;
  281. };
  282. /// Proxy returned by post-increment on directory iterators.
  283. struct __directory_iterator_proxy
  284. {
  285. const directory_entry& operator*() const& noexcept { return _M_entry; }
  286. directory_entry operator*() && noexcept { return std::move(_M_entry); }
  287. private:
  288. friend class directory_iterator;
  289. friend class recursive_directory_iterator;
  290. explicit
  291. __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
  292. directory_entry _M_entry;
  293. };
  294. /// Iterator type for traversing the entries in a single directory.
  295. class directory_iterator
  296. {
  297. public:
  298. typedef directory_entry value_type;
  299. typedef ptrdiff_t difference_type;
  300. typedef const directory_entry* pointer;
  301. typedef const directory_entry& reference;
  302. typedef input_iterator_tag iterator_category;
  303. directory_iterator() = default;
  304. explicit
  305. directory_iterator(const path& __p)
  306. : directory_iterator(__p, directory_options::none, nullptr) { }
  307. directory_iterator(const path& __p, directory_options __options)
  308. : directory_iterator(__p, __options, nullptr) { }
  309. directory_iterator(const path& __p, error_code& __ec)
  310. : directory_iterator(__p, directory_options::none, __ec) { }
  311. directory_iterator(const path& __p, directory_options __options,
  312. error_code& __ec)
  313. : directory_iterator(__p, __options, &__ec) { }
  314. directory_iterator(const directory_iterator& __rhs) = default;
  315. directory_iterator(directory_iterator&& __rhs) noexcept = default;
  316. ~directory_iterator() = default;
  317. directory_iterator&
  318. operator=(const directory_iterator& __rhs) = default;
  319. directory_iterator&
  320. operator=(directory_iterator&& __rhs) noexcept = default;
  321. const directory_entry& operator*() const noexcept;
  322. const directory_entry* operator->() const noexcept { return &**this; }
  323. directory_iterator& operator++();
  324. directory_iterator& increment(error_code& __ec);
  325. __directory_iterator_proxy operator++(int)
  326. {
  327. __directory_iterator_proxy __pr{**this};
  328. ++*this;
  329. return __pr;
  330. }
  331. private:
  332. directory_iterator(const path&, directory_options, error_code*);
  333. friend bool
  334. operator==(const directory_iterator& __lhs,
  335. const directory_iterator& __rhs) noexcept
  336. {
  337. return !__rhs._M_dir.owner_before(__lhs._M_dir)
  338. && !__lhs._M_dir.owner_before(__rhs._M_dir);
  339. }
  340. friend bool
  341. operator!=(const directory_iterator& __lhs,
  342. const directory_iterator& __rhs) noexcept
  343. { return !(__lhs == __rhs); }
  344. friend class recursive_directory_iterator;
  345. std::__shared_ptr<_Dir> _M_dir;
  346. };
  347. /// @relates std::filesystem::directory_iterator @{
  348. /** @brief Enable range-based `for` using directory_iterator.
  349. *
  350. * e.g. `for (auto& entry : std::filesystem::directory_iterator(".")) ...`
  351. */
  352. inline directory_iterator
  353. begin(directory_iterator __iter) noexcept
  354. { return __iter; }
  355. /// Return a past-the-end directory_iterator
  356. inline directory_iterator
  357. end(directory_iterator) noexcept
  358. { return directory_iterator(); }
  359. // @}
  360. /// Iterator type for recursively traversing a directory hierarchy.
  361. class recursive_directory_iterator
  362. {
  363. public:
  364. typedef directory_entry value_type;
  365. typedef ptrdiff_t difference_type;
  366. typedef const directory_entry* pointer;
  367. typedef const directory_entry& reference;
  368. typedef input_iterator_tag iterator_category;
  369. recursive_directory_iterator() = default;
  370. explicit
  371. recursive_directory_iterator(const path& __p)
  372. : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
  373. recursive_directory_iterator(const path& __p, directory_options __options)
  374. : recursive_directory_iterator(__p, __options, nullptr) { }
  375. recursive_directory_iterator(const path& __p, directory_options __options,
  376. error_code& __ec)
  377. : recursive_directory_iterator(__p, __options, &__ec) { }
  378. recursive_directory_iterator(const path& __p, error_code& __ec)
  379. : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
  380. recursive_directory_iterator(
  381. const recursive_directory_iterator&) = default;
  382. recursive_directory_iterator(recursive_directory_iterator&&) = default;
  383. ~recursive_directory_iterator();
  384. // observers
  385. directory_options options() const noexcept;
  386. int depth() const noexcept;
  387. bool recursion_pending() const noexcept;
  388. const directory_entry& operator*() const noexcept;
  389. const directory_entry* operator->() const noexcept { return &**this; }
  390. // modifiers
  391. recursive_directory_iterator&
  392. operator=(const recursive_directory_iterator& __rhs) noexcept;
  393. recursive_directory_iterator&
  394. operator=(recursive_directory_iterator&& __rhs) noexcept;
  395. recursive_directory_iterator& operator++();
  396. recursive_directory_iterator& increment(error_code& __ec);
  397. __directory_iterator_proxy operator++(int)
  398. {
  399. __directory_iterator_proxy __pr{**this};
  400. ++*this;
  401. return __pr;
  402. }
  403. void pop();
  404. void pop(error_code&);
  405. void disable_recursion_pending() noexcept;
  406. private:
  407. recursive_directory_iterator(const path&, directory_options, error_code*);
  408. friend bool
  409. operator==(const recursive_directory_iterator& __lhs,
  410. const recursive_directory_iterator& __rhs) noexcept
  411. {
  412. return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
  413. && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
  414. }
  415. friend bool
  416. operator!=(const recursive_directory_iterator& __lhs,
  417. const recursive_directory_iterator& __rhs) noexcept
  418. { return !(__lhs == __rhs); }
  419. struct _Dir_stack;
  420. std::__shared_ptr<_Dir_stack> _M_dirs;
  421. };
  422. /// @relates std::filesystem::recursive_directory_iterator @{
  423. /** @brief Enable range-based `for` using recursive_directory_iterator.
  424. *
  425. * e.g. `for (auto& entry : recursive_directory_iterator(".")) ...`
  426. */
  427. inline recursive_directory_iterator
  428. begin(recursive_directory_iterator __iter) noexcept
  429. { return __iter; }
  430. /// Return a past-the-end recursive_directory_iterator
  431. inline recursive_directory_iterator
  432. end(recursive_directory_iterator) noexcept
  433. { return recursive_directory_iterator(); }
  434. // @}
  435. _GLIBCXX_END_NAMESPACE_CXX11
  436. // @} group filesystem
  437. } // namespace filesystem
  438. // Use explicit instantiations of these types. Any inconsistency in the
  439. // value of __default_lock_policy between code including this header and
  440. // the library will cause a linker error.
  441. extern template class
  442. __shared_ptr<filesystem::_Dir>;
  443. extern template class
  444. __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>;
  445. _GLIBCXX_END_NAMESPACE_VERSION
  446. } // namespace std
  447. #endif // C++17
  448. #endif // _GLIBCXX_FS_DIR_H