1 // Filesystem directory utilities -*- C++ -*- 2 3 // Copyright (C) 2014-2019 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file include/bits/fs_dir.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{filesystem} 28 */ 29 30 #ifndef _GLIBCXX_FS_DIR_H 31 #define _GLIBCXX_FS_DIR_H 1 32 33 #if __cplusplus >= 201703L 34 # include <typeinfo> 35 # include <ext/concurrence.h> 36 # include <bits/unique_ptr.h> 37 # include <bits/shared_ptr.h> 38 39 namespace std _GLIBCXX_VISIBILITY(default) 40 { 41 _GLIBCXX_BEGIN_NAMESPACE_VERSION 42 43 namespace filesystem 44 { 45 /** 46 * @ingroup filesystem 47 * @{ 48 */ 49 50 class file_status 51 { 52 public: 53 // constructors and destructor 54 file_status() noexcept : file_status(file_type::none) {} 55 56 explicit 57 file_status(file_type __ft, perms __prms = perms::unknown) noexcept 58 : _M_type(__ft), _M_perms(__prms) { } 59 60 file_status(const file_status&) noexcept = default; 61 file_status(file_status&&) noexcept = default; 62 ~file_status() = default; 63 64 file_status& operator=(const file_status&) noexcept = default; 65 file_status& operator=(file_status&&) noexcept = default; 66 67 // observers 68 file_type type() const noexcept { return _M_type; } 69 perms permissions() const noexcept { return _M_perms; } 70 71 // modifiers 72 void type(file_type __ft) noexcept { _M_type = __ft; } 73 void permissions(perms __prms) noexcept { _M_perms = __prms; } 74 75 private: 76 file_type _M_type; 77 perms _M_perms; 78 }; 79 80 _GLIBCXX_BEGIN_NAMESPACE_CXX11 81 82 struct _Dir; 83 class directory_iterator; 84 class recursive_directory_iterator; 85 86 class directory_entry 87 { 88 public: 89 // constructors and destructor 90 directory_entry() noexcept = default; 91 directory_entry(const directory_entry&) = default; 92 directory_entry(directory_entry&&) noexcept = default; 93 94 explicit 95 directory_entry(const filesystem::path& __p) 96 : _M_path(__p) 97 { refresh(); } 98 99 directory_entry(const filesystem::path& __p, error_code& __ec) 100 : _M_path(__p) 101 { 102 refresh(__ec); 103 if (__ec) 104 _M_path.clear(); 105 } 106 107 ~directory_entry() = default; 108 109 // modifiers 110 directory_entry& operator=(const directory_entry&) = default; 111 directory_entry& operator=(directory_entry&&) noexcept = default; 112 113 void 114 assign(const filesystem::path& __p) 115 { 116 _M_path = __p; 117 refresh(); 118 } 119 120 void 121 assign(const filesystem::path& __p, error_code& __ec) 122 { 123 _M_path = __p; 124 refresh(__ec); 125 } 126 127 void 128 replace_filename(const filesystem::path& __p) 129 { 130 _M_path.replace_filename(__p); 131 refresh(); 132 } 133 134 void 135 replace_filename(const filesystem::path& __p, error_code& __ec) 136 { 137 _M_path.replace_filename(__p); 138 refresh(__ec); 139 } 140 141 void 142 refresh() 143 { _M_type = symlink_status().type(); } 144 145 void 146 refresh(error_code& __ec) noexcept 147 { _M_type = symlink_status(__ec).type(); } 148 149 // observers 150 const filesystem::path& path() const noexcept { return _M_path; } 151 operator const filesystem::path& () const noexcept { return _M_path; } 152 153 bool 154 exists() const 155 { return filesystem::exists(file_status{_M_file_type()}); } 156 157 bool 158 exists(error_code& __ec) const noexcept 159 { return filesystem::exists(file_status{_M_file_type(__ec)}); } 160 161 bool 162 is_block_file() const 163 { return _M_file_type() == file_type::block; } 164 165 bool 166 is_block_file(error_code& __ec) const noexcept 167 { return _M_file_type(__ec) == file_type::block; } 168 169 bool 170 is_character_file() const 171 { return _M_file_type() == file_type::character; } 172 173 bool 174 is_character_file(error_code& __ec) const noexcept 175 { return _M_file_type(__ec) == file_type::character; } 176 177 bool 178 is_directory() const 179 { return _M_file_type() == file_type::directory; } 180 181 bool 182 is_directory(error_code& __ec) const noexcept 183 { return _M_file_type(__ec) == file_type::directory; } 184 185 bool 186 is_fifo() const 187 { return _M_file_type() == file_type::fifo; } 188 189 bool 190 is_fifo(error_code& __ec) const noexcept 191 { return _M_file_type(__ec) == file_type::fifo; } 192 193 bool 194 is_other() const 195 { return filesystem::is_other(file_status{_M_file_type()}); } 196 197 bool 198 is_other(error_code& __ec) const noexcept 199 { return filesystem::is_other(file_status{_M_file_type(__ec)}); } 200 201 bool 202 is_regular_file() const 203 { return _M_file_type() == file_type::regular; } 204 205 bool 206 is_regular_file(error_code& __ec) const noexcept 207 { return _M_file_type(__ec) == file_type::regular; } 208 209 bool 210 is_socket() const 211 { return _M_file_type() == file_type::socket; } 212 213 bool 214 is_socket(error_code& __ec) const noexcept 215 { return _M_file_type(__ec) == file_type::socket; } 216 217 bool 218 is_symlink() const 219 { 220 if (_M_type != file_type::none) 221 return _M_type == file_type::symlink; 222 return symlink_status().type() == file_type::symlink; 223 } 224 225 bool 226 is_symlink(error_code& __ec) const noexcept 227 { 228 if (_M_type != file_type::none) 229 return _M_type == file_type::symlink; 230 return symlink_status(__ec).type() == file_type::symlink; 231 } 232 233 uintmax_t 234 file_size() const 235 { return filesystem::file_size(_M_path); } 236 237 uintmax_t 238 file_size(error_code& __ec) const noexcept 239 { return filesystem::file_size(_M_path, __ec); } 240 241 uintmax_t 242 hard_link_count() const 243 { return filesystem::hard_link_count(_M_path); } 244 245 uintmax_t 246 hard_link_count(error_code& __ec) const noexcept 247 { return filesystem::hard_link_count(_M_path, __ec); } 248 249 file_time_type 250 last_write_time() const 251 { return filesystem::last_write_time(_M_path); } 252 253 254 file_time_type 255 last_write_time(error_code& __ec) const noexcept 256 { return filesystem::last_write_time(_M_path, __ec); } 257 258 file_status 259 status() const 260 { return filesystem::status(_M_path); } 261 262 file_status 263 status(error_code& __ec) const noexcept 264 { return filesystem::status(_M_path, __ec); } 265 266 file_status 267 symlink_status() const 268 { return filesystem::symlink_status(_M_path); } 269 270 file_status 271 symlink_status(error_code& __ec) const noexcept 272 { return filesystem::symlink_status(_M_path, __ec); } 273 274 bool 275 operator< (const directory_entry& __rhs) const noexcept 276 { return _M_path < __rhs._M_path; } 277 278 bool 279 operator==(const directory_entry& __rhs) const noexcept 280 { return _M_path == __rhs._M_path; } 281 282 bool 283 operator!=(const directory_entry& __rhs) const noexcept 284 { return _M_path != __rhs._M_path; } 285 286 bool 287 operator<=(const directory_entry& __rhs) const noexcept 288 { return _M_path <= __rhs._M_path; } 289 290 bool 291 operator> (const directory_entry& __rhs) const noexcept 292 { return _M_path > __rhs._M_path; } 293 294 bool 295 operator>=(const directory_entry& __rhs) const noexcept 296 { return _M_path >= __rhs._M_path; } 297 298 private: 299 friend class _Dir; 300 friend class directory_iterator; 301 friend class recursive_directory_iterator; 302 303 // _GLIBCXX_RESOLVE_LIB_DEFECTS 304 // 3171. LWG 2989 breaks directory_entry stream insertion 305 template<typename _CharT, typename _Traits> 306 friend basic_ostream<_CharT, _Traits>& 307 operator<<(basic_ostream<_CharT, _Traits>& __os, 308 const directory_entry& __d) 309 { return __os << __d.path(); } 310 311 directory_entry(const filesystem::path& __p, file_type __t) 312 : _M_path(__p), _M_type(__t) 313 { } 314 315 // Equivalent to status().type() but uses cached value, if any. 316 file_type 317 _M_file_type() const 318 { 319 if (_M_type != file_type::none && _M_type != file_type::symlink) 320 return _M_type; 321 return status().type(); 322 } 323 324 // Equivalent to status(__ec).type() but uses cached value, if any. 325 file_type 326 _M_file_type(error_code& __ec) const noexcept 327 { 328 if (_M_type != file_type::none && _M_type != file_type::symlink) 329 { 330 __ec.clear(); 331 return _M_type; 332 } 333 return status(__ec).type(); 334 } 335 336 filesystem::path _M_path; 337 file_type _M_type = file_type::none; 338 }; 339 340 struct __directory_iterator_proxy 341 { 342 const directory_entry& operator*() const& noexcept { return _M_entry; } 343 344 directory_entry operator*() && noexcept { return std::move(_M_entry); } 345 346 private: 347 friend class directory_iterator; 348 friend class recursive_directory_iterator; 349 350 explicit 351 __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { } 352 353 directory_entry _M_entry; 354 }; 355 356 class directory_iterator 357 { 358 public: 359 typedef directory_entry value_type; 360 typedef ptrdiff_t difference_type; 361 typedef const directory_entry* pointer; 362 typedef const directory_entry& reference; 363 typedef input_iterator_tag iterator_category; 364 365 directory_iterator() = default; 366 367 explicit 368 directory_iterator(const path& __p) 369 : directory_iterator(__p, directory_options::none, nullptr) { } 370 371 directory_iterator(const path& __p, directory_options __options) 372 : directory_iterator(__p, __options, nullptr) { } 373 374 directory_iterator(const path& __p, error_code& __ec) 375 : directory_iterator(__p, directory_options::none, __ec) { } 376 377 directory_iterator(const path& __p, directory_options __options, 378 error_code& __ec) 379 : directory_iterator(__p, __options, &__ec) { } 380 381 directory_iterator(const directory_iterator& __rhs) = default; 382 383 directory_iterator(directory_iterator&& __rhs) noexcept = default; 384 385 ~directory_iterator() = default; 386 387 directory_iterator& 388 operator=(const directory_iterator& __rhs) = default; 389 390 directory_iterator& 391 operator=(directory_iterator&& __rhs) noexcept = default; 392 393 const directory_entry& operator*() const noexcept; 394 const directory_entry* operator->() const noexcept { return &**this; } 395 directory_iterator& operator++(); 396 directory_iterator& increment(error_code& __ec); 397 398 __directory_iterator_proxy operator++(int) 399 { 400 __directory_iterator_proxy __pr{**this}; 401 ++*this; 402 return __pr; 403 } 404 405 private: 406 directory_iterator(const path&, directory_options, error_code*); 407 408 friend bool 409 operator==(const directory_iterator& __lhs, 410 const directory_iterator& __rhs) noexcept 411 { 412 return !__rhs._M_dir.owner_before(__lhs._M_dir) 413 && !__lhs._M_dir.owner_before(__rhs._M_dir); 414 } 415 416 friend bool 417 operator!=(const directory_iterator& __lhs, 418 const directory_iterator& __rhs) noexcept 419 { return !(__lhs == __rhs); } 420 421 friend class recursive_directory_iterator; 422 423 std::__shared_ptr<_Dir> _M_dir; 424 }; 425 426 inline directory_iterator 427 begin(directory_iterator __iter) noexcept 428 { return __iter; } 429 430 inline directory_iterator 431 end(directory_iterator) noexcept 432 { return directory_iterator(); } 433 434 class recursive_directory_iterator 435 { 436 public: 437 typedef directory_entry value_type; 438 typedef ptrdiff_t difference_type; 439 typedef const directory_entry* pointer; 440 typedef const directory_entry& reference; 441 typedef input_iterator_tag iterator_category; 442 443 recursive_directory_iterator() = default; 444 445 explicit 446 recursive_directory_iterator(const path& __p) 447 : recursive_directory_iterator(__p, directory_options::none, nullptr) { } 448 449 recursive_directory_iterator(const path& __p, directory_options __options) 450 : recursive_directory_iterator(__p, __options, nullptr) { } 451 452 recursive_directory_iterator(const path& __p, directory_options __options, 453 error_code& __ec) 454 : recursive_directory_iterator(__p, __options, &__ec) { } 455 456 recursive_directory_iterator(const path& __p, error_code& __ec) 457 : recursive_directory_iterator(__p, directory_options::none, &__ec) { } 458 459 recursive_directory_iterator( 460 const recursive_directory_iterator&) = default; 461 462 recursive_directory_iterator(recursive_directory_iterator&&) = default; 463 464 ~recursive_directory_iterator(); 465 466 // observers 467 directory_options options() const noexcept; 468 int depth() const noexcept; 469 bool recursion_pending() const noexcept; 470 471 const directory_entry& operator*() const noexcept; 472 const directory_entry* operator->() const noexcept { return &**this; } 473 474 // modifiers 475 recursive_directory_iterator& 476 operator=(const recursive_directory_iterator& __rhs) noexcept; 477 recursive_directory_iterator& 478 operator=(recursive_directory_iterator&& __rhs) noexcept; 479 480 recursive_directory_iterator& operator++(); 481 recursive_directory_iterator& increment(error_code& __ec); 482 483 __directory_iterator_proxy operator++(int) 484 { 485 __directory_iterator_proxy __pr{**this}; 486 ++*this; 487 return __pr; 488 } 489 490 void pop(); 491 void pop(error_code&); 492 493 void disable_recursion_pending() noexcept; 494 495 private: 496 recursive_directory_iterator(const path&, directory_options, error_code*); 497 498 friend bool 499 operator==(const recursive_directory_iterator& __lhs, 500 const recursive_directory_iterator& __rhs) noexcept 501 { 502 return !__rhs._M_dirs.owner_before(__lhs._M_dirs) 503 && !__lhs._M_dirs.owner_before(__rhs._M_dirs); 504 } 505 506 friend bool 507 operator!=(const recursive_directory_iterator& __lhs, 508 const recursive_directory_iterator& __rhs) noexcept 509 { return !(__lhs == __rhs); } 510 511 struct _Dir_stack; 512 std::__shared_ptr<_Dir_stack> _M_dirs; 513 }; 514 515 inline recursive_directory_iterator 516 begin(recursive_directory_iterator __iter) noexcept 517 { return __iter; } 518 519 inline recursive_directory_iterator 520 end(recursive_directory_iterator) noexcept 521 { return recursive_directory_iterator(); } 522 523 _GLIBCXX_END_NAMESPACE_CXX11 524 525 // @} group filesystem 526 } // namespace filesystem 527 528 // Use explicit instantiations of these types. Any inconsistency in the 529 // value of __default_lock_policy between code including this header and 530 // the library will cause a linker error. 531 extern template class 532 __shared_ptr<filesystem::_Dir>; 533 extern template class 534 __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>; 535 536 _GLIBCXX_END_NAMESPACE_VERSION 537 } // namespace std 538 539 #endif // C++17 540 541 #endif // _GLIBCXX_FS_DIR_H 542