1 // Filesystem directory utilities -*- C++ -*- 2 3 // Copyright (C) 2014-2018 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 directory_entry(const filesystem::path& __p, file_type __t) 304 : _M_path(__p), _M_type(__t) 305 { } 306 307 // Equivalent to status().type() but uses cached value, if any. 308 file_type 309 _M_file_type() const 310 { 311 if (_M_type != file_type::none && _M_type != file_type::symlink) 312 return _M_type; 313 return status().type(); 314 } 315 316 // Equivalent to status(__ec).type() but uses cached value, if any. 317 file_type 318 _M_file_type(error_code& __ec) const noexcept 319 { 320 if (_M_type != file_type::none && _M_type != file_type::symlink) 321 { 322 __ec.clear(); 323 return _M_type; 324 } 325 return status(__ec).type(); 326 } 327 328 filesystem::path _M_path; 329 file_type _M_type = file_type::none; 330 }; 331 332 struct __directory_iterator_proxy 333 { 334 const directory_entry& operator*() const& noexcept { return _M_entry; } 335 336 directory_entry operator*() && noexcept { return std::move(_M_entry); } 337 338 private: 339 friend class directory_iterator; 340 friend class recursive_directory_iterator; 341 342 explicit 343 __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { } 344 345 directory_entry _M_entry; 346 }; 347 348 class directory_iterator 349 { 350 public: 351 typedef directory_entry value_type; 352 typedef ptrdiff_t difference_type; 353 typedef const directory_entry* pointer; 354 typedef const directory_entry& reference; 355 typedef input_iterator_tag iterator_category; 356 357 directory_iterator() = default; 358 359 explicit 360 directory_iterator(const path& __p) 361 : directory_iterator(__p, directory_options::none, nullptr) { } 362 363 directory_iterator(const path& __p, directory_options __options) 364 : directory_iterator(__p, __options, nullptr) { } 365 366 directory_iterator(const path& __p, error_code& __ec) 367 : directory_iterator(__p, directory_options::none, __ec) { } 368 369 directory_iterator(const path& __p, directory_options __options, 370 error_code& __ec) 371 : directory_iterator(__p, __options, &__ec) { } 372 373 directory_iterator(const directory_iterator& __rhs) = default; 374 375 directory_iterator(directory_iterator&& __rhs) noexcept = default; 376 377 ~directory_iterator() = default; 378 379 directory_iterator& 380 operator=(const directory_iterator& __rhs) = default; 381 382 directory_iterator& 383 operator=(directory_iterator&& __rhs) noexcept = default; 384 385 const directory_entry& operator*() const; 386 const directory_entry* operator->() const { return &**this; } 387 directory_iterator& operator++(); 388 directory_iterator& increment(error_code& __ec); 389 390 __directory_iterator_proxy operator++(int) 391 { 392 __directory_iterator_proxy __pr{**this}; 393 ++*this; 394 return __pr; 395 } 396 397 private: 398 directory_iterator(const path&, directory_options, error_code*); 399 400 friend bool 401 operator==(const directory_iterator& __lhs, 402 const directory_iterator& __rhs); 403 404 friend class recursive_directory_iterator; 405 406 std::shared_ptr<_Dir> _M_dir; 407 }; 408 409 inline directory_iterator 410 begin(directory_iterator __iter) noexcept 411 { return __iter; } 412 413 inline directory_iterator 414 end(directory_iterator) noexcept 415 { return directory_iterator(); } 416 417 inline bool 418 operator==(const directory_iterator& __lhs, const directory_iterator& __rhs) 419 { 420 return !__rhs._M_dir.owner_before(__lhs._M_dir) 421 && !__lhs._M_dir.owner_before(__rhs._M_dir); 422 } 423 424 inline bool 425 operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs) 426 { return !(__lhs == __rhs); } 427 428 class recursive_directory_iterator 429 { 430 public: 431 typedef directory_entry value_type; 432 typedef ptrdiff_t difference_type; 433 typedef const directory_entry* pointer; 434 typedef const directory_entry& reference; 435 typedef input_iterator_tag iterator_category; 436 437 recursive_directory_iterator() = default; 438 439 explicit 440 recursive_directory_iterator(const path& __p) 441 : recursive_directory_iterator(__p, directory_options::none, nullptr) { } 442 443 recursive_directory_iterator(const path& __p, directory_options __options) 444 : recursive_directory_iterator(__p, __options, nullptr) { } 445 446 recursive_directory_iterator(const path& __p, directory_options __options, 447 error_code& __ec) 448 : recursive_directory_iterator(__p, __options, &__ec) { } 449 450 recursive_directory_iterator(const path& __p, error_code& __ec) 451 : recursive_directory_iterator(__p, directory_options::none, &__ec) { } 452 453 recursive_directory_iterator( 454 const recursive_directory_iterator&) = default; 455 456 recursive_directory_iterator(recursive_directory_iterator&&) = default; 457 458 ~recursive_directory_iterator(); 459 460 // observers 461 directory_options options() const { return _M_options; } 462 int depth() const; 463 bool recursion_pending() const { return _M_pending; } 464 465 const directory_entry& operator*() const; 466 const directory_entry* operator->() const { return &**this; } 467 468 // modifiers 469 recursive_directory_iterator& 470 operator=(const recursive_directory_iterator& __rhs) noexcept; 471 recursive_directory_iterator& 472 operator=(recursive_directory_iterator&& __rhs) noexcept; 473 474 recursive_directory_iterator& operator++(); 475 recursive_directory_iterator& increment(error_code& __ec); 476 477 __directory_iterator_proxy operator++(int) 478 { 479 __directory_iterator_proxy __pr{**this}; 480 ++*this; 481 return __pr; 482 } 483 484 void pop(); 485 void pop(error_code&); 486 487 void disable_recursion_pending() { _M_pending = false; } 488 489 private: 490 recursive_directory_iterator(const path&, directory_options, error_code*); 491 492 friend bool 493 operator==(const recursive_directory_iterator& __lhs, 494 const recursive_directory_iterator& __rhs); 495 496 struct _Dir_stack; 497 std::shared_ptr<_Dir_stack> _M_dirs; 498 directory_options _M_options = {}; 499 bool _M_pending = false; 500 }; 501 502 inline recursive_directory_iterator 503 begin(recursive_directory_iterator __iter) noexcept 504 { return __iter; } 505 506 inline recursive_directory_iterator 507 end(recursive_directory_iterator) noexcept 508 { return recursive_directory_iterator(); } 509 510 inline bool 511 operator==(const recursive_directory_iterator& __lhs, 512 const recursive_directory_iterator& __rhs) 513 { 514 return !__rhs._M_dirs.owner_before(__lhs._M_dirs) 515 && !__lhs._M_dirs.owner_before(__rhs._M_dirs); 516 } 517 518 inline bool 519 operator!=(const recursive_directory_iterator& __lhs, 520 const recursive_directory_iterator& __rhs) 521 { return !(__lhs == __rhs); } 522 523 _GLIBCXX_END_NAMESPACE_CXX11 524 525 // @} group filesystem 526 } // namespace filesystem 527 528 _GLIBCXX_END_NAMESPACE_VERSION 529 } // namespace std 530 531 #endif // C++17 532 533 #endif // _GLIBCXX_FS_DIR_H 534