directory.hpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. // boost/filesystem/directory.hpp ---------------------------------------------------//
  2. // Copyright Beman Dawes 2002-2009
  3. // Copyright Jan Langer 2002
  4. // Copyright Dietmar Kuehl 2001
  5. // Copyright Vladimir Prus 2002
  6. // Copyright Andrey Semashev 2019-2025
  7. // Distributed under the Boost Software License, Version 1.0.
  8. // See http://www.boost.org/LICENSE_1_0.txt
  9. // Library home page: http://www.boost.org/libs/filesystem
  10. //--------------------------------------------------------------------------------------//
  11. #ifndef BOOST_FILESYSTEM_DIRECTORY_HPP
  12. #define BOOST_FILESYSTEM_DIRECTORY_HPP
  13. #include <boost/filesystem/config.hpp>
  14. #include <boost/filesystem/path.hpp>
  15. #include <boost/filesystem/file_status.hpp>
  16. #include <boost/filesystem/detail/path_traits.hpp>
  17. #include <cstddef>
  18. #include <string>
  19. #include <vector>
  20. #include <boost/assert.hpp>
  21. #include <boost/detail/bitmask.hpp>
  22. #include <boost/system/error_code.hpp>
  23. #include <boost/smart_ptr/intrusive_ptr.hpp>
  24. #include <boost/smart_ptr/intrusive_ref_counter.hpp>
  25. #include <boost/iterator/iterator_facade.hpp>
  26. #include <boost/iterator/iterator_categories.hpp>
  27. #include <boost/filesystem/detail/header.hpp> // must be the last #include
  28. #if defined(BOOST_GCC) && (__GNUC__ == 12)
  29. #pragma GCC diagnostic push
  30. // 'function' redeclared without dllimport attribute: previous dllimport ignored
  31. // gcc bug on MinGW-w64 and Cygwin: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106395
  32. #pragma GCC diagnostic ignored "-Wattributes"
  33. #endif
  34. //--------------------------------------------------------------------------------------//
  35. namespace boost {
  36. namespace filesystem {
  37. enum class directory_options : unsigned int
  38. {
  39. none = 0u,
  40. skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty
  41. follow_directory_symlink = 1u << 1u, // recursive_directory_iterator: follow directory symlinks
  42. skip_dangling_symlinks = 1u << 2u, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks,
  43. pop_on_error = 1u << 3u, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors,
  44. // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator
  45. _detail_no_follow = 1u << 4u, // internal use only
  46. _detail_no_push = 1u << 5u // internal use only
  47. };
  48. BOOST_BITMASK(directory_options)
  49. class directory_iterator;
  50. class recursive_directory_iterator;
  51. namespace detail {
  52. struct directory_iterator_params;
  53. BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, directory_iterator_params* params, system::error_code* ec);
  54. BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec);
  55. struct recur_dir_itr_imp;
  56. BOOST_FILESYSTEM_DECL void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec);
  57. BOOST_FILESYSTEM_DECL void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
  58. BOOST_FILESYSTEM_DECL void recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec);
  59. } // namespace detail
  60. //--------------------------------------------------------------------------------------//
  61. // //
  62. // directory_entry //
  63. // //
  64. //--------------------------------------------------------------------------------------//
  65. // GCC has a problem with a member function named path within a namespace or
  66. // sub-namespace that also has a class named path. The workaround is to always
  67. // fully qualify the name path when it refers to the class name.
  68. class directory_entry
  69. {
  70. friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, detail::directory_iterator_params* params, system::error_code* ec);
  71. friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec);
  72. friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
  73. public:
  74. typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry
  75. directory_entry() noexcept {}
  76. explicit directory_entry(boost::filesystem::path const& p);
  77. #if BOOST_FILESYSTEM_VERSION >= 4
  78. directory_entry(boost::filesystem::path const& p, system::error_code& ec) :
  79. m_path(p)
  80. {
  81. refresh_impl(&ec);
  82. if (ec)
  83. m_path.clear();
  84. }
  85. #else
  86. directory_entry(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) :
  87. m_path(p), m_status(st), m_symlink_status(symlink_st)
  88. {
  89. }
  90. #endif
  91. directory_entry(directory_entry const& rhs) :
  92. m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status)
  93. {
  94. }
  95. directory_entry& operator=(directory_entry const& rhs)
  96. {
  97. m_path = rhs.m_path;
  98. m_status = rhs.m_status;
  99. m_symlink_status = rhs.m_symlink_status;
  100. return *this;
  101. }
  102. directory_entry(directory_entry&& rhs) noexcept :
  103. m_path(static_cast< boost::filesystem::path&& >(rhs.m_path)),
  104. m_status(static_cast< file_status&& >(rhs.m_status)),
  105. m_symlink_status(static_cast< file_status&& >(rhs.m_symlink_status))
  106. {
  107. }
  108. directory_entry& operator=(directory_entry&& rhs) noexcept
  109. {
  110. m_path = static_cast< boost::filesystem::path&& >(rhs.m_path);
  111. m_status = static_cast< file_status&& >(rhs.m_status);
  112. m_symlink_status = static_cast< file_status&& >(rhs.m_symlink_status);
  113. return *this;
  114. }
  115. void assign(boost::filesystem::path&& p);
  116. #if BOOST_FILESYSTEM_VERSION >= 4
  117. void assign(boost::filesystem::path&& p, system::error_code& ec)
  118. {
  119. m_path = static_cast< boost::filesystem::path&& >(p);
  120. refresh_impl(&ec);
  121. }
  122. #else
  123. void assign(boost::filesystem::path&& p, file_status st, file_status symlink_st = file_status())
  124. {
  125. assign_with_status(static_cast< boost::filesystem::path&& >(p), st, symlink_st);
  126. }
  127. #endif
  128. void assign(boost::filesystem::path const& p);
  129. #if BOOST_FILESYSTEM_VERSION >= 4
  130. void assign(boost::filesystem::path const& p, system::error_code& ec)
  131. {
  132. m_path = p;
  133. refresh_impl(&ec);
  134. }
  135. #else
  136. void assign(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status())
  137. {
  138. assign_with_status(p, st, symlink_st);
  139. }
  140. #endif
  141. void replace_filename(boost::filesystem::path const& p);
  142. #if BOOST_FILESYSTEM_VERSION >= 4
  143. void replace_filename(boost::filesystem::path const& p, system::error_code& ec)
  144. {
  145. m_path.replace_filename(p);
  146. refresh_impl(&ec);
  147. }
  148. #else
  149. void replace_filename(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status())
  150. {
  151. replace_filename_with_status(p, st, symlink_st);
  152. }
  153. BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead")
  154. void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st)
  155. {
  156. replace_filename_with_status(p, st, symlink_st);
  157. }
  158. #endif
  159. boost::filesystem::path const& path() const noexcept { return m_path; }
  160. operator boost::filesystem::path const&() const noexcept { return m_path; }
  161. void refresh() { refresh_impl(); }
  162. void refresh(system::error_code& ec) noexcept { refresh_impl(&ec); }
  163. file_status status() const
  164. {
  165. if (!filesystem::status_known(m_status))
  166. refresh_impl();
  167. return m_status;
  168. }
  169. file_status status(system::error_code& ec) const noexcept
  170. {
  171. ec.clear();
  172. if (!filesystem::status_known(m_status))
  173. refresh_impl(&ec);
  174. return m_status;
  175. }
  176. file_status symlink_status() const
  177. {
  178. if (!filesystem::status_known(m_symlink_status))
  179. refresh_impl();
  180. return m_symlink_status;
  181. }
  182. file_status symlink_status(system::error_code& ec) const noexcept
  183. {
  184. ec.clear();
  185. if (!filesystem::status_known(m_symlink_status))
  186. refresh_impl(&ec);
  187. return m_symlink_status;
  188. }
  189. filesystem::file_type file_type() const
  190. {
  191. if (!filesystem::type_present(m_status))
  192. refresh_impl();
  193. return m_status.type();
  194. }
  195. filesystem::file_type file_type(system::error_code& ec) const noexcept
  196. {
  197. ec.clear();
  198. if (!filesystem::type_present(m_status))
  199. refresh_impl(&ec);
  200. return m_status.type();
  201. }
  202. filesystem::file_type symlink_file_type() const
  203. {
  204. if (!filesystem::type_present(m_symlink_status))
  205. refresh_impl();
  206. return m_symlink_status.type();
  207. }
  208. filesystem::file_type symlink_file_type(system::error_code& ec) const noexcept
  209. {
  210. ec.clear();
  211. if (!filesystem::type_present(m_symlink_status))
  212. refresh_impl(&ec);
  213. return m_symlink_status.type();
  214. }
  215. bool exists() const
  216. {
  217. filesystem::file_type ft = this->file_type();
  218. return ft != filesystem::status_error && ft != filesystem::file_not_found;
  219. }
  220. bool exists(system::error_code& ec) const noexcept
  221. {
  222. filesystem::file_type ft = this->file_type(ec);
  223. return ft != filesystem::status_error && ft != filesystem::file_not_found;
  224. }
  225. bool is_regular_file() const
  226. {
  227. return this->file_type() == filesystem::regular_file;
  228. }
  229. bool is_regular_file(system::error_code& ec) const noexcept
  230. {
  231. return this->file_type(ec) == filesystem::regular_file;
  232. }
  233. bool is_directory() const
  234. {
  235. return this->file_type() == filesystem::directory_file;
  236. }
  237. bool is_directory(system::error_code& ec) const noexcept
  238. {
  239. return this->file_type(ec) == filesystem::directory_file;
  240. }
  241. bool is_symlink() const
  242. {
  243. return this->symlink_file_type() == filesystem::symlink_file;
  244. }
  245. bool is_symlink(system::error_code& ec) const noexcept
  246. {
  247. return this->symlink_file_type(ec) == filesystem::symlink_file;
  248. }
  249. bool is_block_file() const
  250. {
  251. return this->file_type() == filesystem::block_file;
  252. }
  253. bool is_block_file(system::error_code& ec) const noexcept
  254. {
  255. return this->file_type(ec) == filesystem::block_file;
  256. }
  257. bool is_character_file() const
  258. {
  259. return this->file_type() == filesystem::character_file;
  260. }
  261. bool is_character_file(system::error_code& ec) const noexcept
  262. {
  263. return this->file_type(ec) == filesystem::character_file;
  264. }
  265. bool is_fifo() const
  266. {
  267. return this->file_type() == filesystem::fifo_file;
  268. }
  269. bool is_fifo(system::error_code& ec) const noexcept
  270. {
  271. return this->file_type(ec) == filesystem::fifo_file;
  272. }
  273. bool is_socket() const
  274. {
  275. return this->file_type() == filesystem::socket_file;
  276. }
  277. bool is_socket(system::error_code& ec) const noexcept
  278. {
  279. return this->file_type(ec) == filesystem::socket_file;
  280. }
  281. bool is_reparse_file() const
  282. {
  283. return this->symlink_file_type() == filesystem::reparse_file;
  284. }
  285. bool is_reparse_file(system::error_code& ec) const noexcept
  286. {
  287. return this->symlink_file_type(ec) == filesystem::reparse_file;
  288. }
  289. bool is_other() const
  290. {
  291. filesystem::file_type ft = this->file_type();
  292. return ft != filesystem::status_error && ft != filesystem::file_not_found &&
  293. ft != filesystem::regular_file && ft != filesystem::directory_file;
  294. }
  295. bool is_other(system::error_code& ec) const noexcept
  296. {
  297. filesystem::file_type ft = this->file_type(ec);
  298. return ft != filesystem::status_error && ft != filesystem::file_not_found &&
  299. ft != filesystem::regular_file && ft != filesystem::directory_file;
  300. }
  301. bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; }
  302. bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; }
  303. bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; }
  304. bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; }
  305. bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; }
  306. bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; }
  307. private:
  308. BOOST_FILESYSTEM_DECL void refresh_impl(system::error_code* ec = nullptr) const;
  309. void assign_with_status(boost::filesystem::path&& p, file_status st, file_status symlink_st)
  310. {
  311. m_path = static_cast< boost::filesystem::path&& >(p);
  312. m_status = static_cast< file_status&& >(st);
  313. m_symlink_status = static_cast< file_status&& >(symlink_st);
  314. }
  315. void assign_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st)
  316. {
  317. m_path = p;
  318. m_status = static_cast< file_status&& >(st);
  319. m_symlink_status = static_cast< file_status&& >(symlink_st);
  320. }
  321. void replace_filename_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st)
  322. {
  323. m_path.replace_filename(p);
  324. m_status = static_cast< file_status&& >(st);
  325. m_symlink_status = static_cast< file_status&& >(symlink_st);
  326. }
  327. private:
  328. boost::filesystem::path m_path;
  329. mutable file_status m_status; // stat()-like
  330. mutable file_status m_symlink_status; // lstat()-like
  331. };
  332. #if !defined(BOOST_FILESYSTEM_SOURCE)
  333. inline directory_entry::directory_entry(boost::filesystem::path const& p) :
  334. m_path(p)
  335. {
  336. #if BOOST_FILESYSTEM_VERSION >= 4
  337. refresh_impl();
  338. #endif
  339. }
  340. inline void directory_entry::assign(boost::filesystem::path&& p)
  341. {
  342. m_path = static_cast< boost::filesystem::path&& >(p);
  343. #if BOOST_FILESYSTEM_VERSION >= 4
  344. refresh_impl();
  345. #else
  346. m_status = file_status();
  347. m_symlink_status = file_status();
  348. #endif
  349. }
  350. inline void directory_entry::assign(boost::filesystem::path const& p)
  351. {
  352. m_path = p;
  353. #if BOOST_FILESYSTEM_VERSION >= 4
  354. refresh_impl();
  355. #else
  356. m_status = file_status();
  357. m_symlink_status = file_status();
  358. #endif
  359. }
  360. inline void directory_entry::replace_filename(boost::filesystem::path const& p)
  361. {
  362. m_path.replace_filename(p);
  363. #if BOOST_FILESYSTEM_VERSION >= 4
  364. refresh_impl();
  365. #else
  366. m_status = file_status();
  367. m_symlink_status = file_status();
  368. #endif
  369. }
  370. #endif // !defined(BOOST_FILESYSTEM_SOURCE)
  371. namespace detail {
  372. namespace path_traits {
  373. // Dispatch function for integration with path class
  374. template< typename Callback >
  375. BOOST_FORCEINLINE typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag)
  376. {
  377. boost::filesystem::path::string_type const& source = de.path().native();
  378. return cb(source.data(), source.data() + source.size(), cvt);
  379. }
  380. } // namespace path_traits
  381. } // namespace detail
  382. //--------------------------------------------------------------------------------------//
  383. // //
  384. // directory_entry overloads //
  385. // //
  386. //--------------------------------------------------------------------------------------//
  387. // Without these functions, calling (for example) 'is_directory' with a 'directory_entry' results in:
  388. // - a conversion to 'path' using 'operator boost::filesystem::path const&()',
  389. // - then a call to 'is_directory(path const& p)' which recomputes the status with 'detail::status(p)'.
  390. //
  391. // These functions avoid a costly recomputation of the status if one calls 'is_directory(e)' instead of 'is_directory(e.status())'
  392. inline file_status status(directory_entry const& e)
  393. {
  394. return e.status();
  395. }
  396. inline file_status status(directory_entry const& e, system::error_code& ec) noexcept
  397. {
  398. return e.status(ec);
  399. }
  400. inline file_status symlink_status(directory_entry const& e)
  401. {
  402. return e.symlink_status();
  403. }
  404. inline file_status symlink_status(directory_entry const& e, system::error_code& ec) noexcept
  405. {
  406. return e.symlink_status(ec);
  407. }
  408. inline bool type_present(directory_entry const& e)
  409. {
  410. return e.file_type() != filesystem::status_error;
  411. }
  412. inline bool type_present(directory_entry const& e, system::error_code& ec) noexcept
  413. {
  414. return e.file_type(ec) != filesystem::status_error;
  415. }
  416. inline bool status_known(directory_entry const& e)
  417. {
  418. return filesystem::status_known(e.status());
  419. }
  420. inline bool status_known(directory_entry const& e, system::error_code& ec) noexcept
  421. {
  422. return filesystem::status_known(e.status(ec));
  423. }
  424. inline bool exists(directory_entry const& e)
  425. {
  426. return e.exists();
  427. }
  428. inline bool exists(directory_entry const& e, system::error_code& ec) noexcept
  429. {
  430. return e.exists(ec);
  431. }
  432. inline bool is_regular_file(directory_entry const& e)
  433. {
  434. return e.is_regular_file();
  435. }
  436. inline bool is_regular_file(directory_entry const& e, system::error_code& ec) noexcept
  437. {
  438. return e.is_regular_file(ec);
  439. }
  440. inline bool is_directory(directory_entry const& e)
  441. {
  442. return e.is_directory();
  443. }
  444. inline bool is_directory(directory_entry const& e, system::error_code& ec) noexcept
  445. {
  446. return e.is_directory(ec);
  447. }
  448. inline bool is_symlink(directory_entry const& e)
  449. {
  450. return e.is_symlink();
  451. }
  452. inline bool is_symlink(directory_entry const& e, system::error_code& ec) noexcept
  453. {
  454. return e.is_symlink(ec);
  455. }
  456. inline bool is_block_file(directory_entry const& e)
  457. {
  458. return e.is_block_file();
  459. }
  460. inline bool is_block_file(directory_entry const& e, system::error_code& ec) noexcept
  461. {
  462. return e.is_block_file(ec);
  463. }
  464. inline bool is_character_file(directory_entry const& e)
  465. {
  466. return e.is_character_file();
  467. }
  468. inline bool is_character_file(directory_entry const& e, system::error_code& ec) noexcept
  469. {
  470. return e.is_character_file(ec);
  471. }
  472. inline bool is_fifo(directory_entry const& e)
  473. {
  474. return e.is_fifo();
  475. }
  476. inline bool is_fifo(directory_entry const& e, system::error_code& ec) noexcept
  477. {
  478. return e.is_fifo(ec);
  479. }
  480. inline bool is_socket(directory_entry const& e)
  481. {
  482. return e.is_socket();
  483. }
  484. inline bool is_socket(directory_entry const& e, system::error_code& ec) noexcept
  485. {
  486. return e.is_socket(ec);
  487. }
  488. inline bool is_reparse_file(directory_entry const& e)
  489. {
  490. return e.is_reparse_file();
  491. }
  492. inline bool is_reparse_file(directory_entry const& e, system::error_code& ec) noexcept
  493. {
  494. return e.is_reparse_file(ec);
  495. }
  496. inline bool is_other(directory_entry const& e)
  497. {
  498. return e.is_other();
  499. }
  500. inline bool is_other(directory_entry const& e, system::error_code& ec) noexcept
  501. {
  502. return e.is_other(ec);
  503. }
  504. //--------------------------------------------------------------------------------------//
  505. // //
  506. // directory_iterator helpers //
  507. // //
  508. //--------------------------------------------------------------------------------------//
  509. namespace detail {
  510. struct dir_itr_imp :
  511. public boost::intrusive_ref_counter< dir_itr_imp >
  512. {
  513. #ifdef BOOST_WINDOWS_API
  514. bool close_handle;
  515. unsigned char extra_data_format;
  516. std::size_t current_offset;
  517. #endif
  518. directory_entry dir_entry;
  519. void* handle;
  520. dir_itr_imp() noexcept :
  521. #ifdef BOOST_WINDOWS_API
  522. close_handle(false),
  523. extra_data_format(0u),
  524. current_offset(0u),
  525. #endif
  526. handle(nullptr)
  527. {
  528. }
  529. BOOST_FILESYSTEM_DECL ~dir_itr_imp() noexcept;
  530. BOOST_FILESYSTEM_DECL static void* operator new(std::size_t class_size, std::size_t extra_size) noexcept;
  531. BOOST_FILESYSTEM_DECL static void operator delete(void* p, std::size_t extra_size) noexcept;
  532. BOOST_FILESYSTEM_DECL static void operator delete(void* p) noexcept;
  533. };
  534. } // namespace detail
  535. //--------------------------------------------------------------------------------------//
  536. // //
  537. // directory_iterator //
  538. // //
  539. //--------------------------------------------------------------------------------------//
  540. class directory_iterator :
  541. public boost::iterator_facade<
  542. directory_iterator,
  543. directory_entry,
  544. boost::single_pass_traversal_tag
  545. >
  546. {
  547. friend class boost::iterator_core_access;
  548. friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, detail::directory_iterator_params* params, system::error_code* ec);
  549. friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec);
  550. friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
  551. public:
  552. directory_iterator() noexcept {} // creates the "end" iterator
  553. // iterator_facade derived classes don't seem to like implementations in
  554. // separate translation unit dll's, so forward to detail functions
  555. explicit directory_iterator(path const& p, directory_options opts = directory_options::none)
  556. {
  557. detail::directory_iterator_construct(*this, p, opts, nullptr, nullptr);
  558. }
  559. directory_iterator(path const& p, system::error_code& ec) noexcept
  560. {
  561. detail::directory_iterator_construct(*this, p, directory_options::none, nullptr, &ec);
  562. }
  563. directory_iterator(path const& p, directory_options opts, system::error_code& ec) noexcept
  564. {
  565. detail::directory_iterator_construct(*this, p, opts, nullptr, &ec);
  566. }
  567. directory_iterator(directory_iterator const&) = default;
  568. directory_iterator& operator=(directory_iterator const&) = default;
  569. directory_iterator(directory_iterator&& that) noexcept :
  570. m_imp(static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp))
  571. {
  572. }
  573. directory_iterator& operator=(directory_iterator&& that) noexcept
  574. {
  575. m_imp = static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp);
  576. return *this;
  577. }
  578. directory_iterator& increment(system::error_code& ec) noexcept
  579. {
  580. detail::directory_iterator_increment(*this, &ec);
  581. return *this;
  582. }
  583. private:
  584. boost::iterator_facade<
  585. directory_iterator,
  586. directory_entry,
  587. boost::single_pass_traversal_tag
  588. >::reference dereference() const
  589. {
  590. BOOST_ASSERT_MSG(!is_end(), "attempt to dereference end directory iterator");
  591. return m_imp->dir_entry;
  592. }
  593. void increment() { detail::directory_iterator_increment(*this, nullptr); }
  594. bool equal(directory_iterator const& rhs) const noexcept
  595. {
  596. return m_imp == rhs.m_imp || (is_end() && rhs.is_end());
  597. }
  598. bool is_end() const noexcept
  599. {
  600. // Note: The check for handle is needed because the iterator can be copied and the copy
  601. // can be incremented to end while the original iterator still refers to the same dir_itr_imp.
  602. return !m_imp || !m_imp->handle;
  603. }
  604. private:
  605. // intrusive_ptr provides the shallow-copy semantics required for single pass iterators
  606. // (i.e. InputIterators). The end iterator is indicated by is_end().
  607. boost::intrusive_ptr< detail::dir_itr_imp > m_imp;
  608. };
  609. // enable directory_iterator C++11 range-based for statement use --------------------//
  610. // begin() and end() are only used by a range-based for statement in the context of
  611. // auto - thus the top-level const is stripped - so returning const is harmless and
  612. // emphasizes begin() is just a pass through.
  613. inline directory_iterator const& begin(directory_iterator const& iter) noexcept
  614. {
  615. return iter;
  616. }
  617. inline directory_iterator end(directory_iterator const&) noexcept
  618. {
  619. return directory_iterator();
  620. }
  621. // enable C++14 generic accessors for range const iterators
  622. inline directory_iterator const& cbegin(directory_iterator const& iter) noexcept
  623. {
  624. return iter;
  625. }
  626. inline directory_iterator cend(directory_iterator const&) noexcept
  627. {
  628. return directory_iterator();
  629. }
  630. // enable directory_iterator BOOST_FOREACH -----------------------------------------//
  631. inline directory_iterator& range_begin(directory_iterator& iter) noexcept
  632. {
  633. return iter;
  634. }
  635. inline directory_iterator range_begin(directory_iterator const& iter) noexcept
  636. {
  637. return iter;
  638. }
  639. inline directory_iterator range_end(directory_iterator&) noexcept
  640. {
  641. return directory_iterator();
  642. }
  643. inline directory_iterator range_end(directory_iterator const&) noexcept
  644. {
  645. return directory_iterator();
  646. }
  647. } // namespace filesystem
  648. // namespace boost template specializations
  649. template< typename C, typename Enabler >
  650. struct range_mutable_iterator;
  651. template<>
  652. struct range_mutable_iterator< boost::filesystem::directory_iterator, void >
  653. {
  654. typedef boost::filesystem::directory_iterator type;
  655. };
  656. template< typename C, typename Enabler >
  657. struct range_const_iterator;
  658. template<>
  659. struct range_const_iterator< boost::filesystem::directory_iterator, void >
  660. {
  661. typedef boost::filesystem::directory_iterator type;
  662. };
  663. namespace filesystem {
  664. //--------------------------------------------------------------------------------------//
  665. // //
  666. // recursive_directory_iterator helpers //
  667. // //
  668. //--------------------------------------------------------------------------------------//
  669. namespace detail {
  670. struct recur_dir_itr_imp :
  671. public boost::intrusive_ref_counter< recur_dir_itr_imp >
  672. {
  673. typedef directory_iterator element_type;
  674. std::vector< element_type > m_stack;
  675. directory_options m_options;
  676. explicit recur_dir_itr_imp(directory_options opts) noexcept : m_options(opts) {}
  677. };
  678. } // namespace detail
  679. //--------------------------------------------------------------------------------------//
  680. // //
  681. // recursive_directory_iterator //
  682. // //
  683. //--------------------------------------------------------------------------------------//
  684. class recursive_directory_iterator :
  685. public boost::iterator_facade<
  686. recursive_directory_iterator,
  687. directory_entry,
  688. boost::single_pass_traversal_tag
  689. >
  690. {
  691. friend class boost::iterator_core_access;
  692. friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec);
  693. friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
  694. friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec);
  695. public:
  696. recursive_directory_iterator() noexcept {} // creates the "end" iterator
  697. explicit recursive_directory_iterator(path const& dir_path)
  698. {
  699. detail::recursive_directory_iterator_construct(*this, dir_path, directory_options::none, nullptr);
  700. }
  701. recursive_directory_iterator(path const& dir_path, system::error_code& ec)
  702. {
  703. detail::recursive_directory_iterator_construct(*this, dir_path, directory_options::none, &ec);
  704. }
  705. recursive_directory_iterator(path const& dir_path, directory_options opts)
  706. {
  707. detail::recursive_directory_iterator_construct(*this, dir_path, opts, nullptr);
  708. }
  709. recursive_directory_iterator(path const& dir_path, directory_options opts, system::error_code& ec)
  710. {
  711. detail::recursive_directory_iterator_construct(*this, dir_path, opts, &ec);
  712. }
  713. recursive_directory_iterator(recursive_directory_iterator const&) = default;
  714. recursive_directory_iterator& operator=(recursive_directory_iterator const&) = default;
  715. recursive_directory_iterator(recursive_directory_iterator&& that) noexcept :
  716. m_imp(static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp))
  717. {
  718. }
  719. recursive_directory_iterator& operator=(recursive_directory_iterator&& that) noexcept
  720. {
  721. m_imp = static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp);
  722. return *this;
  723. }
  724. recursive_directory_iterator& increment(system::error_code& ec) noexcept
  725. {
  726. detail::recursive_directory_iterator_increment(*this, &ec);
  727. return *this;
  728. }
  729. int depth() const noexcept
  730. {
  731. BOOST_ASSERT_MSG(!is_end(), "depth() on end recursive_directory_iterator");
  732. return static_cast< int >(m_imp->m_stack.size() - 1u);
  733. }
  734. bool recursion_pending() const noexcept
  735. {
  736. BOOST_ASSERT_MSG(!is_end(), "recursion_pending() on end recursive_directory_iterator");
  737. return (m_imp->m_options & directory_options::_detail_no_push) == directory_options::none;
  738. }
  739. void pop()
  740. {
  741. detail::recursive_directory_iterator_pop(*this, nullptr);
  742. }
  743. void pop(system::error_code& ec) noexcept
  744. {
  745. detail::recursive_directory_iterator_pop(*this, &ec);
  746. }
  747. void disable_recursion_pending(bool value = true) noexcept
  748. {
  749. BOOST_ASSERT_MSG(!is_end(), "disable_recursion_pending() on end recursive_directory_iterator");
  750. if (value)
  751. m_imp->m_options |= directory_options::_detail_no_push;
  752. else
  753. m_imp->m_options &= ~directory_options::_detail_no_push;
  754. }
  755. file_status status() const
  756. {
  757. BOOST_ASSERT_MSG(!is_end(), "status() on end recursive_directory_iterator");
  758. return m_imp->m_stack.back()->status();
  759. }
  760. file_status symlink_status() const
  761. {
  762. BOOST_ASSERT_MSG(!is_end(), "symlink_status() on end recursive_directory_iterator");
  763. return m_imp->m_stack.back()->symlink_status();
  764. }
  765. private:
  766. boost::iterator_facade<
  767. recursive_directory_iterator,
  768. directory_entry,
  769. boost::single_pass_traversal_tag
  770. >::reference dereference() const
  771. {
  772. BOOST_ASSERT_MSG(!is_end(), "dereference of end recursive_directory_iterator");
  773. return *m_imp->m_stack.back();
  774. }
  775. void increment() { detail::recursive_directory_iterator_increment(*this, nullptr); }
  776. bool equal(recursive_directory_iterator const& rhs) const noexcept
  777. {
  778. return m_imp == rhs.m_imp || (is_end() && rhs.is_end());
  779. }
  780. bool is_end() const noexcept
  781. {
  782. // Note: The check for m_stack.empty() is needed because the iterator can be copied and the copy
  783. // can be incremented to end while the original iterator still refers to the same recur_dir_itr_imp.
  784. return !m_imp || m_imp->m_stack.empty();
  785. }
  786. private:
  787. // intrusive_ptr provides the shallow-copy semantics required for single pass iterators
  788. // (i.e. InputIterators). The end iterator is indicated by is_end().
  789. boost::intrusive_ptr< detail::recur_dir_itr_imp > m_imp;
  790. };
  791. // enable recursive directory iterator C++11 range-base for statement use ----------//
  792. // begin() and end() are only used by a range-based for statement in the context of
  793. // auto - thus the top-level const is stripped - so returning const is harmless and
  794. // emphasizes begin() is just a pass through.
  795. inline recursive_directory_iterator const& begin(recursive_directory_iterator const& iter) noexcept
  796. {
  797. return iter;
  798. }
  799. inline recursive_directory_iterator end(recursive_directory_iterator const&) noexcept
  800. {
  801. return recursive_directory_iterator();
  802. }
  803. // enable C++14 generic accessors for range const iterators
  804. inline recursive_directory_iterator const& cbegin(recursive_directory_iterator const& iter) noexcept
  805. {
  806. return iter;
  807. }
  808. inline recursive_directory_iterator cend(recursive_directory_iterator const&) noexcept
  809. {
  810. return recursive_directory_iterator();
  811. }
  812. // enable recursive directory iterator BOOST_FOREACH -------------------------------//
  813. inline recursive_directory_iterator& range_begin(recursive_directory_iterator& iter) noexcept
  814. {
  815. return iter;
  816. }
  817. inline recursive_directory_iterator range_begin(recursive_directory_iterator const& iter) noexcept
  818. {
  819. return iter;
  820. }
  821. inline recursive_directory_iterator range_end(recursive_directory_iterator&) noexcept
  822. {
  823. return recursive_directory_iterator();
  824. }
  825. inline recursive_directory_iterator range_end(recursive_directory_iterator const&) noexcept
  826. {
  827. return recursive_directory_iterator();
  828. }
  829. } // namespace filesystem
  830. // namespace boost template specializations
  831. template<>
  832. struct range_mutable_iterator< boost::filesystem::recursive_directory_iterator, void >
  833. {
  834. typedef boost::filesystem::recursive_directory_iterator type;
  835. };
  836. template<>
  837. struct range_const_iterator< boost::filesystem::recursive_directory_iterator, void >
  838. {
  839. typedef boost::filesystem::recursive_directory_iterator type;
  840. };
  841. } // namespace boost
  842. #if defined(BOOST_GCC) && (__GNUC__ == 12)
  843. #pragma GCC diagnostic pop
  844. #endif
  845. #include <boost/filesystem/detail/footer.hpp>
  846. #endif // BOOST_FILESYSTEM_DIRECTORY_HPP