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 | |
40 | namespace boost { |
41 | namespace filesystem { |
42 | |
43 | enum 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 | |
55 | BOOST_BITMASK(directory_options) |
56 | |
57 | class directory_iterator; |
58 | class recursive_directory_iterator; |
59 | |
60 | namespace detail { |
61 | |
62 | struct directory_iterator_params; |
63 | |
64 | BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, directory_iterator_params* params, system::error_code* ec); |
65 | BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); |
66 | |
67 | struct recur_dir_itr_imp; |
68 | |
69 | BOOST_FILESYSTEM_DECL void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec); |
70 | BOOST_FILESYSTEM_DECL void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec); |
71 | BOOST_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 | |
85 | class 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 | |
92 | public: |
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 | |
376 | private: |
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 | |
400 | private: |
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 | |
408 | inline 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 | |
416 | inline 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 | |
427 | inline 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 | |
438 | inline 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 | |
451 | namespace detail { |
452 | namespace path_traits { |
453 | |
454 | // Dispatch function for integration with path class |
455 | template< typename Callback > |
456 | BOOST_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 | |
477 | inline file_status status(directory_entry const& e) |
478 | { |
479 | return e.status(); |
480 | } |
481 | |
482 | inline file_status status(directory_entry const& e, system::error_code& ec) noexcept |
483 | { |
484 | return e.status(ec); |
485 | } |
486 | |
487 | inline file_status symlink_status(directory_entry const& e) |
488 | { |
489 | return e.symlink_status(); |
490 | } |
491 | |
492 | inline file_status symlink_status(directory_entry const& e, system::error_code& ec) noexcept |
493 | { |
494 | return e.symlink_status(ec); |
495 | } |
496 | |
497 | inline bool type_present(directory_entry const& e) |
498 | { |
499 | return e.file_type() != filesystem::status_error; |
500 | } |
501 | |
502 | inline bool type_present(directory_entry const& e, system::error_code& ec) noexcept |
503 | { |
504 | return e.file_type(ec) != filesystem::status_error; |
505 | } |
506 | |
507 | inline bool status_known(directory_entry const& e) |
508 | { |
509 | return filesystem::status_known(f: e.status()); |
510 | } |
511 | |
512 | inline bool status_known(directory_entry const& e, system::error_code& ec) noexcept |
513 | { |
514 | return filesystem::status_known(f: e.status(ec)); |
515 | } |
516 | |
517 | inline bool exists(directory_entry const& e) |
518 | { |
519 | return e.exists(); |
520 | } |
521 | |
522 | inline bool exists(directory_entry const& e, system::error_code& ec) noexcept |
523 | { |
524 | return e.exists(ec); |
525 | } |
526 | |
527 | inline bool is_regular_file(directory_entry const& e) |
528 | { |
529 | return e.is_regular_file(); |
530 | } |
531 | |
532 | inline bool is_regular_file(directory_entry const& e, system::error_code& ec) noexcept |
533 | { |
534 | return e.is_regular_file(ec); |
535 | } |
536 | |
537 | inline bool is_directory(directory_entry const& e) |
538 | { |
539 | return e.is_directory(); |
540 | } |
541 | |
542 | inline bool is_directory(directory_entry const& e, system::error_code& ec) noexcept |
543 | { |
544 | return e.is_directory(ec); |
545 | } |
546 | |
547 | inline bool is_symlink(directory_entry const& e) |
548 | { |
549 | return e.is_symlink(); |
550 | } |
551 | |
552 | inline bool is_symlink(directory_entry const& e, system::error_code& ec) noexcept |
553 | { |
554 | return e.is_symlink(ec); |
555 | } |
556 | |
557 | inline bool is_block_file(directory_entry const& e) |
558 | { |
559 | return e.is_block_file(); |
560 | } |
561 | |
562 | inline bool is_block_file(directory_entry const& e, system::error_code& ec) noexcept |
563 | { |
564 | return e.is_block_file(ec); |
565 | } |
566 | |
567 | inline bool is_character_file(directory_entry const& e) |
568 | { |
569 | return e.is_character_file(); |
570 | } |
571 | |
572 | inline bool is_character_file(directory_entry const& e, system::error_code& ec) noexcept |
573 | { |
574 | return e.is_character_file(ec); |
575 | } |
576 | |
577 | inline bool is_fifo(directory_entry const& e) |
578 | { |
579 | return e.is_fifo(); |
580 | } |
581 | |
582 | inline bool is_fifo(directory_entry const& e, system::error_code& ec) noexcept |
583 | { |
584 | return e.is_fifo(ec); |
585 | } |
586 | |
587 | inline bool is_socket(directory_entry const& e) |
588 | { |
589 | return e.is_socket(); |
590 | } |
591 | |
592 | inline bool is_socket(directory_entry const& e, system::error_code& ec) noexcept |
593 | { |
594 | return e.is_socket(ec); |
595 | } |
596 | |
597 | inline bool is_reparse_file(directory_entry const& e) |
598 | { |
599 | return e.is_reparse_file(); |
600 | } |
601 | |
602 | inline bool is_reparse_file(directory_entry const& e, system::error_code& ec) noexcept |
603 | { |
604 | return e.is_reparse_file(ec); |
605 | } |
606 | |
607 | inline bool is_other(directory_entry const& e) |
608 | { |
609 | return e.is_other(); |
610 | } |
611 | |
612 | inline 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 | |
623 | namespace detail { |
624 | |
625 | struct 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 ) noexcept; |
648 | BOOST_FILESYSTEM_DECL static void operator delete(void* p, std::size_t ) 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 | |
660 | class 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 | |
674 | public: |
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 | |
714 | private: |
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 | |
739 | private: |
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. |
750 | inline directory_iterator const& begin(directory_iterator const& iter) noexcept |
751 | { |
752 | return iter; |
753 | } |
754 | |
755 | inline directory_iterator end(directory_iterator const&) noexcept |
756 | { |
757 | return directory_iterator(); |
758 | } |
759 | |
760 | // enable C++14 generic accessors for range const iterators |
761 | inline directory_iterator const& cbegin(directory_iterator const& iter) noexcept |
762 | { |
763 | return iter; |
764 | } |
765 | |
766 | inline directory_iterator cend(directory_iterator const&) noexcept |
767 | { |
768 | return directory_iterator(); |
769 | } |
770 | |
771 | // enable directory_iterator BOOST_FOREACH -----------------------------------------// |
772 | |
773 | inline directory_iterator& range_begin(directory_iterator& iter) noexcept |
774 | { |
775 | return iter; |
776 | } |
777 | |
778 | inline directory_iterator range_begin(directory_iterator const& iter) noexcept |
779 | { |
780 | return iter; |
781 | } |
782 | |
783 | inline directory_iterator range_end(directory_iterator&) noexcept |
784 | { |
785 | return directory_iterator(); |
786 | } |
787 | |
788 | inline directory_iterator range_end(directory_iterator const&) noexcept |
789 | { |
790 | return directory_iterator(); |
791 | } |
792 | |
793 | } // namespace filesystem |
794 | |
795 | // namespace boost template specializations |
796 | template< typename C, typename Enabler > |
797 | struct range_mutable_iterator; |
798 | |
799 | template<> |
800 | struct range_mutable_iterator< boost::filesystem::directory_iterator, void > |
801 | { |
802 | typedef boost::filesystem::directory_iterator type; |
803 | }; |
804 | |
805 | template< typename C, typename Enabler > |
806 | struct range_const_iterator; |
807 | |
808 | template<> |
809 | struct range_const_iterator< boost::filesystem::directory_iterator, void > |
810 | { |
811 | typedef boost::filesystem::directory_iterator type; |
812 | }; |
813 | |
814 | namespace filesystem { |
815 | |
816 | //--------------------------------------------------------------------------------------// |
817 | // // |
818 | // recursive_directory_iterator helpers // |
819 | // // |
820 | //--------------------------------------------------------------------------------------// |
821 | |
822 | namespace detail { |
823 | |
824 | struct 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 | |
842 | class 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 | |
855 | public: |
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 | |
941 | private: |
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 | |
966 | private: |
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. |
977 | inline recursive_directory_iterator const& begin(recursive_directory_iterator const& iter) noexcept |
978 | { |
979 | return iter; |
980 | } |
981 | |
982 | inline 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 |
988 | inline recursive_directory_iterator const& cbegin(recursive_directory_iterator const& iter) noexcept |
989 | { |
990 | return iter; |
991 | } |
992 | |
993 | inline 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 | |
1000 | inline recursive_directory_iterator& range_begin(recursive_directory_iterator& iter) noexcept |
1001 | { |
1002 | return iter; |
1003 | } |
1004 | |
1005 | inline recursive_directory_iterator range_begin(recursive_directory_iterator const& iter) noexcept |
1006 | { |
1007 | return iter; |
1008 | } |
1009 | |
1010 | inline recursive_directory_iterator range_end(recursive_directory_iterator&) noexcept |
1011 | { |
1012 | return recursive_directory_iterator(); |
1013 | } |
1014 | |
1015 | inline 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 |
1023 | template<> |
1024 | struct range_mutable_iterator< boost::filesystem::recursive_directory_iterator, void > |
1025 | { |
1026 | typedef boost::filesystem::recursive_directory_iterator type; |
1027 | }; |
1028 | |
1029 | template<> |
1030 | struct 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 | |