1 // Filesystem operations -*- C++ -*- 2 3 // Copyright (C) 2014-2016 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 #ifndef _GLIBCXX_USE_CXX11_ABI 26 # define _GLIBCXX_USE_CXX11_ABI 1 27 #endif 28 29 #include <experimental/filesystem> 30 #include <functional> 31 #include <ostream> 32 #include <stack> 33 #include <ext/stdio_filebuf.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <errno.h> 37 #include <limits.h> // PATH_MAX 38 #ifdef _GLIBCXX_HAVE_UNISTD_H 39 # include <unistd.h> 40 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H) 41 # include <sys/types.h> 42 # include <sys/stat.h> 43 # endif 44 #endif 45 #ifdef _GLIBCXX_HAVE_FCNTL_H 46 # include <fcntl.h> 47 #endif 48 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H 49 # include <sys/statvfs.h> 50 #endif 51 #ifdef _GLIBCXX_USE_SENDFILE 52 # include <sys/sendfile.h> 53 #endif 54 #if _GLIBCXX_HAVE_UTIME_H 55 # include <utime.h> 56 #endif 57 58 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 59 # undef utime 60 # define utime _wutime 61 # undef chmod 62 # define chmod _wchmod 63 #endif 64 65 namespace fs = std::experimental::filesystem; 66 67 fs::path 68 fs::absolute(const path& p, const path& base) 69 { 70 const bool has_root_dir = p.has_root_directory(); 71 const bool has_root_name = p.has_root_name(); 72 path abs; 73 if (has_root_dir && has_root_name) 74 abs = p; 75 else 76 { 77 abs = base.is_absolute() ? base : absolute(base); 78 if (has_root_dir) 79 abs = abs.root_name() / p; 80 else if (has_root_name) 81 abs = p.root_name() / abs.root_directory() / abs.relative_path() 82 / p.relative_path(); 83 else 84 abs = abs / p; 85 } 86 return abs; 87 } 88 89 namespace 90 { 91 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 92 inline bool is_dot(wchar_t c) { return c == L'.'; } 93 #else 94 inline bool is_dot(char c) { return c == '.'; } 95 #endif 96 97 inline bool is_dot(const fs::path& path) 98 { 99 const auto& filename = path.native(); 100 return filename.size() == 1 && is_dot(filename[0]); 101 } 102 103 inline bool is_dotdot(const fs::path& path) 104 { 105 const auto& filename = path.native(); 106 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]); 107 } 108 109 struct free_as_in_malloc 110 { 111 void operator()(void* p) const { ::free(p); } 112 }; 113 114 using char_ptr = std::unique_ptr<char[], free_as_in_malloc>; 115 } 116 117 fs::path 118 fs::canonical(const path& p, const path& base, error_code& ec) 119 { 120 const path pa = absolute(p, base); 121 path result; 122 123 #ifdef _GLIBCXX_USE_REALPATH 124 char_ptr buf{ nullptr }; 125 # if _XOPEN_VERSION < 700 126 // Not safe to call realpath(path, NULL) 127 buf.reset( (char*)::malloc(PATH_MAX) ); 128 # endif 129 if (char* rp = ::realpath(pa.c_str(), buf.get())) 130 { 131 if (buf == nullptr) 132 buf.reset(rp); 133 result.assign(rp); 134 ec.clear(); 135 return result; 136 } 137 if (errno != ENAMETOOLONG) 138 { 139 ec.assign(errno, std::generic_category()); 140 return result; 141 } 142 #endif 143 144 if (!exists(pa, ec)) 145 { 146 if (!ec) 147 ec = make_error_code(std::errc::no_such_file_or_directory); 148 return result; 149 } 150 // else: we know there are (currently) no unresolvable symlink loops 151 152 result = pa.root_path(); 153 154 deque<path> cmpts; 155 for (auto& f : pa.relative_path()) 156 cmpts.push_back(f); 157 158 int max_allowed_symlinks = 40; 159 160 while (!cmpts.empty() && !ec) 161 { 162 path f = std::move(cmpts.front()); 163 cmpts.pop_front(); 164 165 if (is_dot(f)) 166 { 167 if (!is_directory(result, ec) && !ec) 168 ec.assign(ENOTDIR, std::generic_category()); 169 } 170 else if (is_dotdot(f)) 171 { 172 auto parent = result.parent_path(); 173 if (parent.empty()) 174 result = pa.root_path(); 175 else 176 result.swap(parent); 177 } 178 else 179 { 180 result /= f; 181 182 if (is_symlink(result, ec)) 183 { 184 path link = read_symlink(result, ec); 185 if (!ec) 186 { 187 if (--max_allowed_symlinks == 0) 188 ec.assign(ELOOP, std::generic_category()); 189 else 190 { 191 if (link.is_absolute()) 192 { 193 result = link.root_path(); 194 link = link.relative_path(); 195 } 196 else 197 result.remove_filename(); 198 199 cmpts.insert(cmpts.begin(), link.begin(), link.end()); 200 } 201 } 202 } 203 } 204 } 205 206 if (ec || !exists(result, ec)) 207 result.clear(); 208 209 return result; 210 } 211 212 fs::path 213 fs::canonical(const path& p, error_code& ec) 214 { 215 path cur = current_path(ec); 216 if (ec.value()) 217 return {}; 218 return canonical(p, cur, ec); 219 } 220 221 fs::path 222 fs::canonical(const path& p, const path& base) 223 { 224 error_code ec; 225 path can = canonical(p, base, ec); 226 if (ec) 227 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, base, 228 ec)); 229 return can; 230 } 231 232 void 233 fs::copy(const path& from, const path& to, copy_options options) 234 { 235 error_code ec; 236 copy(from, to, options, ec); 237 if (ec.value()) 238 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec)); 239 } 240 241 namespace 242 { 243 template<typename Bitmask> 244 inline bool is_set(Bitmask obj, Bitmask bits) 245 { 246 return (obj & bits) != Bitmask::none; 247 } 248 } 249 250 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 251 namespace 252 { 253 typedef struct ::stat stat_type; 254 255 inline fs::file_type 256 make_file_type(const stat_type& st) noexcept 257 { 258 using fs::file_type; 259 #ifdef _GLIBCXX_HAVE_S_ISREG 260 if (S_ISREG(st.st_mode)) 261 return file_type::regular; 262 else if (S_ISDIR(st.st_mode)) 263 return file_type::directory; 264 else if (S_ISCHR(st.st_mode)) 265 return file_type::character; 266 else if (S_ISBLK(st.st_mode)) 267 return file_type::block; 268 else if (S_ISFIFO(st.st_mode)) 269 return file_type::fifo; 270 else if (S_ISLNK(st.st_mode)) 271 return file_type::symlink; 272 else if (S_ISSOCK(st.st_mode)) 273 return file_type::socket; 274 #endif 275 return file_type::unknown; 276 277 } 278 279 inline fs::file_status 280 make_file_status(const stat_type& st) noexcept 281 { 282 return fs::file_status{ 283 make_file_type(st), 284 static_cast<fs::perms>(st.st_mode) & fs::perms::mask 285 }; 286 } 287 288 inline bool 289 is_not_found_errno(int err) noexcept 290 { 291 return err == ENOENT || err == ENOTDIR; 292 } 293 294 inline fs::file_time_type 295 file_time(const stat_type& st, std::error_code& ec) noexcept 296 { 297 using namespace std::chrono; 298 #ifdef _GLIBCXX_USE_ST_MTIM 299 time_t s = st.st_mtim.tv_sec; 300 nanoseconds ns{st.st_mtim.tv_nsec}; 301 #else 302 time_t s = st.st_mtime; 303 nanoseconds ns{}; 304 #endif 305 306 if (s >= (nanoseconds::max().count() / 1e9)) 307 { 308 ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW 309 return fs::file_time_type::min(); 310 } 311 ec.clear(); 312 return fs::file_time_type{seconds{s} + ns}; 313 } 314 315 bool 316 do_copy_file(const fs::path& from, const fs::path& to, 317 fs::copy_options option, 318 stat_type* from_st, stat_type* to_st, 319 std::error_code& ec) noexcept 320 { 321 stat_type st1, st2; 322 fs::file_status t, f; 323 324 if (to_st == nullptr) 325 { 326 if (::stat(to.c_str(), &st1)) 327 { 328 int err = errno; 329 if (!is_not_found_errno(err)) 330 { 331 ec.assign(err, std::generic_category()); 332 return false; 333 } 334 } 335 else 336 to_st = &st1; 337 } 338 else if (to_st == from_st) 339 to_st = nullptr; 340 341 if (to_st == nullptr) 342 t = fs::file_status{fs::file_type::not_found}; 343 else 344 t = make_file_status(*to_st); 345 346 if (from_st == nullptr) 347 { 348 if (::stat(from.c_str(), &st2)) 349 { 350 ec.assign(errno, std::generic_category()); 351 return false; 352 } 353 else 354 from_st = &st2; 355 } 356 f = make_file_status(*from_st); 357 // _GLIBCXX_RESOLVE_LIB_DEFECTS 358 // 2712. copy_file() has a number of unspecified error conditions 359 if (!is_regular_file(f)) 360 { 361 ec = std::make_error_code(std::errc::not_supported); 362 return false; 363 } 364 365 using opts = fs::copy_options; 366 367 if (exists(t)) 368 { 369 if (!is_regular_file(t)) 370 { 371 ec = std::make_error_code(std::errc::not_supported); 372 return false; 373 } 374 375 if (to_st->st_dev == from_st->st_dev 376 && to_st->st_ino == from_st->st_ino) 377 { 378 ec = std::make_error_code(std::errc::file_exists); 379 return false; 380 } 381 382 if (is_set(option, opts::skip_existing)) 383 { 384 ec.clear(); 385 return false; 386 } 387 else if (is_set(option, opts::update_existing)) 388 { 389 const auto from_mtime = file_time(*from_st, ec); 390 if (ec) 391 return false; 392 if ((from_mtime <= file_time(*to_st, ec)) || ec) 393 return false; 394 } 395 else if (!is_set(option, opts::overwrite_existing)) 396 { 397 ec = std::make_error_code(std::errc::file_exists); 398 return false; 399 } 400 else if (!is_regular_file(t)) 401 { 402 ec = std::make_error_code(std::errc::not_supported); 403 return false; 404 } 405 } 406 407 struct CloseFD { 408 ~CloseFD() { if (fd != -1) ::close(fd); } 409 bool close() { return ::close(std::exchange(fd, -1)) == 0; } 410 int fd; 411 }; 412 413 CloseFD in = { ::open(from.c_str(), O_RDONLY) }; 414 if (in.fd == -1) 415 { 416 ec.assign(errno, std::generic_category()); 417 return false; 418 } 419 int oflag = O_WRONLY|O_CREAT; 420 if (is_set(option, opts::overwrite_existing|opts::update_existing)) 421 oflag |= O_TRUNC; 422 else 423 oflag |= O_EXCL; 424 CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) }; 425 if (out.fd == -1) 426 { 427 if (errno == EEXIST && is_set(option, opts::skip_existing)) 428 ec.clear(); 429 else 430 ec.assign(errno, std::generic_category()); 431 return false; 432 } 433 434 #ifdef _GLIBCXX_USE_FCHMOD 435 if (::fchmod(out.fd, from_st->st_mode)) 436 #elif defined _GLIBCXX_USE_FCHMODAT 437 if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0)) 438 #else 439 if (::chmod(to.c_str(), from_st->st_mode)) 440 #endif 441 { 442 ec.assign(errno, std::generic_category()); 443 return false; 444 } 445 446 size_t count = from_st->st_size; 447 #ifdef _GLIBCXX_USE_SENDFILE 448 off_t offset = 0; 449 ssize_t n = ::sendfile(out.fd, in.fd, &offset, count); 450 if (n < 0 && errno != ENOSYS && errno != EINVAL) 451 { 452 ec.assign(errno, std::generic_category()); 453 return false; 454 } 455 if ((size_t)n == count) 456 { 457 if (!out.close() || !in.close()) 458 { 459 ec.assign(errno, std::generic_category()); 460 return false; 461 } 462 ec.clear(); 463 return true; 464 } 465 else if (n > 0) 466 count -= n; 467 #endif // _GLIBCXX_USE_SENDFILE 468 469 using std::ios; 470 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary); 471 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary); 472 473 if (sbin.is_open()) 474 in.fd = -1; 475 if (sbout.is_open()) 476 out.fd = -1; 477 478 #ifdef _GLIBCXX_USE_SENDFILE 479 if (n != 0) 480 { 481 if (n < 0) 482 n = 0; 483 484 const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in); 485 const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out); 486 487 const std::streampos errpos(std::streamoff(-1)); 488 if (p1 == errpos || p2 == errpos) 489 { 490 ec = std::make_error_code(std::errc::io_error); 491 return false; 492 } 493 } 494 #endif 495 496 if (count && !(std::ostream(&sbout) << &sbin)) 497 { 498 ec = std::make_error_code(std::errc::io_error); 499 return false; 500 } 501 if (!sbout.close() || !sbin.close()) 502 { 503 ec.assign(errno, std::generic_category()); 504 return false; 505 } 506 ec.clear(); 507 return true; 508 } 509 } 510 #endif 511 512 void 513 fs::copy(const path& from, const path& to, copy_options options, 514 error_code& ec) noexcept 515 { 516 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks); 517 const bool create_symlinks = is_set(options, copy_options::create_symlinks); 518 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks); 519 const bool use_lstat = create_symlinks || skip_symlinks; 520 521 file_status f, t; 522 stat_type from_st, to_st; 523 // _GLIBCXX_RESOLVE_LIB_DEFECTS 524 // 2681. filesystem::copy() cannot copy symlinks 525 if (use_lstat || copy_symlinks 526 ? ::lstat(from.c_str(), &from_st) 527 : ::stat(from.c_str(), &from_st)) 528 { 529 ec.assign(errno, std::generic_category()); 530 return; 531 } 532 if (use_lstat 533 ? ::lstat(to.c_str(), &to_st) 534 : ::stat(to.c_str(), &to_st)) 535 { 536 if (!is_not_found_errno(errno)) 537 { 538 ec.assign(errno, std::generic_category()); 539 return; 540 } 541 t = file_status{file_type::not_found}; 542 } 543 else 544 t = make_file_status(to_st); 545 f = make_file_status(from_st); 546 547 if (exists(t) && !is_other(t) && !is_other(f) 548 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino) 549 { 550 ec = std::make_error_code(std::errc::file_exists); 551 return; 552 } 553 if (is_other(f) || is_other(t)) 554 { 555 ec = std::make_error_code(std::errc::not_supported); 556 return; 557 } 558 if (is_directory(f) && is_regular_file(t)) 559 { 560 ec = std::make_error_code(std::errc::is_a_directory); 561 return; 562 } 563 564 if (is_symlink(f)) 565 { 566 if (skip_symlinks) 567 ec.clear(); 568 else if (!exists(t) && copy_symlinks) 569 copy_symlink(from, to, ec); 570 else 571 // Not clear what should be done here. 572 // "Otherwise report an error as specified in Error reporting (7)." 573 ec = std::make_error_code(std::errc::invalid_argument); 574 } 575 else if (is_regular_file(f)) 576 { 577 if (is_set(options, copy_options::directories_only)) 578 ec.clear(); 579 else if (create_symlinks) 580 create_symlink(from, to, ec); 581 else if (is_set(options, copy_options::create_hard_links)) 582 create_hard_link(from, to, ec); 583 else if (is_directory(t)) 584 do_copy_file(from, to / from.filename(), options, &from_st, 0, ec); 585 else 586 { 587 auto ptr = exists(t) ? &to_st : &from_st; 588 do_copy_file(from, to, options, &from_st, ptr, ec); 589 } 590 } 591 // _GLIBCXX_RESOLVE_LIB_DEFECTS 592 // 2682. filesystem::copy() won't create a symlink to a directory 593 else if (is_directory(f) && create_symlinks) 594 ec = std::make_error_code(errc::is_a_directory); 595 else if (is_directory(f) && (is_set(options, copy_options::recursive) 596 || options == copy_options::none)) 597 { 598 if (!exists(t)) 599 if (!create_directory(to, from, ec)) 600 return; 601 // set an unused bit in options to disable further recursion 602 if (!is_set(options, copy_options::recursive)) 603 options |= static_cast<copy_options>(4096); 604 for (const directory_entry& x : directory_iterator(from)) 605 copy(x.path(), to/x.path().filename(), options, ec); 606 } 607 // _GLIBCXX_RESOLVE_LIB_DEFECTS 608 // 2683. filesystem::copy() says "no effects" 609 else 610 ec.clear(); 611 } 612 613 bool 614 fs::copy_file(const path& from, const path& to, copy_options option) 615 { 616 error_code ec; 617 bool result = copy_file(from, to, option, ec); 618 if (ec.value()) 619 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to, 620 ec)); 621 return result; 622 } 623 624 bool 625 fs::copy_file(const path& from, const path& to, copy_options option, 626 error_code& ec) noexcept 627 { 628 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 629 return do_copy_file(from, to, option, nullptr, nullptr, ec); 630 #else 631 ec = std::make_error_code(std::errc::not_supported); 632 return false; 633 #endif 634 } 635 636 637 void 638 fs::copy_symlink(const path& existing_symlink, const path& new_symlink) 639 { 640 error_code ec; 641 copy_symlink(existing_symlink, new_symlink, ec); 642 if (ec.value()) 643 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink", 644 existing_symlink, new_symlink, ec)); 645 } 646 647 void 648 fs::copy_symlink(const path& existing_symlink, const path& new_symlink, 649 error_code& ec) noexcept 650 { 651 auto p = read_symlink(existing_symlink, ec); 652 if (ec.value()) 653 return; 654 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 655 if (is_directory(p)) 656 { 657 create_directory_symlink(p, new_symlink, ec); 658 return; 659 } 660 #endif 661 create_symlink(p, new_symlink, ec); 662 } 663 664 665 bool 666 fs::create_directories(const path& p) 667 { 668 error_code ec; 669 bool result = create_directories(p, ec); 670 if (ec.value()) 671 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p, 672 ec)); 673 return result; 674 } 675 676 bool 677 fs::create_directories(const path& p, error_code& ec) noexcept 678 { 679 if (p.empty()) 680 { 681 ec = std::make_error_code(errc::invalid_argument); 682 return false; 683 } 684 std::stack<path> missing; 685 path pp = p; 686 687 while (!pp.empty() && status(pp, ec).type() == file_type::not_found) 688 { 689 ec.clear(); 690 const auto& filename = pp.filename(); 691 if (!is_dot(filename) && !is_dotdot(filename)) 692 missing.push(pp); 693 pp.remove_filename(); 694 } 695 696 if (ec || missing.empty()) 697 return false; 698 699 do 700 { 701 const path& top = missing.top(); 702 create_directory(top, ec); 703 if (ec && is_directory(top)) 704 ec.clear(); 705 missing.pop(); 706 } 707 while (!missing.empty() && !ec); 708 709 return missing.empty(); 710 } 711 712 namespace 713 { 714 bool 715 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec) 716 { 717 bool created = false; 718 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 719 ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm); 720 if (::mkdir(p.c_str(), mode)) 721 { 722 const int err = errno; 723 if (err != EEXIST || !is_directory(p)) 724 ec.assign(err, std::generic_category()); 725 else 726 ec.clear(); 727 } 728 else 729 { 730 ec.clear(); 731 created = true; 732 } 733 #else 734 ec = std::make_error_code(std::errc::not_supported); 735 #endif 736 return created; 737 } 738 } // namespace 739 740 bool 741 fs::create_directory(const path& p) 742 { 743 error_code ec; 744 bool result = create_directory(p, ec); 745 if (ec.value()) 746 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, 747 ec)); 748 return result; 749 } 750 751 bool 752 fs::create_directory(const path& p, error_code& ec) noexcept 753 { 754 return create_dir(p, perms::all, ec); 755 } 756 757 758 bool 759 fs::create_directory(const path& p, const path& attributes) 760 { 761 error_code ec; 762 bool result = create_directory(p, attributes, ec); 763 if (ec.value()) 764 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, 765 ec)); 766 return result; 767 } 768 769 bool 770 fs::create_directory(const path& p, const path& attributes, 771 error_code& ec) noexcept 772 { 773 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 774 stat_type st; 775 if (::stat(attributes.c_str(), &st)) 776 { 777 ec.assign(errno, std::generic_category()); 778 return false; 779 } 780 return create_dir(p, static_cast<perms>(st.st_mode), ec); 781 #else 782 ec = std::make_error_code(std::errc::not_supported); 783 return false; 784 #endif 785 } 786 787 788 void 789 fs::create_directory_symlink(const path& to, const path& new_symlink) 790 { 791 error_code ec; 792 create_directory_symlink(to, new_symlink, ec); 793 if (ec.value()) 794 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink", 795 to, new_symlink, ec)); 796 } 797 798 void 799 fs::create_directory_symlink(const path& to, const path& new_symlink, 800 error_code& ec) noexcept 801 { 802 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 803 ec = std::make_error_code(std::errc::not_supported); 804 #else 805 create_symlink(to, new_symlink, ec); 806 #endif 807 } 808 809 810 void 811 fs::create_hard_link(const path& to, const path& new_hard_link) 812 { 813 error_code ec; 814 create_hard_link(to, new_hard_link, ec); 815 if (ec.value()) 816 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link", 817 to, new_hard_link, ec)); 818 } 819 820 void 821 fs::create_hard_link(const path& to, const path& new_hard_link, 822 error_code& ec) noexcept 823 { 824 #ifdef _GLIBCXX_HAVE_UNISTD_H 825 if (::link(to.c_str(), new_hard_link.c_str())) 826 ec.assign(errno, std::generic_category()); 827 else 828 ec.clear(); 829 #else 830 ec = std::make_error_code(std::errc::not_supported); 831 #endif 832 } 833 834 void 835 fs::create_symlink(const path& to, const path& new_symlink) 836 { 837 error_code ec; 838 create_symlink(to, new_symlink, ec); 839 if (ec.value()) 840 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink", 841 to, new_symlink, ec)); 842 } 843 844 void 845 fs::create_symlink(const path& to, const path& new_symlink, 846 error_code& ec) noexcept 847 { 848 #ifdef _GLIBCXX_HAVE_UNISTD_H 849 if (::symlink(to.c_str(), new_symlink.c_str())) 850 ec.assign(errno, std::generic_category()); 851 else 852 ec.clear(); 853 #else 854 ec = std::make_error_code(std::errc::not_supported); 855 #endif 856 } 857 858 859 fs::path 860 fs::current_path() 861 { 862 error_code ec; 863 path p = current_path(ec); 864 if (ec.value()) 865 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec)); 866 return p; 867 } 868 869 fs::path 870 fs::current_path(error_code& ec) 871 { 872 path p; 873 #ifdef _GLIBCXX_HAVE_UNISTD_H 874 #ifdef __GLIBC__ 875 if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) 876 { 877 p.assign(cwd.get()); 878 ec.clear(); 879 } 880 else 881 ec.assign(errno, std::generic_category()); 882 #else 883 long path_max = pathconf(".", _PC_PATH_MAX); 884 size_t size; 885 if (path_max == -1) 886 size = 1024; 887 else if (path_max > 10240) 888 size = 10240; 889 else 890 size = path_max; 891 for (char_ptr buf; p.empty(); size *= 2) 892 { 893 buf.reset((char*)malloc(size)); 894 if (buf) 895 { 896 if (getcwd(buf.get(), size)) 897 { 898 p.assign(buf.get()); 899 ec.clear(); 900 } 901 else if (errno != ERANGE) 902 { 903 ec.assign(errno, std::generic_category()); 904 return {}; 905 } 906 } 907 else 908 { 909 ec = std::make_error_code(std::errc::not_enough_memory); 910 return {}; 911 } 912 } 913 #endif // __GLIBC__ 914 #else // _GLIBCXX_HAVE_UNISTD_H 915 ec = std::make_error_code(std::errc::not_supported); 916 #endif 917 return p; 918 } 919 920 void 921 fs::current_path(const path& p) 922 { 923 error_code ec; 924 current_path(p, ec); 925 if (ec.value()) 926 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec)); 927 } 928 929 void 930 fs::current_path(const path& p, error_code& ec) noexcept 931 { 932 #ifdef _GLIBCXX_HAVE_UNISTD_H 933 if (::chdir(p.c_str())) 934 ec.assign(errno, std::generic_category()); 935 else 936 ec.clear(); 937 #else 938 ec = std::make_error_code(std::errc::not_supported); 939 #endif 940 } 941 942 bool 943 fs::equivalent(const path& p1, const path& p2) 944 { 945 error_code ec; 946 auto result = equivalent(p1, p2, ec); 947 if (ec) 948 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence", 949 p1, p2, ec)); 950 return result; 951 } 952 953 bool 954 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept 955 { 956 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 957 int err = 0; 958 file_status s1, s2; 959 stat_type st1, st2; 960 if (::stat(p1.c_str(), &st1) == 0) 961 s1 = make_file_status(st1); 962 else if (is_not_found_errno(errno)) 963 s1.type(file_type::not_found); 964 else 965 err = errno; 966 967 if (::stat(p2.c_str(), &st2) == 0) 968 s2 = make_file_status(st2); 969 else if (is_not_found_errno(errno)) 970 s2.type(file_type::not_found); 971 else 972 err = errno; 973 974 if (exists(s1) && exists(s2)) 975 { 976 if (is_other(s1) && is_other(s2)) 977 { 978 ec = std::make_error_code(std::errc::not_supported); 979 return false; 980 } 981 ec.clear(); 982 if (is_other(s1) || is_other(s2)) 983 return false; 984 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; 985 } 986 else if (!exists(s1) && !exists(s2)) 987 ec = std::make_error_code(std::errc::no_such_file_or_directory); 988 else if (err) 989 ec.assign(err, std::generic_category()); 990 else 991 ec.clear(); 992 return false; 993 #else 994 ec = std::make_error_code(std::errc::not_supported); 995 #endif 996 return false; 997 } 998 999 std::uintmax_t 1000 fs::file_size(const path& p) 1001 { 1002 error_code ec; 1003 auto sz = file_size(p, ec); 1004 if (ec.value()) 1005 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec)); 1006 return sz; 1007 } 1008 1009 namespace 1010 { 1011 template<typename Accessor, typename T> 1012 inline T 1013 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt) 1014 { 1015 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 1016 stat_type st; 1017 if (::stat(p.c_str(), &st)) 1018 { 1019 ec.assign(errno, std::generic_category()); 1020 return deflt; 1021 } 1022 ec.clear(); 1023 return f(st); 1024 #else 1025 ec = std::make_error_code(std::errc::not_supported); 1026 return deflt; 1027 #endif 1028 } 1029 } 1030 1031 std::uintmax_t 1032 fs::file_size(const path& p, error_code& ec) noexcept 1033 { 1034 struct S 1035 { 1036 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { } 1037 S() : type(file_type::not_found) { } 1038 file_type type; 1039 size_t size; 1040 }; 1041 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{}); 1042 if (s.type == file_type::regular) 1043 return s.size; 1044 if (!ec) 1045 { 1046 if (s.type == file_type::directory) 1047 ec = std::make_error_code(std::errc::is_a_directory); 1048 else 1049 ec = std::make_error_code(std::errc::not_supported); 1050 } 1051 return -1; 1052 } 1053 1054 std::uintmax_t 1055 fs::hard_link_count(const path& p) 1056 { 1057 error_code ec; 1058 auto count = hard_link_count(p, ec); 1059 if (ec.value()) 1060 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec)); 1061 return count; 1062 } 1063 1064 std::uintmax_t 1065 fs::hard_link_count(const path& p, error_code& ec) noexcept 1066 { 1067 return do_stat(p, ec, std::mem_fn(&stat::st_nlink), 1068 static_cast<uintmax_t>(-1)); 1069 } 1070 1071 bool 1072 fs::is_empty(const path& p) 1073 { 1074 error_code ec; 1075 bool e = is_empty(p, ec); 1076 if (ec) 1077 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty", 1078 p, ec)); 1079 return e; 1080 } 1081 1082 bool 1083 fs::is_empty(const path& p, error_code& ec) noexcept 1084 { 1085 auto s = status(p, ec); 1086 if (ec) 1087 return false; 1088 bool empty = fs::is_directory(s) 1089 ? fs::directory_iterator(p, ec) == fs::directory_iterator() 1090 : fs::file_size(p, ec) == 0; 1091 return ec ? false : empty; 1092 } 1093 1094 fs::file_time_type 1095 fs::last_write_time(const path& p) 1096 { 1097 error_code ec; 1098 auto t = last_write_time(p, ec); 1099 if (ec.value()) 1100 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec)); 1101 return t; 1102 } 1103 1104 fs::file_time_type 1105 fs::last_write_time(const path& p, error_code& ec) noexcept 1106 { 1107 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); }, 1108 file_time_type::min()); 1109 } 1110 1111 void 1112 fs::last_write_time(const path& p, file_time_type new_time) 1113 { 1114 error_code ec; 1115 last_write_time(p, new_time, ec); 1116 if (ec.value()) 1117 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec)); 1118 } 1119 1120 void 1121 fs::last_write_time(const path& p __attribute__((__unused__)), 1122 file_time_type new_time, error_code& ec) noexcept 1123 { 1124 auto d = new_time.time_since_epoch(); 1125 auto s = chrono::duration_cast<chrono::seconds>(d); 1126 #if _GLIBCXX_USE_UTIMENSAT 1127 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s); 1128 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9. 1129 { 1130 --s; 1131 ns += chrono::seconds(1); 1132 } 1133 struct ::timespec ts[2]; 1134 ts[0].tv_sec = 0; 1135 ts[0].tv_nsec = UTIME_OMIT; 1136 ts[1].tv_sec = static_cast<std::time_t>(s.count()); 1137 ts[1].tv_nsec = static_cast<long>(ns.count()); 1138 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0)) 1139 ec.assign(errno, std::generic_category()); 1140 else 1141 ec.clear(); 1142 #elif _GLIBCXX_HAVE_UTIME_H 1143 ::utimbuf times; 1144 times.modtime = s.count(); 1145 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; }, 1146 times.modtime); 1147 if (::utime(p.c_str(), ×)) 1148 ec.assign(errno, std::generic_category()); 1149 else 1150 ec.clear(); 1151 #else 1152 ec = std::make_error_code(std::errc::not_supported); 1153 #endif 1154 } 1155 1156 void 1157 fs::permissions(const path& p, perms prms) 1158 { 1159 error_code ec; 1160 permissions(p, prms, ec); 1161 if (ec.value()) 1162 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec)); 1163 } 1164 1165 void 1166 fs::permissions(const path& p, perms prms, error_code& ec) noexcept 1167 { 1168 const bool add = is_set(prms, perms::add_perms); 1169 const bool remove = is_set(prms, perms::remove_perms); 1170 const bool nofollow = is_set(prms, perms::symlink_nofollow); 1171 if (add && remove) 1172 { 1173 ec = std::make_error_code(std::errc::invalid_argument); 1174 return; 1175 } 1176 1177 prms &= perms::mask; 1178 1179 file_status st; 1180 if (add || remove || nofollow) 1181 { 1182 st = nofollow ? symlink_status(p, ec) : status(p, ec); 1183 if (ec) 1184 return; 1185 auto curr = st.permissions(); 1186 if (add) 1187 prms |= curr; 1188 else if (remove) 1189 prms = curr & ~prms; 1190 } 1191 1192 int err = 0; 1193 #if _GLIBCXX_USE_FCHMODAT 1194 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0; 1195 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag)) 1196 err = errno; 1197 #else 1198 if (nofollow && is_symlink(st)) 1199 ec = std::make_error_code(std::errc::operation_not_supported); 1200 else if (::chmod(p.c_str(), static_cast<mode_t>(prms))) 1201 err = errno; 1202 #endif 1203 1204 if (err) 1205 ec.assign(err, std::generic_category()); 1206 else 1207 ec.clear(); 1208 } 1209 1210 fs::path 1211 fs::read_symlink(const path& p) 1212 { 1213 error_code ec; 1214 path tgt = read_symlink(p, ec); 1215 if (ec.value()) 1216 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec)); 1217 return tgt; 1218 } 1219 1220 fs::path fs::read_symlink(const path& p, error_code& ec) 1221 { 1222 path result; 1223 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 1224 stat_type st; 1225 if (::lstat(p.c_str(), &st)) 1226 { 1227 ec.assign(errno, std::generic_category()); 1228 return result; 1229 } 1230 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0'); 1231 do 1232 { 1233 ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); 1234 if (len == -1) 1235 { 1236 ec.assign(errno, std::generic_category()); 1237 return result; 1238 } 1239 else if (len == (ssize_t)buf.size()) 1240 { 1241 if (buf.size() > 4096) 1242 { 1243 ec.assign(ENAMETOOLONG, std::generic_category()); 1244 return result; 1245 } 1246 buf.resize(buf.size() * 2); 1247 } 1248 else 1249 { 1250 buf.resize(len); 1251 result.assign(buf); 1252 ec.clear(); 1253 break; 1254 } 1255 } 1256 while (true); 1257 #else 1258 ec = std::make_error_code(std::errc::not_supported); 1259 #endif 1260 return result; 1261 } 1262 1263 1264 bool 1265 fs::remove(const path& p) 1266 { 1267 error_code ec; 1268 bool result = fs::remove(p, ec); 1269 if (ec.value()) 1270 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec)); 1271 return result; 1272 } 1273 1274 bool 1275 fs::remove(const path& p, error_code& ec) noexcept 1276 { 1277 if (::remove(p.c_str()) == 0) 1278 { 1279 ec.clear(); 1280 return true; 1281 } 1282 else if (errno == ENOENT) 1283 ec.clear(); 1284 else 1285 ec.assign(errno, std::generic_category()); 1286 return false; 1287 } 1288 1289 1290 std::uintmax_t 1291 fs::remove_all(const path& p) 1292 { 1293 error_code ec; 1294 const auto result = remove_all(p, ec); 1295 if (ec.value()) 1296 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); 1297 return result; 1298 } 1299 1300 std::uintmax_t 1301 fs::remove_all(const path& p, error_code& ec) noexcept 1302 { 1303 const auto s = symlink_status(p, ec); 1304 if (!status_known(s)) 1305 return -1; 1306 1307 ec.clear(); 1308 if (s.type() == file_type::not_found) 1309 return 0; 1310 1311 uintmax_t count = 0; 1312 if (s.type() == file_type::directory) 1313 { 1314 for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec)) 1315 count += fs::remove_all(d->path(), ec); 1316 if (ec.value() == ENOENT) 1317 ec.clear(); 1318 else if (ec) 1319 return -1; 1320 } 1321 1322 if (fs::remove(p, ec)) 1323 ++count; 1324 return ec ? -1 : count; 1325 } 1326 1327 void 1328 fs::rename(const path& from, const path& to) 1329 { 1330 error_code ec; 1331 rename(from, to, ec); 1332 if (ec.value()) 1333 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec)); 1334 } 1335 1336 void 1337 fs::rename(const path& from, const path& to, error_code& ec) noexcept 1338 { 1339 if (::rename(from.c_str(), to.c_str())) 1340 ec.assign(errno, std::generic_category()); 1341 else 1342 ec.clear(); 1343 } 1344 1345 void 1346 fs::resize_file(const path& p, uintmax_t size) 1347 { 1348 error_code ec; 1349 resize_file(p, size, ec); 1350 if (ec.value()) 1351 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec)); 1352 } 1353 1354 void 1355 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept 1356 { 1357 #ifdef _GLIBCXX_HAVE_UNISTD_H 1358 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max())) 1359 ec.assign(EINVAL, std::generic_category()); 1360 else if (::truncate(p.c_str(), size)) 1361 ec.assign(errno, std::generic_category()); 1362 else 1363 ec.clear(); 1364 #else 1365 ec = std::make_error_code(std::errc::not_supported); 1366 #endif 1367 } 1368 1369 1370 fs::space_info 1371 fs::space(const path& p) 1372 { 1373 error_code ec; 1374 space_info s = space(p, ec); 1375 if (ec.value()) 1376 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec)); 1377 return s; 1378 } 1379 1380 fs::space_info 1381 fs::space(const path& p, error_code& ec) noexcept 1382 { 1383 space_info info = { 1384 static_cast<uintmax_t>(-1), 1385 static_cast<uintmax_t>(-1), 1386 static_cast<uintmax_t>(-1) 1387 }; 1388 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H 1389 struct ::statvfs f; 1390 if (::statvfs(p.c_str(), &f)) 1391 ec.assign(errno, std::generic_category()); 1392 else 1393 { 1394 uintmax_t fragment_size = f.f_frsize; 1395 info = space_info{ 1396 f.f_blocks * fragment_size, 1397 f.f_bfree * fragment_size, 1398 f.f_bavail * fragment_size 1399 }; 1400 ec.clear(); 1401 } 1402 #else 1403 ec = std::make_error_code(std::errc::not_supported); 1404 #endif 1405 return info; 1406 } 1407 1408 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 1409 fs::file_status 1410 fs::status(const fs::path& p, error_code& ec) noexcept 1411 { 1412 file_status status; 1413 stat_type st; 1414 if (::stat(p.c_str(), &st)) 1415 { 1416 int err = errno; 1417 ec.assign(err, std::generic_category()); 1418 if (is_not_found_errno(err)) 1419 status.type(file_type::not_found); 1420 #ifdef EOVERFLOW 1421 else if (err == EOVERFLOW) 1422 status.type(file_type::unknown); 1423 #endif 1424 } 1425 else 1426 { 1427 status = make_file_status(st); 1428 ec.clear(); 1429 } 1430 return status; 1431 } 1432 1433 fs::file_status 1434 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept 1435 { 1436 file_status status; 1437 stat_type st; 1438 if (::lstat(p.c_str(), &st)) 1439 { 1440 int err = errno; 1441 ec.assign(err, std::generic_category()); 1442 if (is_not_found_errno(err)) 1443 status.type(file_type::not_found); 1444 } 1445 else 1446 { 1447 status = make_file_status(st); 1448 ec.clear(); 1449 } 1450 return status; 1451 } 1452 #endif 1453 1454 fs::file_status 1455 fs::status(const fs::path& p) 1456 { 1457 std::error_code ec; 1458 auto result = status(p, ec); 1459 if (result.type() == file_type::none) 1460 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec)); 1461 return result; 1462 } 1463 1464 fs::file_status 1465 fs::symlink_status(const fs::path& p) 1466 { 1467 std::error_code ec; 1468 auto result = symlink_status(p, ec); 1469 if (result.type() == file_type::none) 1470 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec)); 1471 return result; 1472 } 1473 1474 fs::path 1475 fs::system_complete(const path& p) 1476 { 1477 error_code ec; 1478 path comp = system_complete(p, ec); 1479 if (ec.value()) 1480 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec)); 1481 return comp; 1482 } 1483 1484 fs::path 1485 fs::system_complete(const path& p, error_code& ec) 1486 { 1487 path base = current_path(ec); 1488 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1489 if (p.is_absolute() || !p.has_root_name() 1490 || p.root_name() == base.root_name()) 1491 return absolute(p, base); 1492 // else TODO 1493 ec = std::make_error_code(std::errc::not_supported); 1494 return {}; 1495 #else 1496 if (ec.value()) 1497 return {}; 1498 return absolute(p, base); 1499 #endif 1500 } 1501 1502 fs::path fs::temp_directory_path() 1503 { 1504 error_code ec; 1505 path tmp = temp_directory_path(ec); 1506 if (ec.value()) 1507 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec)); 1508 return tmp; 1509 } 1510 1511 fs::path fs::temp_directory_path(error_code& ec) 1512 { 1513 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1514 ec = std::make_error_code(std::errc::not_supported); 1515 return {}; // TODO 1516 #else 1517 const char* tmpdir = nullptr; 1518 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr }; 1519 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e) 1520 tmpdir = ::getenv(*e); 1521 path p = tmpdir ? tmpdir : "/tmp"; 1522 auto st = status(p, ec); 1523 if (!ec) 1524 { 1525 if (is_directory(st)) 1526 { 1527 ec.clear(); 1528 return p; 1529 } 1530 else 1531 ec = std::make_error_code(std::errc::not_a_directory); 1532 } 1533 return {}; 1534 #endif 1535 } 1536 1537