ops.cc revision 1.1.1.4
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 65namespace fs = std::experimental::filesystem; 66 67fs::path 68fs::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 89namespace 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 117fs::path 118fs::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 212fs::path 213fs::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 221fs::path 222fs::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 232void 233fs::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 241namespace 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 251namespace 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 512void 513fs::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 613bool 614fs::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 624bool 625fs::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 637void 638fs::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 647void 648fs::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 665bool 666fs::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 676bool 677fs::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 712namespace 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 740bool 741fs::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 751bool 752fs::create_directory(const path& p, error_code& ec) noexcept 753{ 754 return create_dir(p, perms::all, ec); 755} 756 757 758bool 759fs::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 769bool 770fs::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 788void 789fs::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 798void 799fs::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 810void 811fs::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 820void 821fs::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 834void 835fs::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 844void 845fs::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 859fs::path 860fs::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 869fs::path 870fs::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 920void 921fs::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 929void 930fs::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 942bool 943fs::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 953bool 954fs::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 999std::uintmax_t 1000fs::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 1009namespace 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 1031std::uintmax_t 1032fs::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 1054std::uintmax_t 1055fs::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 1064std::uintmax_t 1065fs::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 1071bool 1072fs::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 1082bool 1083fs::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 1094fs::file_time_type 1095fs::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 1104fs::file_time_type 1105fs::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 1111void 1112fs::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 1120void 1121fs::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 1156void 1157fs::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 1165void 1166fs::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 1210fs::path 1211fs::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 1220fs::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 1264bool 1265fs::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 1274bool 1275fs::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 1290std::uintmax_t 1291fs::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 1300std::uintmax_t 1301fs::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 1327void 1328fs::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 1336void 1337fs::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 1345void 1346fs::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 1354void 1355fs::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 1370fs::space_info 1371fs::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 1380fs::space_info 1381fs::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 1409fs::file_status 1410fs::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 1433fs::file_status 1434fs::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 1454fs::file_status 1455fs::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 1464fs::file_status 1465fs::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 1474fs::path 1475fs::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 1484fs::path 1485fs::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 1502fs::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 1511fs::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