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