]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // boost/filesystem/operations.hpp ---------------------------------------------------// |
2 | ||
3 | // Copyright Beman Dawes 2002-2009 | |
4 | // Copyright Jan Langer 2002 | |
5 | // Copyright Dietmar Kuehl 2001 | |
6 | // Copyright Vladimir Prus 2002 | |
7 | ||
8 | // Distributed under the Boost Software License, Version 1.0. | |
9 | // See http://www.boost.org/LICENSE_1_0.txt | |
10 | ||
11 | // Library home page: http://www.boost.org/libs/filesystem | |
12 | ||
13 | //--------------------------------------------------------------------------------------// | |
14 | ||
15 | #ifndef BOOST_FILESYSTEM3_OPERATIONS_HPP | |
16 | #define BOOST_FILESYSTEM3_OPERATIONS_HPP | |
17 | ||
18 | #include <boost/config.hpp> | |
19 | ||
20 | # if defined( BOOST_NO_STD_WSTRING ) | |
21 | # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support | |
22 | # endif | |
23 | ||
24 | #include <boost/filesystem/config.hpp> | |
25 | #include <boost/filesystem/path.hpp> | |
26 | ||
27 | #include <boost/detail/scoped_enum_emulation.hpp> | |
28 | #include <boost/detail/bitmask.hpp> | |
29 | #include <boost/system/error_code.hpp> | |
30 | #include <boost/system/system_error.hpp> | |
31 | #include <boost/shared_ptr.hpp> | |
32 | #include <boost/utility/enable_if.hpp> | |
33 | #include <boost/type_traits/is_same.hpp> | |
34 | #include <boost/cstdint.hpp> | |
35 | #include <boost/range/mutable_iterator.hpp> | |
36 | #include <boost/range/const_iterator.hpp> | |
37 | #include <boost/assert.hpp> | |
38 | #include <string> | |
39 | #include <utility> // for pair | |
40 | #include <ctime> | |
41 | #include <vector> | |
42 | #include <stack> | |
43 | ||
44 | #ifdef BOOST_WINDOWS_API | |
45 | # include <fstream> | |
46 | #endif | |
47 | ||
48 | #include <boost/config/abi_prefix.hpp> // must be the last #include | |
49 | ||
50 | //--------------------------------------------------------------------------------------// | |
51 | ||
52 | namespace boost | |
53 | { | |
54 | namespace filesystem | |
55 | { | |
56 | ||
57 | //--------------------------------------------------------------------------------------// | |
58 | // // | |
59 | // class filesystem_error // | |
60 | // // | |
61 | //--------------------------------------------------------------------------------------// | |
62 | ||
63 | class BOOST_SYMBOL_VISIBLE filesystem_error : public system::system_error | |
64 | { | |
65 | // see http://www.boost.org/more/error_handling.html for design rationale | |
66 | ||
67 | // all functions are inline to avoid issues with crossing dll boundaries | |
68 | ||
69 | // functions previously throw() are now BOOST_NOEXCEPT_OR_NOTHROW | |
70 | // functions previously without throw() are now BOOST_NOEXCEPT | |
71 | ||
72 | public: | |
73 | // compiler generates copy constructor and copy assignment | |
74 | ||
75 | filesystem_error( | |
76 | const std::string & what_arg, system::error_code ec) BOOST_NOEXCEPT | |
77 | : system::system_error(ec, what_arg) | |
78 | { | |
79 | try | |
80 | { | |
81 | m_imp_ptr.reset(new m_imp); | |
82 | } | |
83 | catch (...) { m_imp_ptr.reset(); } | |
84 | } | |
85 | ||
86 | filesystem_error( | |
87 | const std::string & what_arg, const path& path1_arg, | |
88 | system::error_code ec) BOOST_NOEXCEPT | |
89 | : system::system_error(ec, what_arg) | |
90 | { | |
91 | try | |
92 | { | |
93 | m_imp_ptr.reset(new m_imp); | |
94 | m_imp_ptr->m_path1 = path1_arg; | |
95 | } | |
96 | catch (...) { m_imp_ptr.reset(); } | |
97 | } | |
98 | ||
99 | filesystem_error( | |
100 | const std::string & what_arg, const path& path1_arg, | |
101 | const path& path2_arg, system::error_code ec) BOOST_NOEXCEPT | |
102 | : system::system_error(ec, what_arg) | |
103 | { | |
104 | try | |
105 | { | |
106 | m_imp_ptr.reset(new m_imp); | |
107 | m_imp_ptr->m_path1 = path1_arg; | |
108 | m_imp_ptr->m_path2 = path2_arg; | |
109 | } | |
110 | catch (...) { m_imp_ptr.reset(); } | |
111 | } | |
112 | ||
113 | ~filesystem_error() BOOST_NOEXCEPT_OR_NOTHROW{} | |
114 | ||
115 | const path& path1() const BOOST_NOEXCEPT | |
116 | { | |
117 | static const path empty_path; | |
118 | return m_imp_ptr.get() ? m_imp_ptr->m_path1 : empty_path; | |
119 | } | |
120 | const path& path2() const BOOST_NOEXCEPT | |
121 | { | |
122 | static const path empty_path; | |
123 | return m_imp_ptr.get() ? m_imp_ptr->m_path2 : empty_path; | |
124 | } | |
125 | ||
126 | const char* what() const BOOST_NOEXCEPT_OR_NOTHROW | |
127 | { | |
128 | if (!m_imp_ptr.get()) | |
129 | return system::system_error::what(); | |
130 | ||
131 | try | |
132 | { | |
133 | if (m_imp_ptr->m_what.empty()) | |
134 | { | |
135 | m_imp_ptr->m_what = system::system_error::what(); | |
136 | if (!m_imp_ptr->m_path1.empty()) | |
137 | { | |
138 | m_imp_ptr->m_what += ": \""; | |
139 | m_imp_ptr->m_what += m_imp_ptr->m_path1.string(); | |
140 | m_imp_ptr->m_what += "\""; | |
141 | } | |
142 | if (!m_imp_ptr->m_path2.empty()) | |
143 | { | |
144 | m_imp_ptr->m_what += ", \""; | |
145 | m_imp_ptr->m_what += m_imp_ptr->m_path2.string(); | |
146 | m_imp_ptr->m_what += "\""; | |
147 | } | |
148 | } | |
149 | return m_imp_ptr->m_what.c_str(); | |
150 | } | |
151 | catch (...) | |
152 | { | |
153 | return system::system_error::what(); | |
154 | } | |
155 | } | |
156 | ||
157 | private: | |
158 | struct m_imp | |
159 | { | |
160 | path m_path1; // may be empty() | |
161 | path m_path2; // may be empty() | |
162 | std::string m_what; // not built until needed | |
163 | }; | |
164 | boost::shared_ptr<m_imp> m_imp_ptr; | |
165 | }; | |
166 | ||
167 | //--------------------------------------------------------------------------------------// | |
168 | // file_type // | |
169 | //--------------------------------------------------------------------------------------// | |
170 | ||
171 | enum file_type | |
172 | { | |
173 | status_error, | |
174 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
175 | status_unknown = status_error, | |
176 | # endif | |
177 | file_not_found, | |
178 | regular_file, | |
179 | directory_file, | |
180 | // the following may not apply to some operating systems or file systems | |
181 | symlink_file, | |
182 | block_file, | |
183 | character_file, | |
184 | fifo_file, | |
185 | socket_file, | |
186 | reparse_file, // Windows: FILE_ATTRIBUTE_REPARSE_POINT that is not a symlink | |
187 | type_unknown, // file does exist, but isn't one of the above types or | |
188 | // we don't have strong enough permission to find its type | |
189 | ||
190 | _detail_directory_symlink // internal use only; never exposed to users | |
191 | }; | |
192 | ||
193 | //--------------------------------------------------------------------------------------// | |
194 | // perms // | |
195 | //--------------------------------------------------------------------------------------// | |
196 | ||
197 | enum perms | |
198 | { | |
199 | no_perms = 0, // file_not_found is no_perms rather than perms_not_known | |
200 | ||
201 | // POSIX equivalent macros given in comments. | |
202 | // Values are from POSIX and are given in octal per the POSIX standard. | |
203 | ||
204 | // permission bits | |
205 | ||
206 | owner_read = 0400, // S_IRUSR, Read permission, owner | |
207 | owner_write = 0200, // S_IWUSR, Write permission, owner | |
208 | owner_exe = 0100, // S_IXUSR, Execute/search permission, owner | |
209 | owner_all = 0700, // S_IRWXU, Read, write, execute/search by owner | |
210 | ||
211 | group_read = 040, // S_IRGRP, Read permission, group | |
212 | group_write = 020, // S_IWGRP, Write permission, group | |
213 | group_exe = 010, // S_IXGRP, Execute/search permission, group | |
214 | group_all = 070, // S_IRWXG, Read, write, execute/search by group | |
215 | ||
216 | others_read = 04, // S_IROTH, Read permission, others | |
217 | others_write = 02, // S_IWOTH, Write permission, others | |
218 | others_exe = 01, // S_IXOTH, Execute/search permission, others | |
219 | others_all = 07, // S_IRWXO, Read, write, execute/search by others | |
220 | ||
221 | all_all = 0777, // owner_all|group_all|others_all | |
222 | ||
223 | // other POSIX bits | |
224 | ||
225 | set_uid_on_exe = 04000, // S_ISUID, Set-user-ID on execution | |
226 | set_gid_on_exe = 02000, // S_ISGID, Set-group-ID on execution | |
227 | sticky_bit = 01000, // S_ISVTX, | |
228 | // (POSIX XSI) On directories, restricted deletion flag | |
229 | // (V7) 'sticky bit': save swapped text even after use | |
230 | // (SunOS) On non-directories: don't cache this file | |
231 | // (SVID-v4.2) On directories: restricted deletion flag | |
232 | // Also see http://en.wikipedia.org/wiki/Sticky_bit | |
233 | ||
234 | perms_mask = 07777, // all_all|set_uid_on_exe|set_gid_on_exe|sticky_bit | |
235 | ||
236 | perms_not_known = 0xFFFF, // present when directory_entry cache not loaded | |
237 | ||
238 | // options for permissions() function | |
239 | ||
240 | add_perms = 0x1000, // adds the given permission bits to the current bits | |
241 | remove_perms = 0x2000, // removes the given permission bits from the current bits; | |
242 | // choose add_perms or remove_perms, not both; if neither add_perms | |
243 | // nor remove_perms is given, replace the current bits with | |
244 | // the given bits. | |
245 | ||
246 | symlink_perms = 0x4000 // on POSIX, don't resolve symlinks; implied on Windows | |
247 | }; | |
248 | ||
249 | BOOST_BITMASK(perms) | |
250 | ||
251 | //--------------------------------------------------------------------------------------// | |
252 | // file_status // | |
253 | //--------------------------------------------------------------------------------------// | |
254 | ||
255 | class BOOST_FILESYSTEM_DECL file_status | |
256 | { | |
257 | public: | |
258 | file_status() BOOST_NOEXCEPT | |
259 | : m_value(status_error), m_perms(perms_not_known) {} | |
260 | explicit file_status(file_type v) BOOST_NOEXCEPT | |
261 | : m_value(v), m_perms(perms_not_known) {} | |
262 | file_status(file_type v, perms prms) BOOST_NOEXCEPT | |
263 | : m_value(v), m_perms(prms) {} | |
264 | ||
265 | // As of October 2015 the interaction between noexcept and =default is so troublesome | |
266 | // for VC++, GCC, and probably other compilers, that =default is not used with noexcept | |
267 | // functions. GCC is not even consistent for the same release on different platforms. | |
268 | ||
269 | file_status(const file_status& rhs) BOOST_NOEXCEPT | |
270 | : m_value(rhs.m_value), m_perms(rhs.m_perms) {} | |
271 | file_status& operator=(const file_status& rhs) BOOST_NOEXCEPT | |
272 | { | |
273 | m_value = rhs.m_value; | |
274 | m_perms = rhs.m_perms; | |
275 | return *this; | |
276 | } | |
277 | ||
278 | # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
279 | file_status(file_status&& rhs) BOOST_NOEXCEPT | |
280 | { | |
281 | m_value = std::move(rhs.m_value); | |
282 | m_perms = std::move(rhs.m_perms); | |
283 | } | |
284 | file_status& operator=(file_status&& rhs) BOOST_NOEXCEPT | |
285 | { | |
286 | m_value = std::move(rhs.m_value); | |
287 | m_perms = std::move(rhs.m_perms); | |
288 | return *this; | |
289 | } | |
290 | # endif | |
291 | ||
292 | ||
293 | // observers | |
294 | file_type type() const BOOST_NOEXCEPT { return m_value; } | |
295 | perms permissions() const BOOST_NOEXCEPT { return m_perms; } | |
296 | ||
297 | // modifiers | |
298 | void type(file_type v) BOOST_NOEXCEPT { m_value = v; } | |
299 | void permissions(perms prms) BOOST_NOEXCEPT { m_perms = prms; } | |
300 | ||
301 | bool operator==(const file_status& rhs) const BOOST_NOEXCEPT | |
302 | { return type() == rhs.type() && | |
303 | permissions() == rhs.permissions(); } | |
304 | bool operator!=(const file_status& rhs) const BOOST_NOEXCEPT | |
305 | { return !(*this == rhs); } | |
306 | ||
307 | private: | |
308 | file_type m_value; | |
309 | enum perms m_perms; | |
310 | }; | |
311 | ||
312 | inline bool type_present(file_status f) BOOST_NOEXCEPT | |
313 | { return f.type() != status_error; } | |
314 | inline bool permissions_present(file_status f) BOOST_NOEXCEPT | |
315 | {return f.permissions() != perms_not_known;} | |
316 | inline bool status_known(file_status f) BOOST_NOEXCEPT | |
317 | { return type_present(f) && permissions_present(f); } | |
318 | inline bool exists(file_status f) BOOST_NOEXCEPT | |
319 | { return f.type() != status_error | |
320 | && f.type() != file_not_found; } | |
321 | inline bool is_regular_file(file_status f) BOOST_NOEXCEPT | |
322 | { return f.type() == regular_file; } | |
323 | inline bool is_directory(file_status f) BOOST_NOEXCEPT | |
324 | { return f.type() == directory_file; } | |
325 | inline bool is_symlink(file_status f) BOOST_NOEXCEPT | |
326 | { return f.type() == symlink_file; } | |
327 | inline bool is_other(file_status f) BOOST_NOEXCEPT | |
328 | { return exists(f) && !is_regular_file(f) | |
329 | && !is_directory(f) && !is_symlink(f); } | |
330 | ||
331 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
332 | inline bool is_regular(file_status f) BOOST_NOEXCEPT { return f.type() == regular_file; } | |
333 | # endif | |
334 | ||
335 | struct space_info | |
336 | { | |
337 | // all values are byte counts | |
338 | boost::uintmax_t capacity; | |
339 | boost::uintmax_t free; // <= capacity | |
340 | boost::uintmax_t available; // <= free | |
341 | }; | |
342 | ||
343 | BOOST_SCOPED_ENUM_START(copy_option) | |
344 | {none=0, fail_if_exists = none, overwrite_if_exists}; | |
345 | BOOST_SCOPED_ENUM_END | |
346 | ||
347 | //--------------------------------------------------------------------------------------// | |
348 | // implementation details // | |
349 | //--------------------------------------------------------------------------------------// | |
350 | ||
351 | namespace detail | |
352 | { | |
353 | // We cannot pass a BOOST_SCOPED_ENUM to a compled function because it will result | |
354 | // in an undefined reference if the library is compled with -std=c++0x but the use | |
355 | // is compiled in C++03 mode, or visa versa. See tickets 6124, 6779, 10038. | |
356 | enum copy_option {none=0, fail_if_exists = none, overwrite_if_exists}; | |
357 | ||
358 | BOOST_FILESYSTEM_DECL | |
359 | file_status status(const path&p, system::error_code* ec=0); | |
360 | BOOST_FILESYSTEM_DECL | |
361 | file_status symlink_status(const path& p, system::error_code* ec=0); | |
362 | BOOST_FILESYSTEM_DECL | |
363 | bool is_empty(const path& p, system::error_code* ec=0); | |
364 | BOOST_FILESYSTEM_DECL | |
365 | path initial_path(system::error_code* ec=0); | |
366 | BOOST_FILESYSTEM_DECL | |
367 | path canonical(const path& p, const path& base, system::error_code* ec=0); | |
368 | BOOST_FILESYSTEM_DECL | |
369 | void copy(const path& from, const path& to, system::error_code* ec=0); | |
370 | BOOST_FILESYSTEM_DECL | |
371 | void copy_directory(const path& from, const path& to, system::error_code* ec=0); | |
372 | BOOST_FILESYSTEM_DECL | |
373 | void copy_file(const path& from, const path& to, // See ticket #2925 | |
374 | detail::copy_option option, system::error_code* ec=0); | |
375 | BOOST_FILESYSTEM_DECL | |
376 | void copy_symlink(const path& existing_symlink, const path& new_symlink, system::error_code* ec=0); | |
377 | BOOST_FILESYSTEM_DECL | |
378 | bool create_directories(const path& p, system::error_code* ec=0); | |
379 | BOOST_FILESYSTEM_DECL | |
380 | bool create_directory(const path& p, system::error_code* ec=0); | |
381 | BOOST_FILESYSTEM_DECL | |
382 | void create_directory_symlink(const path& to, const path& from, | |
383 | system::error_code* ec=0); | |
384 | BOOST_FILESYSTEM_DECL | |
385 | void create_hard_link(const path& to, const path& from, system::error_code* ec=0); | |
386 | BOOST_FILESYSTEM_DECL | |
387 | void create_symlink(const path& to, const path& from, system::error_code* ec=0); | |
388 | BOOST_FILESYSTEM_DECL | |
389 | path current_path(system::error_code* ec=0); | |
390 | BOOST_FILESYSTEM_DECL | |
391 | void current_path(const path& p, system::error_code* ec=0); | |
392 | BOOST_FILESYSTEM_DECL | |
393 | bool equivalent(const path& p1, const path& p2, system::error_code* ec=0); | |
394 | BOOST_FILESYSTEM_DECL | |
395 | boost::uintmax_t file_size(const path& p, system::error_code* ec=0); | |
396 | BOOST_FILESYSTEM_DECL | |
397 | boost::uintmax_t hard_link_count(const path& p, system::error_code* ec=0); | |
398 | BOOST_FILESYSTEM_DECL | |
399 | std::time_t last_write_time(const path& p, system::error_code* ec=0); | |
400 | BOOST_FILESYSTEM_DECL | |
401 | void last_write_time(const path& p, const std::time_t new_time, | |
402 | system::error_code* ec=0); | |
403 | BOOST_FILESYSTEM_DECL | |
404 | void permissions(const path& p, perms prms, system::error_code* ec=0); | |
405 | BOOST_FILESYSTEM_DECL | |
406 | path read_symlink(const path& p, system::error_code* ec=0); | |
407 | BOOST_FILESYSTEM_DECL | |
408 | path relative(const path& p, const path& base, system::error_code* ec = 0); | |
409 | BOOST_FILESYSTEM_DECL | |
410 | bool remove(const path& p, system::error_code* ec=0); | |
411 | BOOST_FILESYSTEM_DECL | |
412 | boost::uintmax_t remove_all(const path& p, system::error_code* ec=0); | |
413 | BOOST_FILESYSTEM_DECL | |
414 | void rename(const path& old_p, const path& new_p, system::error_code* ec=0); | |
415 | BOOST_FILESYSTEM_DECL | |
416 | void resize_file(const path& p, uintmax_t size, system::error_code* ec=0); | |
417 | BOOST_FILESYSTEM_DECL | |
418 | space_info space(const path& p, system::error_code* ec=0); | |
419 | BOOST_FILESYSTEM_DECL | |
420 | path system_complete(const path& p, system::error_code* ec=0); | |
421 | BOOST_FILESYSTEM_DECL | |
422 | path temp_directory_path(system::error_code* ec=0); | |
423 | BOOST_FILESYSTEM_DECL | |
424 | path unique_path(const path& p, system::error_code* ec=0); | |
425 | BOOST_FILESYSTEM_DECL | |
426 | path weakly_canonical(const path& p, system::error_code* ec = 0); | |
427 | } // namespace detail | |
428 | ||
429 | //--------------------------------------------------------------------------------------// | |
430 | // // | |
431 | // status query functions // | |
432 | // // | |
433 | //--------------------------------------------------------------------------------------// | |
434 | ||
435 | inline | |
436 | file_status status(const path& p) {return detail::status(p);} | |
437 | inline | |
438 | file_status status(const path& p, system::error_code& ec) | |
439 | {return detail::status(p, &ec);} | |
440 | inline | |
441 | file_status symlink_status(const path& p) {return detail::symlink_status(p);} | |
442 | inline | |
443 | file_status symlink_status(const path& p, system::error_code& ec) | |
444 | {return detail::symlink_status(p, &ec);} | |
445 | inline | |
446 | bool exists(const path& p) {return exists(detail::status(p));} | |
447 | inline | |
448 | bool exists(const path& p, system::error_code& ec) | |
449 | {return exists(detail::status(p, &ec));} | |
450 | inline | |
451 | bool is_directory(const path& p) {return is_directory(detail::status(p));} | |
452 | inline | |
453 | bool is_directory(const path& p, system::error_code& ec) | |
454 | {return is_directory(detail::status(p, &ec));} | |
455 | inline | |
456 | bool is_regular_file(const path& p) {return is_regular_file(detail::status(p));} | |
457 | inline | |
458 | bool is_regular_file(const path& p, system::error_code& ec) | |
459 | {return is_regular_file(detail::status(p, &ec));} | |
460 | inline | |
461 | bool is_other(const path& p) {return is_other(detail::status(p));} | |
462 | inline | |
463 | bool is_other(const path& p, system::error_code& ec) | |
464 | {return is_other(detail::status(p, &ec));} | |
465 | inline | |
466 | bool is_symlink(const path& p) {return is_symlink(detail::symlink_status(p));} | |
467 | inline | |
468 | bool is_symlink(const path& p, system::error_code& ec) | |
469 | {return is_symlink(detail::symlink_status(p, &ec));} | |
470 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
471 | inline | |
472 | bool is_regular(const path& p) {return is_regular(detail::status(p));} | |
473 | inline | |
474 | bool is_regular(const path& p, system::error_code& ec) | |
475 | {return is_regular(detail::status(p, &ec));} | |
476 | # endif | |
477 | ||
478 | inline | |
479 | bool is_empty(const path& p) {return detail::is_empty(p);} | |
480 | inline | |
481 | bool is_empty(const path& p, system::error_code& ec) | |
482 | {return detail::is_empty(p, &ec);} | |
483 | ||
484 | //--------------------------------------------------------------------------------------// | |
485 | // // | |
486 | // operational functions // | |
487 | // in alphabetical order, unless otherwise noted // | |
488 | // // | |
489 | //--------------------------------------------------------------------------------------// | |
490 | ||
491 | // forward declarations | |
492 | path current_path(); // fwd declaration | |
493 | path initial_path(); | |
494 | ||
495 | BOOST_FILESYSTEM_DECL | |
496 | path absolute(const path& p, const path& base=current_path()); | |
497 | // If base.is_absolute(), throws nothing. Thus no need for ec argument | |
498 | ||
499 | inline | |
500 | path canonical(const path& p, const path& base=current_path()) | |
501 | {return detail::canonical(p, base);} | |
502 | inline | |
503 | path canonical(const path& p, system::error_code& ec) | |
504 | {return detail::canonical(p, current_path(), &ec);} | |
505 | inline | |
506 | path canonical(const path& p, const path& base, system::error_code& ec) | |
507 | {return detail::canonical(p, base, &ec);} | |
508 | ||
509 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
510 | inline | |
511 | path complete(const path& p) | |
512 | { | |
513 | return absolute(p, initial_path()); | |
514 | } | |
515 | ||
516 | inline | |
517 | path complete(const path& p, const path& base) | |
518 | { | |
519 | return absolute(p, base); | |
520 | } | |
521 | # endif | |
522 | ||
523 | inline | |
524 | void copy(const path& from, const path& to) {detail::copy(from, to);} | |
525 | ||
526 | inline | |
527 | void copy(const path& from, const path& to, system::error_code& ec) BOOST_NOEXCEPT | |
528 | {detail::copy(from, to, &ec);} | |
529 | inline | |
530 | void copy_directory(const path& from, const path& to) | |
531 | {detail::copy_directory(from, to);} | |
532 | inline | |
533 | void copy_directory(const path& from, const path& to, system::error_code& ec) BOOST_NOEXCEPT | |
534 | {detail::copy_directory(from, to, &ec);} | |
535 | inline | |
536 | void copy_file(const path& from, const path& to, // See ticket #2925 | |
537 | BOOST_SCOPED_ENUM(copy_option) option) | |
538 | { | |
539 | detail::copy_file(from, to, static_cast<detail::copy_option>(option)); | |
540 | } | |
541 | inline | |
542 | void copy_file(const path& from, const path& to) | |
543 | { | |
544 | detail::copy_file(from, to, detail::fail_if_exists); | |
545 | } | |
546 | inline | |
547 | void copy_file(const path& from, const path& to, // See ticket #2925 | |
548 | BOOST_SCOPED_ENUM(copy_option) option, system::error_code& ec) BOOST_NOEXCEPT | |
549 | { | |
550 | detail::copy_file(from, to, static_cast<detail::copy_option>(option), &ec); | |
551 | } | |
552 | inline | |
553 | void copy_file(const path& from, const path& to, system::error_code& ec) BOOST_NOEXCEPT | |
554 | { | |
555 | detail::copy_file(from, to, detail::fail_if_exists, &ec); | |
556 | } | |
557 | inline | |
558 | void copy_symlink(const path& existing_symlink, | |
559 | const path& new_symlink) {detail::copy_symlink(existing_symlink, new_symlink);} | |
560 | ||
561 | inline | |
562 | void copy_symlink(const path& existing_symlink, const path& new_symlink, | |
563 | system::error_code& ec) BOOST_NOEXCEPT | |
564 | {detail::copy_symlink(existing_symlink, new_symlink, &ec);} | |
565 | inline | |
566 | bool create_directories(const path& p) {return detail::create_directories(p);} | |
567 | ||
568 | inline | |
569 | bool create_directories(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
570 | {return detail::create_directories(p, &ec);} | |
571 | inline | |
572 | bool create_directory(const path& p) {return detail::create_directory(p);} | |
573 | ||
574 | inline | |
575 | bool create_directory(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
576 | {return detail::create_directory(p, &ec);} | |
577 | inline | |
578 | void create_directory_symlink(const path& to, const path& from) | |
579 | {detail::create_directory_symlink(to, from);} | |
580 | inline | |
581 | void create_directory_symlink(const path& to, const path& from, system::error_code& ec) BOOST_NOEXCEPT | |
582 | {detail::create_directory_symlink(to, from, &ec);} | |
583 | inline | |
584 | void create_hard_link(const path& to, const path& new_hard_link) {detail::create_hard_link(to, new_hard_link);} | |
585 | ||
586 | inline | |
587 | void create_hard_link(const path& to, const path& new_hard_link, system::error_code& ec) BOOST_NOEXCEPT | |
588 | {detail::create_hard_link(to, new_hard_link, &ec);} | |
589 | inline | |
590 | void create_symlink(const path& to, const path& new_symlink) {detail::create_symlink(to, new_symlink);} | |
591 | ||
592 | inline | |
593 | void create_symlink(const path& to, const path& new_symlink, system::error_code& ec) BOOST_NOEXCEPT | |
594 | {detail::create_symlink(to, new_symlink, &ec);} | |
595 | inline | |
596 | path current_path() {return detail::current_path();} | |
597 | ||
598 | inline | |
599 | path current_path(system::error_code& ec) BOOST_NOEXCEPT {return detail::current_path(&ec);} | |
600 | ||
601 | inline | |
602 | void current_path(const path& p) {detail::current_path(p);} | |
603 | ||
604 | inline | |
605 | void current_path(const path& p, system::error_code& ec) BOOST_NOEXCEPT {detail::current_path(p, &ec);} | |
606 | ||
607 | inline | |
608 | bool equivalent(const path& p1, const path& p2) {return detail::equivalent(p1, p2);} | |
609 | ||
610 | inline | |
611 | bool equivalent(const path& p1, const path& p2, system::error_code& ec) BOOST_NOEXCEPT | |
612 | {return detail::equivalent(p1, p2, &ec);} | |
613 | inline | |
614 | boost::uintmax_t file_size(const path& p) {return detail::file_size(p);} | |
615 | ||
616 | inline | |
617 | boost::uintmax_t file_size(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
618 | {return detail::file_size(p, &ec);} | |
619 | inline | |
620 | boost::uintmax_t hard_link_count(const path& p) {return detail::hard_link_count(p);} | |
621 | ||
622 | inline | |
623 | boost::uintmax_t hard_link_count(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
624 | {return detail::hard_link_count(p, &ec);} | |
625 | inline | |
626 | path initial_path() {return detail::initial_path();} | |
627 | ||
628 | inline | |
629 | path initial_path(system::error_code& ec) {return detail::initial_path(&ec);} | |
630 | ||
631 | template <class Path> | |
632 | path initial_path() {return initial_path();} | |
633 | template <class Path> | |
634 | path initial_path(system::error_code& ec) {return detail::initial_path(&ec);} | |
635 | ||
636 | inline | |
637 | std::time_t last_write_time(const path& p) {return detail::last_write_time(p);} | |
638 | ||
639 | inline | |
640 | std::time_t last_write_time(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
641 | {return detail::last_write_time(p, &ec);} | |
642 | inline | |
643 | void last_write_time(const path& p, const std::time_t new_time) | |
644 | {detail::last_write_time(p, new_time);} | |
645 | inline | |
646 | void last_write_time(const path& p, const std::time_t new_time, | |
647 | system::error_code& ec) BOOST_NOEXCEPT | |
648 | {detail::last_write_time(p, new_time, &ec);} | |
649 | inline | |
650 | void permissions(const path& p, perms prms) | |
651 | {detail::permissions(p, prms);} | |
652 | inline | |
653 | void permissions(const path& p, perms prms, system::error_code& ec) BOOST_NOEXCEPT | |
654 | {detail::permissions(p, prms, &ec);} | |
655 | ||
656 | inline | |
657 | path read_symlink(const path& p) {return detail::read_symlink(p);} | |
658 | ||
659 | inline | |
660 | path read_symlink(const path& p, system::error_code& ec) | |
661 | {return detail::read_symlink(p, &ec);} | |
662 | inline | |
663 | // For standardization, if the committee doesn't like "remove", consider "eliminate" | |
664 | bool remove(const path& p) {return detail::remove(p);} | |
665 | ||
666 | inline | |
667 | bool remove(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
668 | {return detail::remove(p, &ec);} | |
669 | ||
670 | inline | |
671 | boost::uintmax_t remove_all(const path& p) {return detail::remove_all(p);} | |
672 | ||
673 | inline | |
674 | boost::uintmax_t remove_all(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
675 | {return detail::remove_all(p, &ec);} | |
676 | inline | |
677 | void rename(const path& old_p, const path& new_p) {detail::rename(old_p, new_p);} | |
678 | ||
679 | inline | |
680 | void rename(const path& old_p, const path& new_p, system::error_code& ec) BOOST_NOEXCEPT | |
681 | {detail::rename(old_p, new_p, &ec);} | |
682 | inline // name suggested by Scott McMurray | |
683 | void resize_file(const path& p, uintmax_t size) {detail::resize_file(p, size);} | |
684 | ||
685 | inline | |
686 | void resize_file(const path& p, uintmax_t size, system::error_code& ec) BOOST_NOEXCEPT | |
687 | {detail::resize_file(p, size, &ec);} | |
688 | inline | |
689 | path relative(const path& p, const path& base=current_path()) | |
690 | {return detail::relative(p, base);} | |
691 | inline | |
692 | path relative(const path& p, system::error_code& ec) | |
693 | {return detail::relative(p, current_path(), &ec);} | |
694 | inline | |
695 | path relative(const path& p, const path& base, system::error_code& ec) | |
696 | {return detail::relative(p, base, &ec);} | |
697 | inline | |
698 | space_info space(const path& p) {return detail::space(p);} | |
699 | ||
700 | inline | |
701 | space_info space(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
702 | {return detail::space(p, &ec);} | |
703 | ||
704 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
705 | inline bool symbolic_link_exists(const path& p) | |
706 | { return is_symlink(symlink_status(p)); } | |
707 | # endif | |
708 | ||
709 | inline | |
710 | path system_complete(const path& p) {return detail::system_complete(p);} | |
711 | ||
712 | inline | |
713 | path system_complete(const path& p, system::error_code& ec) | |
714 | {return detail::system_complete(p, &ec);} | |
715 | inline | |
716 | path temp_directory_path() {return detail::temp_directory_path();} | |
717 | ||
718 | inline | |
719 | path temp_directory_path(system::error_code& ec) | |
720 | {return detail::temp_directory_path(&ec);} | |
721 | inline | |
722 | path unique_path(const path& p="%%%%-%%%%-%%%%-%%%%") | |
723 | {return detail::unique_path(p);} | |
724 | inline | |
725 | path unique_path(const path& p, system::error_code& ec) | |
726 | {return detail::unique_path(p, &ec);} | |
727 | inline | |
728 | path weakly_canonical(const path& p) {return detail::weakly_canonical(p);} | |
729 | ||
730 | inline | |
731 | path weakly_canonical(const path& p, system::error_code& ec) | |
732 | {return detail::weakly_canonical(p, &ec);} | |
733 | ||
734 | //--------------------------------------------------------------------------------------// | |
735 | // // | |
736 | // directory_entry // | |
737 | // // | |
738 | //--------------------------------------------------------------------------------------// | |
739 | ||
740 | // GCC has a problem with a member function named path within a namespace or | |
741 | // sub-namespace that also has a class named path. The workaround is to always | |
742 | // fully qualify the name path when it refers to the class name. | |
743 | ||
744 | class BOOST_FILESYSTEM_DECL directory_entry | |
745 | { | |
746 | public: | |
747 | typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry | |
748 | ||
749 | directory_entry() BOOST_NOEXCEPT {} | |
750 | explicit directory_entry(const boost::filesystem::path& p) | |
751 | : m_path(p), m_status(file_status()), m_symlink_status(file_status()) | |
752 | {} | |
753 | directory_entry(const boost::filesystem::path& p, | |
754 | file_status st, file_status symlink_st = file_status()) | |
755 | : m_path(p), m_status(st), m_symlink_status(symlink_st) {} | |
756 | ||
757 | directory_entry(const directory_entry& rhs) | |
758 | : m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status){} | |
759 | ||
760 | directory_entry& operator=(const directory_entry& rhs) | |
761 | { | |
762 | m_path = rhs.m_path; | |
763 | m_status = rhs.m_status; | |
764 | m_symlink_status = rhs.m_symlink_status; | |
765 | return *this; | |
766 | } | |
767 | ||
768 | // As of October 2015 the interaction between noexcept and =default is so troublesome | |
769 | // for VC++, GCC, and probably other compilers, that =default is not used with noexcept | |
770 | // functions. GCC is not even consistent for the same release on different platforms. | |
771 | ||
772 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
773 | directory_entry(directory_entry&& rhs) BOOST_NOEXCEPT | |
774 | { | |
775 | m_path = std::move(rhs.m_path); | |
776 | m_status = std::move(rhs.m_status); | |
777 | m_symlink_status = std::move(rhs.m_symlink_status); | |
778 | } | |
779 | directory_entry& operator=(directory_entry&& rhs) BOOST_NOEXCEPT | |
780 | { | |
781 | m_path = std::move(rhs.m_path); | |
782 | m_status = std::move(rhs.m_status); | |
783 | m_symlink_status = std::move(rhs.m_symlink_status); | |
784 | return *this; | |
785 | } | |
786 | #endif | |
787 | ||
788 | void assign(const boost::filesystem::path& p, | |
789 | file_status st = file_status(), file_status symlink_st = file_status()) | |
790 | { m_path = p; m_status = st; m_symlink_status = symlink_st; } | |
791 | ||
792 | void replace_filename(const boost::filesystem::path& p, | |
793 | file_status st = file_status(), file_status symlink_st = file_status()) | |
794 | { | |
795 | m_path.remove_filename(); | |
796 | m_path /= p; | |
797 | m_status = st; | |
798 | m_symlink_status = symlink_st; | |
799 | } | |
800 | ||
801 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
802 | void replace_leaf(const boost::filesystem::path& p, | |
803 | file_status st, file_status symlink_st) | |
804 | { replace_filename(p, st, symlink_st); } | |
805 | # endif | |
806 | ||
807 | const boost::filesystem::path& path() const BOOST_NOEXCEPT {return m_path;} | |
808 | operator const boost::filesystem::path&() const BOOST_NOEXCEPT | |
809 | {return m_path;} | |
810 | file_status status() const {return m_get_status();} | |
811 | file_status status(system::error_code& ec) const BOOST_NOEXCEPT | |
812 | {return m_get_status(&ec); } | |
813 | file_status symlink_status() const {return m_get_symlink_status();} | |
814 | file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT | |
815 | {return m_get_symlink_status(&ec); } | |
816 | ||
817 | bool operator==(const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path == rhs.m_path; } | |
818 | bool operator!=(const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path != rhs.m_path;} | |
819 | bool operator< (const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path < rhs.m_path;} | |
820 | bool operator<=(const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path <= rhs.m_path;} | |
821 | bool operator> (const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path > rhs.m_path;} | |
822 | bool operator>=(const directory_entry& rhs) const BOOST_NOEXCEPT {return m_path >= rhs.m_path;} | |
823 | ||
824 | private: | |
825 | boost::filesystem::path m_path; | |
826 | mutable file_status m_status; // stat()-like | |
827 | mutable file_status m_symlink_status; // lstat()-like | |
828 | ||
829 | file_status m_get_status(system::error_code* ec=0) const; | |
830 | file_status m_get_symlink_status(system::error_code* ec=0) const; | |
831 | }; // directory_entry | |
832 | ||
833 | //--------------------------------------------------------------------------------------// | |
834 | // // | |
835 | // directory_iterator helpers // | |
836 | // // | |
837 | //--------------------------------------------------------------------------------------// | |
838 | ||
839 | class directory_iterator; | |
840 | ||
841 | namespace detail | |
842 | { | |
843 | BOOST_FILESYSTEM_DECL | |
844 | system::error_code dir_itr_close(// never throws() | |
845 | void *& handle | |
846 | # if defined(BOOST_POSIX_API) | |
847 | , void *& buffer | |
848 | # endif | |
849 | ); | |
850 | ||
851 | struct dir_itr_imp | |
852 | { | |
853 | directory_entry dir_entry; | |
854 | void* handle; | |
855 | ||
856 | # ifdef BOOST_POSIX_API | |
857 | void* buffer; // see dir_itr_increment implementation | |
858 | # endif | |
859 | ||
860 | dir_itr_imp() : handle(0) | |
861 | # ifdef BOOST_POSIX_API | |
862 | , buffer(0) | |
863 | # endif | |
864 | {} | |
865 | ||
866 | ~dir_itr_imp() // never throws | |
867 | { | |
868 | dir_itr_close(handle | |
869 | # if defined(BOOST_POSIX_API) | |
870 | , buffer | |
871 | # endif | |
872 | ); | |
873 | } | |
874 | }; | |
875 | ||
876 | // see path::iterator: comment below | |
877 | BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, | |
878 | const path& p, system::error_code* ec); | |
879 | BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, | |
880 | system::error_code* ec); | |
881 | ||
882 | } // namespace detail | |
883 | ||
884 | //--------------------------------------------------------------------------------------// | |
885 | // // | |
886 | // directory_iterator // | |
887 | // // | |
888 | //--------------------------------------------------------------------------------------// | |
889 | ||
890 | class directory_iterator | |
891 | : public boost::iterator_facade< directory_iterator, | |
892 | directory_entry, | |
893 | boost::single_pass_traversal_tag > | |
894 | { | |
895 | public: | |
896 | ||
897 | directory_iterator() BOOST_NOEXCEPT {} // creates the "end" iterator | |
898 | ||
899 | // iterator_facade derived classes don't seem to like implementations in | |
900 | // separate translation unit dll's, so forward to detail functions | |
901 | explicit directory_iterator(const path& p) | |
902 | : m_imp(new detail::dir_itr_imp) | |
903 | { detail::directory_iterator_construct(*this, p, 0); } | |
904 | ||
905 | directory_iterator(const path& p, system::error_code& ec) BOOST_NOEXCEPT | |
906 | : m_imp(new detail::dir_itr_imp) | |
907 | { detail::directory_iterator_construct(*this, p, &ec); } | |
908 | ||
909 | ~directory_iterator() {} | |
910 | ||
911 | directory_iterator& increment(system::error_code& ec) BOOST_NOEXCEPT | |
912 | { | |
913 | detail::directory_iterator_increment(*this, &ec); | |
914 | return *this; | |
915 | } | |
916 | ||
917 | private: | |
918 | friend struct detail::dir_itr_imp; | |
919 | friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, | |
920 | const path& p, system::error_code* ec); | |
921 | friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, | |
922 | system::error_code* ec); | |
923 | ||
924 | // shared_ptr provides shallow-copy semantics required for InputIterators. | |
925 | // m_imp.get()==0 indicates the end iterator. | |
926 | boost::shared_ptr< detail::dir_itr_imp > m_imp; | |
927 | ||
928 | friend class boost::iterator_core_access; | |
929 | ||
930 | boost::iterator_facade< | |
931 | directory_iterator, | |
932 | directory_entry, | |
933 | boost::single_pass_traversal_tag >::reference dereference() const | |
934 | { | |
935 | BOOST_ASSERT_MSG(m_imp.get(), "attempt to dereference end iterator"); | |
936 | return m_imp->dir_entry; | |
937 | } | |
938 | ||
939 | void increment() { detail::directory_iterator_increment(*this, 0); } | |
940 | ||
941 | bool equal(const directory_iterator& rhs) const | |
942 | { return m_imp == rhs.m_imp; } | |
943 | ||
944 | }; // directory_iterator | |
945 | ||
946 | // enable directory_iterator C++11 range-base for statement use --------------------// | |
947 | ||
948 | // begin() and end() are only used by a range-based for statement in the context of | |
949 | // auto - thus the top-level const is stripped - so returning const is harmless and | |
950 | // emphasizes begin() is just a pass through. | |
951 | inline | |
952 | const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT | |
953 | {return iter;} | |
954 | inline | |
955 | directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT | |
956 | {return directory_iterator();} | |
957 | ||
958 | // enable directory_iterator BOOST_FOREACH -----------------------------------------// | |
959 | ||
960 | inline | |
961 | directory_iterator& range_begin(directory_iterator& iter) BOOST_NOEXCEPT | |
962 | {return iter;} | |
963 | inline | |
964 | directory_iterator range_begin(const directory_iterator& iter) BOOST_NOEXCEPT | |
965 | {return iter;} | |
966 | inline | |
967 | directory_iterator range_end(const directory_iterator&) BOOST_NOEXCEPT | |
968 | {return directory_iterator();} | |
969 | } // namespace filesystem | |
970 | ||
971 | // namespace boost template specializations | |
972 | template<> | |
973 | struct range_mutable_iterator<boost::filesystem::directory_iterator> | |
974 | { typedef boost::filesystem::directory_iterator type; }; | |
975 | template<> | |
976 | struct range_const_iterator <boost::filesystem::directory_iterator> | |
977 | { typedef boost::filesystem::directory_iterator type; }; | |
978 | ||
979 | namespace filesystem | |
980 | { | |
981 | ||
982 | //--------------------------------------------------------------------------------------// | |
983 | // // | |
984 | // recursive_directory_iterator helpers // | |
985 | // // | |
986 | //--------------------------------------------------------------------------------------// | |
987 | ||
988 | BOOST_SCOPED_ENUM_START(symlink_option) | |
989 | { | |
990 | none, | |
991 | no_recurse = none, // don't follow directory symlinks (default behavior) | |
992 | recurse, // follow directory symlinks | |
993 | _detail_no_push = recurse << 1 // internal use only | |
994 | }; | |
995 | BOOST_SCOPED_ENUM_END | |
996 | ||
997 | BOOST_BITMASK(BOOST_SCOPED_ENUM(symlink_option)) | |
998 | ||
999 | namespace detail | |
1000 | { | |
1001 | struct recur_dir_itr_imp | |
1002 | { | |
1003 | typedef directory_iterator element_type; | |
1004 | std::stack< element_type, std::vector< element_type > > m_stack; | |
1005 | int m_level; | |
1006 | BOOST_SCOPED_ENUM(symlink_option) m_options; | |
1007 | ||
1008 | recur_dir_itr_imp() : m_level(0), m_options(symlink_option::none) {} | |
1009 | ||
1010 | void increment(system::error_code* ec); // ec == 0 means throw on error | |
1011 | ||
1012 | bool push_directory(system::error_code& ec) BOOST_NOEXCEPT; | |
1013 | ||
1014 | void pop(); | |
1015 | ||
1016 | }; | |
1017 | ||
1018 | // Implementation is inline to avoid dynamic linking difficulties with m_stack: | |
1019 | // Microsoft warning C4251, m_stack needs to have dll-interface to be used by | |
1020 | // clients of struct 'boost::filesystem::detail::recur_dir_itr_imp' | |
1021 | ||
1022 | inline | |
1023 | bool recur_dir_itr_imp::push_directory(system::error_code& ec) BOOST_NOEXCEPT | |
1024 | // Returns: true if push occurs, otherwise false. Always returns false on error. | |
1025 | { | |
1026 | ec.clear(); | |
1027 | ||
1028 | // Discover if the iterator is for a directory that needs to be recursed into, | |
1029 | // taking symlinks and options into account. | |
1030 | ||
1031 | if ((m_options & symlink_option::_detail_no_push) == symlink_option::_detail_no_push) | |
1032 | m_options &= ~symlink_option::_detail_no_push; | |
1033 | ||
1034 | else | |
1035 | { | |
1036 | // Logic for following predicate was contributed by Daniel Aarno to handle cyclic | |
1037 | // symlinks correctly and efficiently, fixing ticket #5652. | |
1038 | // if (((m_options & symlink_option::recurse) == symlink_option::recurse | |
1039 | // || !is_symlink(m_stack.top()->symlink_status())) | |
1040 | // && is_directory(m_stack.top()->status())) ... | |
1041 | // The predicate code has since been rewritten to pass error_code arguments, | |
1042 | // per ticket #5653. | |
1043 | ||
1044 | file_status symlink_stat; | |
1045 | ||
1046 | if ((m_options & symlink_option::recurse) != symlink_option::recurse) | |
1047 | { | |
1048 | symlink_stat = m_stack.top()->symlink_status(ec); | |
1049 | if (ec) | |
1050 | return false; | |
1051 | } | |
1052 | ||
1053 | if ((m_options & symlink_option::recurse) == symlink_option::recurse | |
1054 | || !is_symlink(symlink_stat)) | |
1055 | { | |
1056 | file_status stat = m_stack.top()->status(ec); | |
1057 | if (ec || !is_directory(stat)) | |
1058 | return false; | |
1059 | ||
1060 | directory_iterator next(m_stack.top()->path(), ec); | |
1061 | if (!ec && next != directory_iterator()) | |
1062 | { | |
1063 | m_stack.push(next); | |
1064 | ++m_level; | |
1065 | return true; | |
1066 | } | |
1067 | } | |
1068 | } | |
1069 | return false; | |
1070 | } | |
1071 | ||
1072 | inline | |
1073 | void recur_dir_itr_imp::increment(system::error_code* ec) | |
1074 | // ec == 0 means throw on error | |
1075 | // | |
1076 | // Invariant: On return, the top of the iterator stack is the next valid (possibly | |
1077 | // end) iterator, regardless of whether or not an error is reported, and regardless of | |
1078 | // whether any error is reported by exception or error code. In other words, progress | |
1079 | // is always made so a loop on the iterator will always eventually terminate | |
1080 | // regardless of errors. | |
1081 | { | |
1082 | system::error_code ec_push_directory; | |
1083 | ||
1084 | // if various conditions are met, push a directory_iterator into the iterator stack | |
1085 | if (push_directory(ec_push_directory)) | |
1086 | { | |
1087 | if (ec) | |
1088 | ec->clear(); | |
1089 | return; | |
1090 | } | |
1091 | ||
1092 | // Do the actual increment operation on the top iterator in the iterator | |
1093 | // stack, popping the stack if necessary, until either the stack is empty or a | |
1094 | // non-end iterator is reached. | |
1095 | while (!m_stack.empty() && ++m_stack.top() == directory_iterator()) | |
1096 | { | |
1097 | m_stack.pop(); | |
1098 | --m_level; | |
1099 | } | |
1100 | ||
1101 | // report errors if any | |
1102 | if (ec_push_directory) | |
1103 | { | |
1104 | if (ec) | |
1105 | *ec = ec_push_directory; | |
1106 | else | |
1107 | { | |
1108 | BOOST_FILESYSTEM_THROW(filesystem_error( | |
1109 | "filesystem::recursive_directory_iterator directory error", | |
1110 | ec_push_directory)); | |
1111 | } | |
1112 | } | |
1113 | else if (ec) | |
1114 | ec->clear(); | |
1115 | } | |
1116 | ||
1117 | inline | |
1118 | void recur_dir_itr_imp::pop() | |
1119 | { | |
1120 | BOOST_ASSERT_MSG(m_level > 0, | |
1121 | "pop() on recursive_directory_iterator with level < 1"); | |
1122 | ||
1123 | do | |
1124 | { | |
1125 | m_stack.pop(); | |
1126 | --m_level; | |
1127 | } | |
1128 | while (!m_stack.empty() && ++m_stack.top() == directory_iterator()); | |
1129 | } | |
1130 | } // namespace detail | |
1131 | ||
1132 | //--------------------------------------------------------------------------------------// | |
1133 | // // | |
1134 | // recursive_directory_iterator // | |
1135 | // // | |
1136 | //--------------------------------------------------------------------------------------// | |
1137 | ||
1138 | class recursive_directory_iterator | |
1139 | : public boost::iterator_facade< | |
1140 | recursive_directory_iterator, | |
1141 | directory_entry, | |
1142 | boost::single_pass_traversal_tag > | |
1143 | { | |
1144 | public: | |
1145 | ||
1146 | recursive_directory_iterator() BOOST_NOEXCEPT {} // creates the "end" iterator | |
1147 | ||
1148 | explicit recursive_directory_iterator(const path& dir_path) // throws if !exists() | |
1149 | : m_imp(new detail::recur_dir_itr_imp) | |
1150 | { | |
1151 | m_imp->m_options = symlink_option::none; | |
1152 | m_imp->m_stack.push(directory_iterator(dir_path)); | |
1153 | if (m_imp->m_stack.top() == directory_iterator()) | |
1154 | { m_imp.reset(); } | |
1155 | } | |
1156 | ||
1157 | recursive_directory_iterator(const path& dir_path, | |
1158 | BOOST_SCOPED_ENUM(symlink_option) opt) // throws if !exists() | |
1159 | : m_imp(new detail::recur_dir_itr_imp) | |
1160 | { | |
1161 | m_imp->m_options = opt; | |
1162 | m_imp->m_stack.push(directory_iterator(dir_path)); | |
1163 | if (m_imp->m_stack.top() == directory_iterator()) | |
1164 | { m_imp.reset (); } | |
1165 | } | |
1166 | ||
1167 | recursive_directory_iterator(const path& dir_path, | |
1168 | BOOST_SCOPED_ENUM(symlink_option) opt, | |
1169 | system::error_code & ec) BOOST_NOEXCEPT | |
1170 | : m_imp(new detail::recur_dir_itr_imp) | |
1171 | { | |
1172 | m_imp->m_options = opt; | |
1173 | m_imp->m_stack.push(directory_iterator(dir_path, ec)); | |
1174 | if (m_imp->m_stack.top() == directory_iterator()) | |
1175 | { m_imp.reset (); } | |
1176 | } | |
1177 | ||
1178 | recursive_directory_iterator(const path& dir_path, | |
1179 | system::error_code & ec) BOOST_NOEXCEPT | |
1180 | : m_imp(new detail::recur_dir_itr_imp) | |
1181 | { | |
1182 | m_imp->m_options = symlink_option::none; | |
1183 | m_imp->m_stack.push(directory_iterator(dir_path, ec)); | |
1184 | if (m_imp->m_stack.top() == directory_iterator()) | |
1185 | { m_imp.reset (); } | |
1186 | } | |
1187 | ||
1188 | recursive_directory_iterator& increment(system::error_code& ec) BOOST_NOEXCEPT | |
1189 | { | |
1190 | BOOST_ASSERT_MSG(m_imp.get(), | |
1191 | "increment() on end recursive_directory_iterator"); | |
1192 | m_imp->increment(&ec); | |
1193 | if (m_imp->m_stack.empty()) | |
1194 | m_imp.reset(); // done, so make end iterator | |
1195 | return *this; | |
1196 | } | |
1197 | ||
1198 | int depth() const BOOST_NOEXCEPT | |
1199 | { | |
1200 | BOOST_ASSERT_MSG(m_imp.get(), | |
1201 | "depth() on end recursive_directory_iterator"); | |
1202 | return m_imp->m_level; | |
1203 | } | |
1204 | ||
1205 | int level() const BOOST_NOEXCEPT { return depth(); } | |
1206 | ||
1207 | bool recursion_pending() const BOOST_NOEXCEPT | |
1208 | { | |
1209 | BOOST_ASSERT_MSG(m_imp.get(), | |
1210 | "is_no_push_requested() on end recursive_directory_iterator"); | |
1211 | return (m_imp->m_options & symlink_option::_detail_no_push) | |
1212 | == symlink_option::_detail_no_push; | |
1213 | } | |
1214 | ||
1215 | bool no_push_pending() const BOOST_NOEXCEPT { return recursion_pending(); } | |
1216 | ||
1217 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED | |
1218 | bool no_push_request() const BOOST_NOEXCEPT { return no_push_pending(); } | |
1219 | # endif | |
1220 | ||
1221 | void pop() | |
1222 | { | |
1223 | BOOST_ASSERT_MSG(m_imp.get(), | |
1224 | "pop() on end recursive_directory_iterator"); | |
1225 | m_imp->pop(); | |
1226 | if (m_imp->m_stack.empty()) m_imp.reset(); // done, so make end iterator | |
1227 | } | |
1228 | ||
1229 | void disable_recursion_pending(bool value=true) BOOST_NOEXCEPT | |
1230 | { | |
1231 | BOOST_ASSERT_MSG(m_imp.get(), | |
1232 | "no_push() on end recursive_directory_iterator"); | |
1233 | if (value) | |
1234 | m_imp->m_options |= symlink_option::_detail_no_push; | |
1235 | else | |
1236 | m_imp->m_options &= ~symlink_option::_detail_no_push; | |
1237 | } | |
1238 | ||
1239 | void no_push(bool value=true) BOOST_NOEXCEPT { disable_recursion_pending(value); } | |
1240 | ||
1241 | file_status status() const | |
1242 | { | |
1243 | BOOST_ASSERT_MSG(m_imp.get(), | |
1244 | "status() on end recursive_directory_iterator"); | |
1245 | return m_imp->m_stack.top()->status(); | |
1246 | } | |
1247 | ||
1248 | file_status symlink_status() const | |
1249 | { | |
1250 | BOOST_ASSERT_MSG(m_imp.get(), | |
1251 | "symlink_status() on end recursive_directory_iterator"); | |
1252 | return m_imp->m_stack.top()->symlink_status(); | |
1253 | } | |
1254 | ||
1255 | private: | |
1256 | ||
1257 | // shared_ptr provides shallow-copy semantics required for InputIterators. | |
1258 | // m_imp.get()==0 indicates the end iterator. | |
1259 | boost::shared_ptr< detail::recur_dir_itr_imp > m_imp; | |
1260 | ||
1261 | friend class boost::iterator_core_access; | |
1262 | ||
1263 | boost::iterator_facade< | |
1264 | recursive_directory_iterator, | |
1265 | directory_entry, | |
1266 | boost::single_pass_traversal_tag >::reference | |
1267 | dereference() const | |
1268 | { | |
1269 | BOOST_ASSERT_MSG(m_imp.get(), | |
1270 | "dereference of end recursive_directory_iterator"); | |
1271 | return *m_imp->m_stack.top(); | |
1272 | } | |
1273 | ||
1274 | void increment() | |
1275 | { | |
1276 | BOOST_ASSERT_MSG(m_imp.get(), | |
1277 | "increment of end recursive_directory_iterator"); | |
1278 | m_imp->increment(0); | |
1279 | if (m_imp->m_stack.empty()) | |
1280 | m_imp.reset(); // done, so make end iterator | |
1281 | } | |
1282 | ||
1283 | bool equal(const recursive_directory_iterator& rhs) const | |
1284 | { return m_imp == rhs.m_imp; } | |
1285 | ||
1286 | }; // recursive directory iterator | |
1287 | ||
1288 | // enable recursive directory iterator C++11 range-base for statement use ----------// | |
1289 | ||
1290 | // begin() and end() are only used by a range-based for statement in the context of | |
1291 | // auto - thus the top-level const is stripped - so returning const is harmless and | |
1292 | // emphasizes begin() is just a pass through. | |
1293 | inline | |
1294 | const recursive_directory_iterator& | |
1295 | begin(const recursive_directory_iterator& iter) BOOST_NOEXCEPT | |
1296 | {return iter;} | |
1297 | inline | |
1298 | recursive_directory_iterator end(const recursive_directory_iterator&) BOOST_NOEXCEPT | |
1299 | {return recursive_directory_iterator();} | |
1300 | ||
1301 | // enable recursive directory iterator BOOST_FOREACH -------------------------------// | |
1302 | ||
1303 | inline | |
1304 | recursive_directory_iterator& | |
1305 | range_begin(recursive_directory_iterator& iter) BOOST_NOEXCEPT | |
1306 | {return iter;} | |
1307 | inline | |
1308 | recursive_directory_iterator | |
1309 | range_begin(const recursive_directory_iterator& iter) BOOST_NOEXCEPT | |
1310 | {return iter;} | |
1311 | inline | |
1312 | recursive_directory_iterator range_end(const recursive_directory_iterator&) BOOST_NOEXCEPT | |
1313 | {return recursive_directory_iterator();} | |
1314 | } // namespace filesystem | |
1315 | ||
1316 | // namespace boost template specializations | |
1317 | template<> | |
1318 | struct range_mutable_iterator<boost::filesystem::recursive_directory_iterator> | |
1319 | { typedef boost::filesystem::recursive_directory_iterator type; }; | |
1320 | template<> | |
1321 | struct range_const_iterator <boost::filesystem::recursive_directory_iterator> | |
1322 | { typedef boost::filesystem::recursive_directory_iterator type; }; | |
1323 | ||
1324 | namespace filesystem | |
1325 | { | |
1326 | ||
1327 | # if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) | |
1328 | typedef recursive_directory_iterator wrecursive_directory_iterator; | |
1329 | # endif | |
1330 | ||
1331 | // test helper -----------------------------------------------------------------------// | |
1332 | ||
1333 | // Not part of the documented interface since false positives are possible; | |
1334 | // there is no law that says that an OS that has large stat.st_size | |
1335 | // actually supports large file sizes. | |
1336 | ||
1337 | namespace detail | |
1338 | { | |
1339 | BOOST_FILESYSTEM_DECL bool possible_large_file_size_support(); | |
1340 | } | |
1341 | ||
1342 | } // namespace filesystem | |
1343 | } // namespace boost | |
1344 | ||
1345 | #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas | |
1346 | #endif // BOOST_FILESYSTEM3_OPERATIONS_HPP |