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