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 #ifdef _GLIBCXX_USE_SENDFILE 447 off_t offset = 0; 448 const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size); 449 if (n < 0 && (errno == ENOSYS || errno == EINVAL)) 450 { 451 #endif 452 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in); 453 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out); 454 if (sbin.is_open()) 455 in.fd = -1; 456 if (sbout.is_open()) 457 out.fd = -1; 458 if (from_st->st_size && !(std::ostream(&sbout) << &sbin)) 459 { 460 ec = std::make_error_code(std::errc::io_error); 461 return false; 462 } 463 if (!sbout.close() || !sbin.close()) 464 { 465 ec.assign(errno, std::generic_category()); 466 return false; 467 } 468 469 ec.clear(); 470 return true; 471 472 #ifdef _GLIBCXX_USE_SENDFILE 473 } 474 if (n != from_st->st_size) 475 { 476 ec.assign(errno, std::generic_category()); 477 return false; 478 } 479 if (!out.close() || !in.close()) 480 { 481 ec.assign(errno, std::generic_category()); 482 return false; 483 } 484 485 ec.clear(); 486 return true; 487 #endif 488 } 489 } 490 #endif 491 492 void 493 fs::copy(const path& from, const path& to, copy_options options, 494 error_code& ec) noexcept 495 { 496 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks); 497 const bool create_symlinks = is_set(options, copy_options::create_symlinks); 498 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks); 499 const bool use_lstat = create_symlinks || skip_symlinks; 500 501 file_status f, t; 502 stat_type from_st, to_st; 503 // _GLIBCXX_RESOLVE_LIB_DEFECTS 504 // 2681. filesystem::copy() cannot copy symlinks 505 if (use_lstat || copy_symlinks 506 ? ::lstat(from.c_str(), &from_st) 507 : ::stat(from.c_str(), &from_st)) 508 { 509 ec.assign(errno, std::generic_category()); 510 return; 511 } 512 if (use_lstat 513 ? ::lstat(to.c_str(), &to_st) 514 : ::stat(to.c_str(), &to_st)) 515 { 516 if (!is_not_found_errno(errno)) 517 { 518 ec.assign(errno, std::generic_category()); 519 return; 520 } 521 t = file_status{file_type::not_found}; 522 } 523 else 524 t = make_file_status(to_st); 525 f = make_file_status(from_st); 526 527 if (exists(t) && !is_other(t) && !is_other(f) 528 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino) 529 { 530 ec = std::make_error_code(std::errc::file_exists); 531 return; 532 } 533 if (is_other(f) || is_other(t)) 534 { 535 ec = std::make_error_code(std::errc::not_supported); 536 return; 537 } 538 if (is_directory(f) && is_regular_file(t)) 539 { 540 ec = std::make_error_code(std::errc::is_a_directory); 541 return; 542 } 543 544 if (is_symlink(f)) 545 { 546 if (skip_symlinks) 547 ec.clear(); 548 else if (!exists(t) && copy_symlinks) 549 copy_symlink(from, to, ec); 550 else 551 // Not clear what should be done here. 552 // "Otherwise report an error as specified in Error reporting (7)." 553 ec = std::make_error_code(std::errc::invalid_argument); 554 } 555 else if (is_regular_file(f)) 556 { 557 if (is_set(options, copy_options::directories_only)) 558 ec.clear(); 559 else if (create_symlinks) 560 create_symlink(from, to, ec); 561 else if (is_set(options, copy_options::create_hard_links)) 562 create_hard_link(from, to, ec); 563 else if (is_directory(t)) 564 do_copy_file(from, to / from.filename(), options, &from_st, 0, ec); 565 else 566 { 567 auto ptr = exists(t) ? &to_st : &from_st; 568 do_copy_file(from, to, options, &from_st, ptr, ec); 569 } 570 } 571 // _GLIBCXX_RESOLVE_LIB_DEFECTS 572 // 2682. filesystem::copy() won't create a symlink to a directory 573 else if (is_directory(f) && create_symlinks) 574 ec = std::make_error_code(errc::is_a_directory); 575 else if (is_directory(f) && (is_set(options, copy_options::recursive) 576 || options == copy_options::none)) 577 { 578 if (!exists(t)) 579 if (!create_directory(to, from, ec)) 580 return; 581 // set an unused bit in options to disable further recursion 582 if (!is_set(options, copy_options::recursive)) 583 options |= static_cast<copy_options>(4096); 584 for (const directory_entry& x : directory_iterator(from)) 585 copy(x.path(), to/x.path().filename(), options, ec); 586 } 587 // _GLIBCXX_RESOLVE_LIB_DEFECTS 588 // 2683. filesystem::copy() says "no effects" 589 else 590 ec.clear(); 591 } 592 593 bool 594 fs::copy_file(const path& from, const path& to, copy_options option) 595 { 596 error_code ec; 597 bool result = copy_file(from, to, option, ec); 598 if (ec.value()) 599 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to, 600 ec)); 601 return result; 602 } 603 604 bool 605 fs::copy_file(const path& from, const path& to, copy_options option, 606 error_code& ec) noexcept 607 { 608 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 609 return do_copy_file(from, to, option, nullptr, nullptr, ec); 610 #else 611 ec = std::make_error_code(std::errc::not_supported); 612 return false; 613 #endif 614 } 615 616 617 void 618 fs::copy_symlink(const path& existing_symlink, const path& new_symlink) 619 { 620 error_code ec; 621 copy_symlink(existing_symlink, new_symlink, ec); 622 if (ec.value()) 623 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink", 624 existing_symlink, new_symlink, ec)); 625 } 626 627 void 628 fs::copy_symlink(const path& existing_symlink, const path& new_symlink, 629 error_code& ec) noexcept 630 { 631 auto p = read_symlink(existing_symlink, ec); 632 if (ec.value()) 633 return; 634 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 635 if (is_directory(p)) 636 { 637 create_directory_symlink(p, new_symlink, ec); 638 return; 639 } 640 #endif 641 create_symlink(p, new_symlink, ec); 642 } 643 644 645 bool 646 fs::create_directories(const path& p) 647 { 648 error_code ec; 649 bool result = create_directories(p, ec); 650 if (ec.value()) 651 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p, 652 ec)); 653 return result; 654 } 655 656 bool 657 fs::create_directories(const path& p, error_code& ec) noexcept 658 { 659 if (p.empty()) 660 { 661 ec = std::make_error_code(errc::invalid_argument); 662 return false; 663 } 664 std::stack<path> missing; 665 path pp = p; 666 667 while (!pp.empty() && status(pp, ec).type() == file_type::not_found) 668 { 669 ec.clear(); 670 const auto& filename = pp.filename(); 671 if (!is_dot(filename) && !is_dotdot(filename)) 672 missing.push(pp); 673 pp.remove_filename(); 674 } 675 676 if (ec || missing.empty()) 677 return false; 678 679 do 680 { 681 const path& top = missing.top(); 682 create_directory(top, ec); 683 if (ec && is_directory(top)) 684 ec.clear(); 685 missing.pop(); 686 } 687 while (!missing.empty() && !ec); 688 689 return missing.empty(); 690 } 691 692 namespace 693 { 694 bool 695 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec) 696 { 697 bool created = false; 698 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 699 ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm); 700 if (::mkdir(p.c_str(), mode)) 701 { 702 const int err = errno; 703 if (err != EEXIST || !is_directory(p)) 704 ec.assign(err, std::generic_category()); 705 else 706 ec.clear(); 707 } 708 else 709 { 710 ec.clear(); 711 created = true; 712 } 713 #else 714 ec = std::make_error_code(std::errc::not_supported); 715 #endif 716 return created; 717 } 718 } // namespace 719 720 bool 721 fs::create_directory(const path& p) 722 { 723 error_code ec; 724 bool result = create_directory(p, ec); 725 if (ec.value()) 726 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, 727 ec)); 728 return result; 729 } 730 731 bool 732 fs::create_directory(const path& p, error_code& ec) noexcept 733 { 734 return create_dir(p, perms::all, ec); 735 } 736 737 738 bool 739 fs::create_directory(const path& p, const path& attributes) 740 { 741 error_code ec; 742 bool result = create_directory(p, attributes, ec); 743 if (ec.value()) 744 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, 745 ec)); 746 return result; 747 } 748 749 bool 750 fs::create_directory(const path& p, const path& attributes, 751 error_code& ec) noexcept 752 { 753 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 754 stat_type st; 755 if (::stat(attributes.c_str(), &st)) 756 { 757 ec.assign(errno, std::generic_category()); 758 return false; 759 } 760 return create_dir(p, static_cast<perms>(st.st_mode), ec); 761 #else 762 ec = std::make_error_code(std::errc::not_supported); 763 return false; 764 #endif 765 } 766 767 768 void 769 fs::create_directory_symlink(const path& to, const path& new_symlink) 770 { 771 error_code ec; 772 create_directory_symlink(to, new_symlink, ec); 773 if (ec.value()) 774 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink", 775 to, new_symlink, ec)); 776 } 777 778 void 779 fs::create_directory_symlink(const path& to, const path& new_symlink, 780 error_code& ec) noexcept 781 { 782 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 783 ec = std::make_error_code(std::errc::not_supported); 784 #else 785 create_symlink(to, new_symlink, ec); 786 #endif 787 } 788 789 790 void 791 fs::create_hard_link(const path& to, const path& new_hard_link) 792 { 793 error_code ec; 794 create_hard_link(to, new_hard_link, ec); 795 if (ec.value()) 796 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link", 797 to, new_hard_link, ec)); 798 } 799 800 void 801 fs::create_hard_link(const path& to, const path& new_hard_link, 802 error_code& ec) noexcept 803 { 804 #ifdef _GLIBCXX_HAVE_UNISTD_H 805 if (::link(to.c_str(), new_hard_link.c_str())) 806 ec.assign(errno, std::generic_category()); 807 else 808 ec.clear(); 809 #else 810 ec = std::make_error_code(std::errc::not_supported); 811 #endif 812 } 813 814 void 815 fs::create_symlink(const path& to, const path& new_symlink) 816 { 817 error_code ec; 818 create_symlink(to, new_symlink, ec); 819 if (ec.value()) 820 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink", 821 to, new_symlink, ec)); 822 } 823 824 void 825 fs::create_symlink(const path& to, const path& new_symlink, 826 error_code& ec) noexcept 827 { 828 #ifdef _GLIBCXX_HAVE_UNISTD_H 829 if (::symlink(to.c_str(), new_symlink.c_str())) 830 ec.assign(errno, std::generic_category()); 831 else 832 ec.clear(); 833 #else 834 ec = std::make_error_code(std::errc::not_supported); 835 #endif 836 } 837 838 839 fs::path 840 fs::current_path() 841 { 842 error_code ec; 843 path p = current_path(ec); 844 if (ec.value()) 845 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec)); 846 return p; 847 } 848 849 fs::path 850 fs::current_path(error_code& ec) 851 { 852 path p; 853 #ifdef _GLIBCXX_HAVE_UNISTD_H 854 #ifdef __GLIBC__ 855 if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) 856 { 857 p.assign(cwd.get()); 858 ec.clear(); 859 } 860 else 861 ec.assign(errno, std::generic_category()); 862 #else 863 long path_max = pathconf(".", _PC_PATH_MAX); 864 size_t size; 865 if (path_max == -1) 866 size = 1024; 867 else if (path_max > 10240) 868 size = 10240; 869 else 870 size = path_max; 871 for (char_ptr buf; p.empty(); size *= 2) 872 { 873 buf.reset((char*)malloc(size)); 874 if (buf) 875 { 876 if (getcwd(buf.get(), size)) 877 { 878 p.assign(buf.get()); 879 ec.clear(); 880 } 881 else if (errno != ERANGE) 882 { 883 ec.assign(errno, std::generic_category()); 884 return {}; 885 } 886 } 887 else 888 { 889 ec = std::make_error_code(std::errc::not_enough_memory); 890 return {}; 891 } 892 } 893 #endif // __GLIBC__ 894 #else // _GLIBCXX_HAVE_UNISTD_H 895 ec = std::make_error_code(std::errc::not_supported); 896 #endif 897 return p; 898 } 899 900 void 901 fs::current_path(const path& p) 902 { 903 error_code ec; 904 current_path(p, ec); 905 if (ec.value()) 906 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec)); 907 } 908 909 void 910 fs::current_path(const path& p, error_code& ec) noexcept 911 { 912 #ifdef _GLIBCXX_HAVE_UNISTD_H 913 if (::chdir(p.c_str())) 914 ec.assign(errno, std::generic_category()); 915 else 916 ec.clear(); 917 #else 918 ec = std::make_error_code(std::errc::not_supported); 919 #endif 920 } 921 922 bool 923 fs::equivalent(const path& p1, const path& p2) 924 { 925 error_code ec; 926 auto result = equivalent(p1, p2, ec); 927 if (ec) 928 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence", 929 p1, p2, ec)); 930 return result; 931 } 932 933 bool 934 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept 935 { 936 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 937 int err = 0; 938 file_status s1, s2; 939 stat_type st1, st2; 940 if (::stat(p1.c_str(), &st1) == 0) 941 s1 = make_file_status(st1); 942 else if (is_not_found_errno(errno)) 943 s1.type(file_type::not_found); 944 else 945 err = errno; 946 947 if (::stat(p2.c_str(), &st2) == 0) 948 s2 = make_file_status(st2); 949 else if (is_not_found_errno(errno)) 950 s2.type(file_type::not_found); 951 else 952 err = errno; 953 954 if (exists(s1) && exists(s2)) 955 { 956 if (is_other(s1) && is_other(s2)) 957 { 958 ec = std::make_error_code(std::errc::not_supported); 959 return false; 960 } 961 ec.clear(); 962 if (is_other(s1) || is_other(s2)) 963 return false; 964 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; 965 } 966 else if (!exists(s1) && !exists(s2)) 967 ec = std::make_error_code(std::errc::no_such_file_or_directory); 968 else if (err) 969 ec.assign(err, std::generic_category()); 970 else 971 ec.clear(); 972 return false; 973 #else 974 ec = std::make_error_code(std::errc::not_supported); 975 #endif 976 return false; 977 } 978 979 std::uintmax_t 980 fs::file_size(const path& p) 981 { 982 error_code ec; 983 auto sz = file_size(p, ec); 984 if (ec.value()) 985 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec)); 986 return sz; 987 } 988 989 namespace 990 { 991 template<typename Accessor, typename T> 992 inline T 993 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt) 994 { 995 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 996 stat_type st; 997 if (::stat(p.c_str(), &st)) 998 { 999 ec.assign(errno, std::generic_category()); 1000 return deflt; 1001 } 1002 ec.clear(); 1003 return f(st); 1004 #else 1005 ec = std::make_error_code(std::errc::not_supported); 1006 return deflt; 1007 #endif 1008 } 1009 } 1010 1011 std::uintmax_t 1012 fs::file_size(const path& p, error_code& ec) noexcept 1013 { 1014 struct S 1015 { 1016 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { } 1017 S() : type(file_type::not_found) { } 1018 file_type type; 1019 size_t size; 1020 }; 1021 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{}); 1022 if (s.type == file_type::regular) 1023 return s.size; 1024 if (!ec) 1025 { 1026 if (s.type == file_type::directory) 1027 ec = std::make_error_code(std::errc::is_a_directory); 1028 else 1029 ec = std::make_error_code(std::errc::not_supported); 1030 } 1031 return -1; 1032 } 1033 1034 std::uintmax_t 1035 fs::hard_link_count(const path& p) 1036 { 1037 error_code ec; 1038 auto count = hard_link_count(p, ec); 1039 if (ec.value()) 1040 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec)); 1041 return count; 1042 } 1043 1044 std::uintmax_t 1045 fs::hard_link_count(const path& p, error_code& ec) noexcept 1046 { 1047 return do_stat(p, ec, std::mem_fn(&stat::st_nlink), 1048 static_cast<uintmax_t>(-1)); 1049 } 1050 1051 bool 1052 fs::is_empty(const path& p) 1053 { 1054 error_code ec; 1055 bool e = is_empty(p, ec); 1056 if (ec) 1057 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty", 1058 p, ec)); 1059 return e; 1060 } 1061 1062 bool 1063 fs::is_empty(const path& p, error_code& ec) noexcept 1064 { 1065 auto s = status(p, ec); 1066 if (ec) 1067 return false; 1068 bool empty = fs::is_directory(s) 1069 ? fs::directory_iterator(p, ec) == fs::directory_iterator() 1070 : fs::file_size(p, ec) == 0; 1071 return ec ? false : empty; 1072 } 1073 1074 fs::file_time_type 1075 fs::last_write_time(const path& p) 1076 { 1077 error_code ec; 1078 auto t = last_write_time(p, ec); 1079 if (ec.value()) 1080 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec)); 1081 return t; 1082 } 1083 1084 fs::file_time_type 1085 fs::last_write_time(const path& p, error_code& ec) noexcept 1086 { 1087 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); }, 1088 file_time_type::min()); 1089 } 1090 1091 void 1092 fs::last_write_time(const path& p, file_time_type new_time) 1093 { 1094 error_code ec; 1095 last_write_time(p, new_time, ec); 1096 if (ec.value()) 1097 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec)); 1098 } 1099 1100 void 1101 fs::last_write_time(const path& p __attribute__((__unused__)), 1102 file_time_type new_time, error_code& ec) noexcept 1103 { 1104 auto d = new_time.time_since_epoch(); 1105 auto s = chrono::duration_cast<chrono::seconds>(d); 1106 #if _GLIBCXX_USE_UTIMENSAT 1107 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s); 1108 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9. 1109 { 1110 --s; 1111 ns += chrono::seconds(1); 1112 } 1113 struct ::timespec ts[2]; 1114 ts[0].tv_sec = 0; 1115 ts[0].tv_nsec = UTIME_OMIT; 1116 ts[1].tv_sec = static_cast<std::time_t>(s.count()); 1117 ts[1].tv_nsec = static_cast<long>(ns.count()); 1118 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0)) 1119 ec.assign(errno, std::generic_category()); 1120 else 1121 ec.clear(); 1122 #elif _GLIBCXX_HAVE_UTIME_H 1123 ::utimbuf times; 1124 times.modtime = s.count(); 1125 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; }, 1126 times.modtime); 1127 if (::utime(p.c_str(), ×)) 1128 ec.assign(errno, std::generic_category()); 1129 else 1130 ec.clear(); 1131 #else 1132 ec = std::make_error_code(std::errc::not_supported); 1133 #endif 1134 } 1135 1136 void 1137 fs::permissions(const path& p, perms prms) 1138 { 1139 error_code ec; 1140 permissions(p, prms, ec); 1141 if (ec.value()) 1142 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec)); 1143 } 1144 1145 void 1146 fs::permissions(const path& p, perms prms, error_code& ec) noexcept 1147 { 1148 const bool add = is_set(prms, perms::add_perms); 1149 const bool remove = is_set(prms, perms::remove_perms); 1150 const bool nofollow = is_set(prms, perms::symlink_nofollow); 1151 if (add && remove) 1152 { 1153 ec = std::make_error_code(std::errc::invalid_argument); 1154 return; 1155 } 1156 1157 prms &= perms::mask; 1158 1159 file_status st; 1160 if (add || remove || nofollow) 1161 { 1162 st = nofollow ? symlink_status(p, ec) : status(p, ec); 1163 if (ec) 1164 return; 1165 auto curr = st.permissions(); 1166 if (add) 1167 prms |= curr; 1168 else if (remove) 1169 prms = curr & ~prms; 1170 } 1171 1172 int err = 0; 1173 #if _GLIBCXX_USE_FCHMODAT 1174 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0; 1175 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag)) 1176 err = errno; 1177 #else 1178 if (nofollow && is_symlink(st)) 1179 ec = std::make_error_code(std::errc::operation_not_supported); 1180 else if (::chmod(p.c_str(), static_cast<mode_t>(prms))) 1181 err = errno; 1182 #endif 1183 1184 if (err) 1185 ec.assign(err, std::generic_category()); 1186 else 1187 ec.clear(); 1188 } 1189 1190 fs::path 1191 fs::read_symlink(const path& p) 1192 { 1193 error_code ec; 1194 path tgt = read_symlink(p, ec); 1195 if (ec.value()) 1196 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec)); 1197 return tgt; 1198 } 1199 1200 fs::path fs::read_symlink(const path& p, error_code& ec) 1201 { 1202 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 1203 stat_type st; 1204 if (::lstat(p.c_str(), &st)) 1205 { 1206 ec.assign(errno, std::generic_category()); 1207 return {}; 1208 } 1209 std::string buf(st.st_size, '\0'); 1210 ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); 1211 if (len == -1) 1212 { 1213 ec.assign(errno, std::generic_category()); 1214 return {}; 1215 } 1216 ec.clear(); 1217 return path{buf.data(), buf.data()+len}; 1218 #else 1219 ec = std::make_error_code(std::errc::not_supported); 1220 return {}; 1221 #endif 1222 } 1223 1224 1225 bool 1226 fs::remove(const path& p) 1227 { 1228 error_code ec; 1229 bool result = fs::remove(p, ec); 1230 if (ec.value()) 1231 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec)); 1232 return result; 1233 } 1234 1235 bool 1236 fs::remove(const path& p, error_code& ec) noexcept 1237 { 1238 if (exists(symlink_status(p, ec))) 1239 { 1240 if (::remove(p.c_str()) == 0) 1241 { 1242 ec.clear(); 1243 return true; 1244 } 1245 else 1246 ec.assign(errno, std::generic_category()); 1247 } 1248 return false; 1249 } 1250 1251 1252 std::uintmax_t 1253 fs::remove_all(const path& p) 1254 { 1255 error_code ec; 1256 bool result = remove_all(p, ec); 1257 if (ec.value()) 1258 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); 1259 return result; 1260 } 1261 1262 std::uintmax_t 1263 fs::remove_all(const path& p, error_code& ec) noexcept 1264 { 1265 auto fs = symlink_status(p, ec); 1266 uintmax_t count = 0; 1267 if (ec.value() == 0 && fs.type() == file_type::directory) 1268 for (directory_iterator d(p, ec), end; ec.value() == 0 && d != end; ++d) 1269 count += fs::remove_all(d->path(), ec); 1270 if (ec.value()) 1271 return -1; 1272 return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear() 1273 } 1274 1275 void 1276 fs::rename(const path& from, const path& to) 1277 { 1278 error_code ec; 1279 rename(from, to, ec); 1280 if (ec.value()) 1281 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec)); 1282 } 1283 1284 void 1285 fs::rename(const path& from, const path& to, error_code& ec) noexcept 1286 { 1287 if (::rename(from.c_str(), to.c_str())) 1288 ec.assign(errno, std::generic_category()); 1289 else 1290 ec.clear(); 1291 } 1292 1293 void 1294 fs::resize_file(const path& p, uintmax_t size) 1295 { 1296 error_code ec; 1297 resize_file(p, size, ec); 1298 if (ec.value()) 1299 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec)); 1300 } 1301 1302 void 1303 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept 1304 { 1305 #ifdef _GLIBCXX_HAVE_UNISTD_H 1306 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max())) 1307 ec.assign(EINVAL, std::generic_category()); 1308 else if (::truncate(p.c_str(), size)) 1309 ec.assign(errno, std::generic_category()); 1310 else 1311 ec.clear(); 1312 #else 1313 ec = std::make_error_code(std::errc::not_supported); 1314 #endif 1315 } 1316 1317 1318 fs::space_info 1319 fs::space(const path& p) 1320 { 1321 error_code ec; 1322 space_info s = space(p, ec); 1323 if (ec.value()) 1324 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec)); 1325 return s; 1326 } 1327 1328 fs::space_info 1329 fs::space(const path& p, error_code& ec) noexcept 1330 { 1331 space_info info = { 1332 static_cast<uintmax_t>(-1), 1333 static_cast<uintmax_t>(-1), 1334 static_cast<uintmax_t>(-1) 1335 }; 1336 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H 1337 struct ::statvfs f; 1338 if (::statvfs(p.c_str(), &f)) 1339 ec.assign(errno, std::generic_category()); 1340 else 1341 { 1342 info = space_info{ 1343 f.f_blocks * f.f_frsize, 1344 f.f_bfree * f.f_frsize, 1345 f.f_bavail * f.f_frsize 1346 }; 1347 ec.clear(); 1348 } 1349 #else 1350 ec = std::make_error_code(std::errc::not_supported); 1351 #endif 1352 return info; 1353 } 1354 1355 #ifdef _GLIBCXX_HAVE_SYS_STAT_H 1356 fs::file_status 1357 fs::status(const fs::path& p, error_code& ec) noexcept 1358 { 1359 file_status status; 1360 stat_type st; 1361 if (::stat(p.c_str(), &st)) 1362 { 1363 int err = errno; 1364 ec.assign(err, std::generic_category()); 1365 if (is_not_found_errno(err)) 1366 status.type(file_type::not_found); 1367 #ifdef EOVERFLOW 1368 else if (err == EOVERFLOW) 1369 status.type(file_type::unknown); 1370 #endif 1371 } 1372 else 1373 { 1374 status = make_file_status(st); 1375 ec.clear(); 1376 } 1377 return status; 1378 } 1379 1380 fs::file_status 1381 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept 1382 { 1383 file_status status; 1384 stat_type st; 1385 if (::lstat(p.c_str(), &st)) 1386 { 1387 int err = errno; 1388 ec.assign(err, std::generic_category()); 1389 if (is_not_found_errno(err)) 1390 status.type(file_type::not_found); 1391 } 1392 else 1393 { 1394 status = make_file_status(st); 1395 ec.clear(); 1396 } 1397 return status; 1398 } 1399 #endif 1400 1401 fs::file_status 1402 fs::status(const fs::path& p) 1403 { 1404 std::error_code ec; 1405 auto result = status(p, ec); 1406 if (result.type() == file_type::none) 1407 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec)); 1408 return result; 1409 } 1410 1411 fs::file_status 1412 fs::symlink_status(const fs::path& p) 1413 { 1414 std::error_code ec; 1415 auto result = symlink_status(p, ec); 1416 if (result.type() == file_type::none) 1417 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec)); 1418 return result; 1419 } 1420 1421 fs::path 1422 fs::system_complete(const path& p) 1423 { 1424 error_code ec; 1425 path comp = system_complete(p, ec); 1426 if (ec.value()) 1427 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec)); 1428 return comp; 1429 } 1430 1431 fs::path 1432 fs::system_complete(const path& p, error_code& ec) 1433 { 1434 path base = current_path(ec); 1435 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1436 if (p.is_absolute() || !p.has_root_name() 1437 || p.root_name() == base.root_name()) 1438 return absolute(p, base); 1439 // else TODO 1440 ec = std::make_error_code(std::errc::not_supported); 1441 return {}; 1442 #else 1443 if (ec.value()) 1444 return {}; 1445 return absolute(p, base); 1446 #endif 1447 } 1448 1449 fs::path fs::temp_directory_path() 1450 { 1451 error_code ec; 1452 path tmp = temp_directory_path(ec); 1453 if (ec.value()) 1454 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec)); 1455 return tmp; 1456 } 1457 1458 fs::path fs::temp_directory_path(error_code& ec) 1459 { 1460 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1461 ec = std::make_error_code(std::errc::not_supported); 1462 return {}; // TODO 1463 #else 1464 const char* tmpdir = nullptr; 1465 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr }; 1466 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e) 1467 tmpdir = ::getenv(*e); 1468 path p = tmpdir ? tmpdir : "/tmp"; 1469 auto st = status(p, ec); 1470 if (!ec) 1471 { 1472 if (is_directory(st)) 1473 { 1474 ec.clear(); 1475 return p; 1476 } 1477 else 1478 ec = std::make_error_code(std::errc::not_a_directory); 1479 } 1480 return {}; 1481 #endif 1482 } 1483 1484