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

source code of boost/libs/filesystem/include/boost/filesystem/directory.hpp