1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__assert> 10 #include <__config> 11 #include <__utility/unreachable.h> 12 #include <array> 13 #include <climits> 14 #include <cstdlib> 15 #include <filesystem> 16 #include <iterator> 17 #include <string_view> 18 #include <type_traits> 19 #include <vector> 20 21 #include "error.h" 22 #include "file_descriptor.h" 23 #include "path_parser.h" 24 #include "posix_compat.h" 25 #include "time_utils.h" 26 27 #if defined(_LIBCPP_WIN32API) 28 # define WIN32_LEAN_AND_MEAN 29 # define NOMINMAX 30 # include <windows.h> 31 #else 32 # include <dirent.h> 33 # include <sys/stat.h> 34 # include <sys/statvfs.h> 35 # include <unistd.h> 36 #endif 37 #include <fcntl.h> /* values for fchmodat */ 38 #include <time.h> 39 40 #if __has_include(<sys/sendfile.h>) 41 # include <sys/sendfile.h> 42 # define _LIBCPP_FILESYSTEM_USE_SENDFILE 43 #elif defined(__APPLE__) || __has_include(<copyfile.h>) 44 # include <copyfile.h> 45 # define _LIBCPP_FILESYSTEM_USE_COPYFILE 46 #else 47 # include <fstream> 48 # define _LIBCPP_FILESYSTEM_USE_FSTREAM 49 #endif 50 51 #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) 52 # pragma comment(lib, "rt") 53 #endif 54 55 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 56 57 using detail::capture_errno; 58 using detail::ErrorHandler; 59 using detail::StatT; 60 using detail::TimeSpec; 61 using parser::createView; 62 using parser::PathParser; 63 using parser::string_view_t; 64 65 static path __do_absolute(const path& p, path* cwd, error_code* ec) { 66 if (ec) 67 ec->clear(); 68 if (p.is_absolute()) 69 return p; 70 *cwd = __current_path(ec); 71 if (ec && *ec) 72 return {}; 73 return (*cwd) / p; 74 } 75 76 path __absolute(const path& p, error_code* ec) { 77 path cwd; 78 return __do_absolute(p, &cwd, ec); 79 } 80 81 path __canonical(path const& orig_p, error_code* ec) { 82 path cwd; 83 ErrorHandler<path> err("canonical", ec, &orig_p, &cwd); 84 85 path p = __do_absolute(orig_p, &cwd, ec); 86 #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API) 87 std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free); 88 if (hold.get() == nullptr) 89 return err.report(capture_errno()); 90 return {hold.get()}; 91 #else 92 # if defined(__MVS__) && !defined(PATH_MAX) 93 path::value_type buff[_XOPEN_PATH_MAX + 1]; 94 # else 95 path::value_type buff[PATH_MAX + 1]; 96 # endif 97 path::value_type* ret; 98 if ((ret = detail::realpath(p.c_str(), buff)) == nullptr) 99 return err.report(capture_errno()); 100 return {ret}; 101 #endif 102 } 103 104 void __copy(const path& from, const path& to, copy_options options, error_code* ec) { 105 ErrorHandler<void> err("copy", ec, &from, &to); 106 107 const bool sym_status = bool(options & (copy_options::create_symlinks | copy_options::skip_symlinks)); 108 109 const bool sym_status2 = bool(options & copy_options::copy_symlinks); 110 111 error_code m_ec1; 112 StatT f_st; 113 const file_status f = 114 sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1); 115 if (m_ec1) 116 return err.report(m_ec1); 117 118 StatT t_st; 119 const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1); 120 121 if (not status_known(t)) 122 return err.report(m_ec1); 123 124 if (!exists(f) || is_other(f) || is_other(t) || (is_directory(f) && is_regular_file(t)) || 125 (exists(t) && detail::stat_equivalent(f_st, t_st))) { 126 return err.report(errc::function_not_supported); 127 } 128 129 if (is_symlink(f)) { 130 if (bool(copy_options::skip_symlinks & options)) { 131 // do nothing 132 } else if (not exists(t)) { 133 __copy_symlink(from, to, ec); 134 } else { 135 return err.report(errc::file_exists); 136 } 137 return; 138 } else if (is_regular_file(f)) { 139 if (bool(copy_options::directories_only & options)) { 140 // do nothing 141 } else if (bool(copy_options::create_symlinks & options)) { 142 __create_symlink(from, to, ec); 143 } else if (bool(copy_options::create_hard_links & options)) { 144 __create_hard_link(from, to, ec); 145 } else if (is_directory(t)) { 146 __copy_file(from, to / from.filename(), options, ec); 147 } else { 148 __copy_file(from, to, options, ec); 149 } 150 return; 151 } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) { 152 return err.report(errc::is_a_directory); 153 } else if (is_directory(f) && (bool(copy_options::recursive & options) || copy_options::none == options)) { 154 if (!exists(t)) { 155 // create directory to with attributes from 'from'. 156 __create_directory(to, from, ec); 157 if (ec && *ec) { 158 return; 159 } 160 } 161 directory_iterator it = ec ? directory_iterator(from, *ec) : directory_iterator(from); 162 if (ec && *ec) { 163 return; 164 } 165 error_code m_ec2; 166 for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) { 167 __copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec); 168 if (ec && *ec) { 169 return; 170 } 171 } 172 if (m_ec2) { 173 return err.report(m_ec2); 174 } 175 } 176 } 177 178 namespace detail { 179 namespace { 180 181 #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) 182 bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 183 size_t count = read_fd.get_stat().st_size; 184 do { 185 ssize_t res; 186 if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) { 187 ec = capture_errno(); 188 return false; 189 } 190 count -= res; 191 } while (count > 0); 192 193 ec.clear(); 194 195 return true; 196 } 197 #elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE) 198 bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 199 struct CopyFileState { 200 copyfile_state_t state; 201 CopyFileState() { state = copyfile_state_alloc(); } 202 ~CopyFileState() { copyfile_state_free(state); } 203 204 private: 205 CopyFileState(CopyFileState const&) = delete; 206 CopyFileState& operator=(CopyFileState const&) = delete; 207 }; 208 209 CopyFileState cfs; 210 if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) { 211 ec = capture_errno(); 212 return false; 213 } 214 215 ec.clear(); 216 return true; 217 } 218 #elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM) 219 bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 220 ifstream in; 221 in.__open(read_fd.fd, ios::binary); 222 if (!in.is_open()) { 223 // This assumes that __open didn't reset the error code. 224 ec = capture_errno(); 225 return false; 226 } 227 read_fd.fd = -1; 228 ofstream out; 229 out.__open(write_fd.fd, ios::binary); 230 if (!out.is_open()) { 231 ec = capture_errno(); 232 return false; 233 } 234 write_fd.fd = -1; 235 236 if (in.good() && out.good()) { 237 using InIt = istreambuf_iterator<char>; 238 using OutIt = ostreambuf_iterator<char>; 239 InIt bin(in); 240 InIt ein; 241 OutIt bout(out); 242 copy(bin, ein, bout); 243 } 244 if (out.fail() || in.fail()) { 245 ec = make_error_code(errc::io_error); 246 return false; 247 } 248 249 ec.clear(); 250 return true; 251 } 252 #else 253 # error "Unknown implementation for copy_file_impl" 254 #endif // copy_file_impl implementation 255 256 } // end anonymous namespace 257 } // end namespace detail 258 259 bool __copy_file(const path& from, const path& to, copy_options options, error_code* ec) { 260 using detail::FileDescriptor; 261 ErrorHandler<bool> err("copy_file", ec, &to, &from); 262 263 error_code m_ec; 264 FileDescriptor from_fd = FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY); 265 if (m_ec) 266 return err.report(m_ec); 267 268 auto from_st = from_fd.get_status(); 269 StatT const& from_stat = from_fd.get_stat(); 270 if (!is_regular_file(from_st)) { 271 if (not m_ec) 272 m_ec = make_error_code(errc::not_supported); 273 return err.report(m_ec); 274 } 275 276 const bool skip_existing = bool(copy_options::skip_existing & options); 277 const bool update_existing = bool(copy_options::update_existing & options); 278 const bool overwrite_existing = bool(copy_options::overwrite_existing & options); 279 280 StatT to_stat_path; 281 file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec); 282 if (!status_known(to_st)) 283 return err.report(m_ec); 284 285 const bool to_exists = exists(to_st); 286 if (to_exists && !is_regular_file(to_st)) 287 return err.report(errc::not_supported); 288 289 if (to_exists && detail::stat_equivalent(from_stat, to_stat_path)) 290 return err.report(errc::file_exists); 291 292 if (to_exists && skip_existing) 293 return false; 294 295 bool ShouldCopy = [&]() { 296 if (to_exists && update_existing) { 297 auto from_time = detail::extract_mtime(from_stat); 298 auto to_time = detail::extract_mtime(to_stat_path); 299 if (from_time.tv_sec < to_time.tv_sec) 300 return false; 301 if (from_time.tv_sec == to_time.tv_sec && from_time.tv_nsec <= to_time.tv_nsec) 302 return false; 303 return true; 304 } 305 if (!to_exists || overwrite_existing) 306 return true; 307 return err.report(errc::file_exists); 308 }(); 309 if (!ShouldCopy) 310 return false; 311 312 // Don't truncate right away. We may not be opening the file we originally 313 // looked at; we'll check this later. 314 int to_open_flags = O_WRONLY | O_BINARY; 315 if (!to_exists) 316 to_open_flags |= O_CREAT; 317 FileDescriptor to_fd = FileDescriptor::create_with_status(&to, m_ec, to_open_flags, from_stat.st_mode); 318 if (m_ec) 319 return err.report(m_ec); 320 321 if (to_exists) { 322 // Check that the file we initially stat'ed is equivalent to the one 323 // we opened. 324 // FIXME: report this better. 325 if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat())) 326 return err.report(errc::bad_file_descriptor); 327 328 // Set the permissions and truncate the file we opened. 329 if (detail::posix_fchmod(to_fd, from_stat, m_ec)) 330 return err.report(m_ec); 331 if (detail::posix_ftruncate(to_fd, 0, m_ec)) 332 return err.report(m_ec); 333 } 334 335 if (!detail::copy_file_impl(from_fd, to_fd, m_ec)) { 336 // FIXME: Remove the dest file if we failed, and it didn't exist previously. 337 return err.report(m_ec); 338 } 339 340 return true; 341 } 342 343 void __copy_symlink(const path& existing_symlink, const path& new_symlink, error_code* ec) { 344 const path real_path(__read_symlink(existing_symlink, ec)); 345 if (ec && *ec) { 346 return; 347 } 348 #if defined(_LIBCPP_WIN32API) 349 error_code local_ec; 350 if (is_directory(real_path, local_ec)) 351 __create_directory_symlink(real_path, new_symlink, ec); 352 else 353 #endif 354 __create_symlink(real_path, new_symlink, ec); 355 } 356 357 bool __create_directories(const path& p, error_code* ec) { 358 ErrorHandler<bool> err("create_directories", ec, &p); 359 360 error_code m_ec; 361 auto const st = detail::posix_stat(p, &m_ec); 362 if (!status_known(st)) 363 return err.report(m_ec); 364 else if (is_directory(st)) 365 return false; 366 else if (exists(st)) 367 return err.report(errc::file_exists); 368 369 const path parent = p.parent_path(); 370 if (!parent.empty()) { 371 const file_status parent_st = status(parent, m_ec); 372 if (not status_known(parent_st)) 373 return err.report(m_ec); 374 if (not exists(parent_st)) { 375 if (parent == p) 376 return err.report(errc::invalid_argument); 377 __create_directories(parent, ec); 378 if (ec && *ec) { 379 return false; 380 } 381 } else if (not is_directory(parent_st)) 382 return err.report(errc::not_a_directory); 383 } 384 bool ret = __create_directory(p, &m_ec); 385 if (m_ec) 386 return err.report(m_ec); 387 return ret; 388 } 389 390 bool __create_directory(const path& p, error_code* ec) { 391 ErrorHandler<bool> err("create_directory", ec, &p); 392 393 if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0) 394 return true; 395 396 if (errno != EEXIST) 397 return err.report(capture_errno()); 398 error_code mec = capture_errno(); 399 error_code ignored_ec; 400 const file_status st = status(p, ignored_ec); 401 if (!is_directory(st)) 402 return err.report(mec); 403 return false; 404 } 405 406 bool __create_directory(path const& p, path const& attributes, error_code* ec) { 407 ErrorHandler<bool> err("create_directory", ec, &p, &attributes); 408 409 StatT attr_stat; 410 error_code mec; 411 file_status st = detail::posix_stat(attributes, attr_stat, &mec); 412 if (!status_known(st)) 413 return err.report(mec); 414 if (!is_directory(st)) 415 return err.report(errc::not_a_directory, "the specified attribute path is invalid"); 416 417 if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0) 418 return true; 419 420 if (errno != EEXIST) 421 return err.report(capture_errno()); 422 423 mec = capture_errno(); 424 error_code ignored_ec; 425 st = status(p, ignored_ec); 426 if (!is_directory(st)) 427 return err.report(mec); 428 return false; 429 } 430 431 void __create_directory_symlink(path const& from, path const& to, error_code* ec) { 432 ErrorHandler<void> err("create_directory_symlink", ec, &from, &to); 433 if (detail::symlink_dir(from.c_str(), to.c_str()) == -1) 434 return err.report(capture_errno()); 435 } 436 437 void __create_hard_link(const path& from, const path& to, error_code* ec) { 438 ErrorHandler<void> err("create_hard_link", ec, &from, &to); 439 if (detail::link(from.c_str(), to.c_str()) == -1) 440 return err.report(capture_errno()); 441 } 442 443 void __create_symlink(path const& from, path const& to, error_code* ec) { 444 ErrorHandler<void> err("create_symlink", ec, &from, &to); 445 if (detail::symlink_file(from.c_str(), to.c_str()) == -1) 446 return err.report(capture_errno()); 447 } 448 449 path __current_path(error_code* ec) { 450 ErrorHandler<path> err("current_path", ec); 451 452 #if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__) 453 // Common extension outside of POSIX getcwd() spec, without needing to 454 // preallocate a buffer. Also supported by a number of other POSIX libcs. 455 int size = 0; 456 path::value_type* ptr = nullptr; 457 typedef decltype(&::free) Deleter; 458 Deleter deleter = &::free; 459 #else 460 errno = 0; // Note: POSIX mandates that modifying `errno` is thread-safe. 461 auto size = ::pathconf(".", _PC_PATH_MAX); 462 if (size == -1) { 463 if (errno != 0) { 464 return err.report(capture_errno(), "call to pathconf failed"); 465 466 // `pathconf` returns `-1` without an error to indicate no limit. 467 } else { 468 # if defined(__MVS__) && !defined(PATH_MAX) 469 size = _XOPEN_PATH_MAX + 1; 470 # else 471 size = PATH_MAX + 1; 472 # endif 473 } 474 } 475 476 auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]); 477 path::value_type* ptr = buff.get(); 478 479 // Preallocated buffer, don't free the buffer in the second unique_ptr 480 // below. 481 struct Deleter { 482 void operator()(void*) const {} 483 }; 484 Deleter deleter; 485 #endif 486 487 unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter); 488 if (hold.get() == nullptr) 489 return err.report(capture_errno(), "call to getcwd failed"); 490 491 return {hold.get()}; 492 } 493 494 void __current_path(const path& p, error_code* ec) { 495 ErrorHandler<void> err("current_path", ec, &p); 496 if (detail::chdir(p.c_str()) == -1) 497 err.report(capture_errno()); 498 } 499 500 bool __equivalent(const path& p1, const path& p2, error_code* ec) { 501 ErrorHandler<bool> err("equivalent", ec, &p1, &p2); 502 503 error_code ec1, ec2; 504 StatT st1 = {}, st2 = {}; 505 auto s1 = detail::posix_stat(p1.native(), st1, &ec1); 506 if (!exists(s1)) 507 return err.report(errc::not_supported); 508 auto s2 = detail::posix_stat(p2.native(), st2, &ec2); 509 if (!exists(s2)) 510 return err.report(errc::not_supported); 511 512 return detail::stat_equivalent(st1, st2); 513 } 514 515 uintmax_t __file_size(const path& p, error_code* ec) { 516 ErrorHandler<uintmax_t> err("file_size", ec, &p); 517 518 error_code m_ec; 519 StatT st; 520 file_status fst = detail::posix_stat(p, st, &m_ec); 521 if (!exists(fst) || !is_regular_file(fst)) { 522 errc error_kind = is_directory(fst) ? errc::is_a_directory : errc::not_supported; 523 if (!m_ec) 524 m_ec = make_error_code(error_kind); 525 return err.report(m_ec); 526 } 527 // is_regular_file(p) == true 528 return static_cast<uintmax_t>(st.st_size); 529 } 530 531 uintmax_t __hard_link_count(const path& p, error_code* ec) { 532 ErrorHandler<uintmax_t> err("hard_link_count", ec, &p); 533 534 error_code m_ec; 535 StatT st; 536 detail::posix_stat(p, st, &m_ec); 537 if (m_ec) 538 return err.report(m_ec); 539 return static_cast<uintmax_t>(st.st_nlink); 540 } 541 542 bool __fs_is_empty(const path& p, error_code* ec) { 543 ErrorHandler<bool> err("is_empty", ec, &p); 544 545 error_code m_ec; 546 StatT pst; 547 auto st = detail::posix_stat(p, pst, &m_ec); 548 if (m_ec) 549 return err.report(m_ec); 550 else if (!is_directory(st) && !is_regular_file(st)) 551 return err.report(errc::not_supported); 552 else if (is_directory(st)) { 553 auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p); 554 if (ec && *ec) 555 return false; 556 return it == directory_iterator{}; 557 } else if (is_regular_file(st)) 558 return static_cast<uintmax_t>(pst.st_size) == 0; 559 560 __libcpp_unreachable(); 561 } 562 563 file_time_type __last_write_time(const path& p, error_code* ec) { 564 using namespace chrono; 565 ErrorHandler<file_time_type> err("last_write_time", ec, &p); 566 567 error_code m_ec; 568 StatT st; 569 detail::posix_stat(p, st, &m_ec); 570 if (m_ec) 571 return err.report(m_ec); 572 return detail::__extract_last_write_time(p, st, ec); 573 } 574 575 void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { 576 using detail::fs_time; 577 ErrorHandler<void> err("last_write_time", ec, &p); 578 579 #if defined(_LIBCPP_WIN32API) 580 TimeSpec ts; 581 if (!fs_time::convert_to_timespec(ts, new_time)) 582 return err.report(errc::value_too_large); 583 detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0); 584 if (!h) 585 return err.report(detail::make_windows_error(GetLastError())); 586 FILETIME last_write = timespec_to_filetime(ts); 587 if (!SetFileTime(h, nullptr, nullptr, &last_write)) 588 return err.report(detail::make_windows_error(GetLastError())); 589 #else 590 error_code m_ec; 591 array<TimeSpec, 2> tbuf; 592 # if !defined(_LIBCPP_USE_UTIMENSAT) 593 // This implementation has a race condition between determining the 594 // last access time and attempting to set it to the same value using 595 // ::utimes 596 StatT st; 597 file_status fst = detail::posix_stat(p, st, &m_ec); 598 if (m_ec) 599 return err.report(m_ec); 600 tbuf[0] = detail::extract_atime(st); 601 # else 602 tbuf[0].tv_sec = 0; 603 tbuf[0].tv_nsec = UTIME_OMIT; 604 # endif 605 if (!fs_time::convert_to_timespec(tbuf[1], new_time)) 606 return err.report(errc::value_too_large); 607 608 detail::set_file_times(p, tbuf, m_ec); 609 if (m_ec) 610 return err.report(m_ec); 611 #endif 612 } 613 614 void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) { 615 ErrorHandler<void> err("permissions", ec, &p); 616 617 auto has_opt = [&](perm_options o) { return bool(o & opts); }; 618 const bool resolve_symlinks = !has_opt(perm_options::nofollow); 619 const bool add_perms = has_opt(perm_options::add); 620 const bool remove_perms = has_opt(perm_options::remove); 621 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 622 (add_perms + remove_perms + has_opt(perm_options::replace)) == 1, 623 "One and only one of the perm_options constants 'replace', 'add', or 'remove' must be present in opts"); 624 625 bool set_sym_perms = false; 626 prms &= perms::mask; 627 if (!resolve_symlinks || (add_perms || remove_perms)) { 628 error_code m_ec; 629 file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) : detail::posix_lstat(p, &m_ec); 630 set_sym_perms = is_symlink(st); 631 if (m_ec) 632 return err.report(m_ec); 633 // TODO(hardening): double-check this assertion -- it might be a valid (if rare) case when the permissions are 634 // unknown. 635 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(st.permissions() != perms::unknown, "Permissions unexpectedly unknown"); 636 if (add_perms) 637 prms |= st.permissions(); 638 else if (remove_perms) 639 prms = st.permissions() & ~prms; 640 } 641 const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask); 642 643 #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) 644 const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; 645 if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { 646 return err.report(capture_errno()); 647 } 648 #else 649 if (set_sym_perms) 650 return err.report(errc::operation_not_supported); 651 if (::chmod(p.c_str(), real_perms) == -1) { 652 return err.report(capture_errno()); 653 } 654 #endif 655 } 656 657 path __read_symlink(const path& p, error_code* ec) { 658 ErrorHandler<path> err("read_symlink", ec, &p); 659 660 #if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE) 661 struct NullDeleter { 662 void operator()(void*) const {} 663 }; 664 # ifdef MAX_SYMLINK_SIZE 665 const size_t size = MAX_SYMLINK_SIZE + 1; 666 # else 667 const size_t size = PATH_MAX + 1; 668 # endif 669 path::value_type stack_buff[size]; 670 auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff); 671 #else 672 StatT sb; 673 if (detail::lstat(p.c_str(), &sb) == -1) { 674 return err.report(capture_errno()); 675 } 676 const size_t size = sb.st_size + 1; 677 auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]); 678 #endif 679 detail::SSizeT ret; 680 if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) 681 return err.report(capture_errno()); 682 // Note that `ret` returning `0` would work, resulting in a valid empty string being returned. 683 if (static_cast<size_t>(ret) >= size) 684 return err.report(errc::value_too_large); 685 buff[ret] = 0; 686 return {buff.get()}; 687 } 688 689 bool __remove(const path& p, error_code* ec) { 690 ErrorHandler<bool> err("remove", ec, &p); 691 if (detail::remove(p.c_str()) == -1) { 692 if (errno != ENOENT) 693 err.report(capture_errno()); 694 return false; 695 } 696 return true; 697 } 698 699 // We currently have two implementations of `__remove_all`. The first one is general and 700 // used on platforms where we don't have access to the `openat()` family of POSIX functions. 701 // That implementation uses `directory_iterator`, however it is vulnerable to some race 702 // conditions, see https://reviews.llvm.org/D118134 for details. 703 // 704 // The second implementation is used on platforms where `openat()` & friends are available, 705 // and it threads file descriptors through recursive calls to avoid such race conditions. 706 #if defined(_LIBCPP_WIN32API) || defined(__MVS__) 707 # define REMOVE_ALL_USE_DIRECTORY_ITERATOR 708 #endif 709 710 #if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR) 711 712 namespace { 713 714 uintmax_t remove_all_impl(path const& p, error_code& ec) { 715 const auto npos = static_cast<uintmax_t>(-1); 716 const file_status st = __symlink_status(p, &ec); 717 if (ec) 718 return npos; 719 uintmax_t count = 1; 720 if (is_directory(st)) { 721 for (directory_iterator it(p, ec); !ec && it != directory_iterator(); it.increment(ec)) { 722 auto other_count = remove_all_impl(it->path(), ec); 723 if (ec) 724 return npos; 725 count += other_count; 726 } 727 if (ec) 728 return npos; 729 } 730 if (!__remove(p, &ec)) 731 return npos; 732 return count; 733 } 734 735 } // end namespace 736 737 uintmax_t __remove_all(const path& p, error_code* ec) { 738 ErrorHandler<uintmax_t> err("remove_all", ec, &p); 739 740 error_code mec; 741 auto count = remove_all_impl(p, mec); 742 if (mec) { 743 if (mec == errc::no_such_file_or_directory) 744 return 0; 745 return err.report(mec); 746 } 747 return count; 748 } 749 750 #else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR 751 752 namespace { 753 754 template <class Cleanup> 755 struct scope_exit { 756 explicit scope_exit(Cleanup const& cleanup) : cleanup_(cleanup) {} 757 758 ~scope_exit() { cleanup_(); } 759 760 private: 761 Cleanup cleanup_; 762 }; 763 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scope_exit); 764 765 uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) { 766 // First, try to open the path as a directory. 767 const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW; 768 int fd = ::openat(parent_directory, p.c_str(), options); 769 if (fd != -1) { 770 // If that worked, iterate over the contents of the directory and 771 // remove everything in it, recursively. 772 DIR* stream = ::fdopendir(fd); 773 if (stream == nullptr) { 774 ::close(fd); 775 ec = detail::capture_errno(); 776 return 0; 777 } 778 // Note: `::closedir` will also close the associated file descriptor, so 779 // there should be no call to `close(fd)`. 780 scope_exit close_stream([=] { ::closedir(stream); }); 781 782 uintmax_t count = 0; 783 while (true) { 784 auto [str, type] = detail::posix_readdir(stream, ec); 785 static_assert(std::is_same_v<decltype(str), std::string_view>); 786 if (str == "." || str == "..") { 787 continue; 788 } else if (ec || str.empty()) { 789 break; // we're done iterating through the directory 790 } else { 791 count += remove_all_impl(fd, str, ec); 792 } 793 } 794 795 // Then, remove the now-empty directory itself. 796 if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) { 797 ec = detail::capture_errno(); 798 return count; 799 } 800 801 return count + 1; // the contents of the directory + the directory itself 802 } 803 804 ec = detail::capture_errno(); 805 806 // If we failed to open `p` because it didn't exist, it's not an 807 // error -- it might have moved or have been deleted already. 808 if (ec == errc::no_such_file_or_directory) { 809 ec.clear(); 810 return 0; 811 } 812 813 // If opening `p` failed because it wasn't a directory, remove it as 814 // a normal file instead. Note that `openat()` can return either ENOTDIR 815 // or ELOOP depending on the exact reason of the failure. On FreeBSD it 816 // may return EMLINK instead of ELOOP, contradicting POSIX. 817 if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) { 818 ec.clear(); 819 if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) { 820 ec = detail::capture_errno(); 821 return 0; 822 } 823 return 1; 824 } 825 826 // Otherwise, it's a real error -- we don't remove anything. 827 return 0; 828 } 829 830 } // end namespace 831 832 uintmax_t __remove_all(const path& p, error_code* ec) { 833 ErrorHandler<uintmax_t> err("remove_all", ec, &p); 834 error_code mec; 835 uintmax_t count = remove_all_impl(AT_FDCWD, p, mec); 836 if (mec) 837 return err.report(mec); 838 return count; 839 } 840 841 #endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR 842 843 void __rename(const path& from, const path& to, error_code* ec) { 844 ErrorHandler<void> err("rename", ec, &from, &to); 845 if (detail::rename(from.c_str(), to.c_str()) == -1) 846 err.report(capture_errno()); 847 } 848 849 void __resize_file(const path& p, uintmax_t size, error_code* ec) { 850 ErrorHandler<void> err("resize_file", ec, &p); 851 if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1) 852 return err.report(capture_errno()); 853 } 854 855 space_info __space(const path& p, error_code* ec) { 856 ErrorHandler<void> err("space", ec, &p); 857 space_info si; 858 detail::StatVFS m_svfs = {}; 859 if (detail::statvfs(p.c_str(), &m_svfs) == -1) { 860 err.report(capture_errno()); 861 si.capacity = si.free = si.available = static_cast<uintmax_t>(-1); 862 return si; 863 } 864 // Multiply with overflow checking. 865 auto do_mult = [&](uintmax_t& out, uintmax_t other) { 866 out = other * m_svfs.f_frsize; 867 if (other == 0 || out / other != m_svfs.f_frsize) 868 out = static_cast<uintmax_t>(-1); 869 }; 870 do_mult(si.capacity, m_svfs.f_blocks); 871 do_mult(si.free, m_svfs.f_bfree); 872 do_mult(si.available, m_svfs.f_bavail); 873 return si; 874 } 875 876 file_status __status(const path& p, error_code* ec) { return detail::posix_stat(p, ec); } 877 878 file_status __symlink_status(const path& p, error_code* ec) { return detail::posix_lstat(p, ec); } 879 880 path __temp_directory_path(error_code* ec) { 881 ErrorHandler<path> err("temp_directory_path", ec); 882 883 #if defined(_LIBCPP_WIN32API) 884 wchar_t buf[MAX_PATH]; 885 DWORD retval = GetTempPathW(MAX_PATH, buf); 886 if (!retval) 887 return err.report(detail::make_windows_error(GetLastError())); 888 if (retval > MAX_PATH) 889 return err.report(errc::filename_too_long); 890 // GetTempPathW returns a path with a trailing slash, which we 891 // shouldn't include for consistency. 892 if (buf[retval - 1] == L'\\') 893 buf[retval - 1] = L'\0'; 894 path p(buf); 895 #else 896 const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; 897 const char* ret = nullptr; 898 899 for (auto& ep : env_paths) 900 if ((ret = getenv(ep))) 901 break; 902 if (ret == nullptr) { 903 # if defined(__ANDROID__) 904 ret = "/data/local/tmp"; 905 # else 906 ret = "/tmp"; 907 # endif 908 } 909 910 path p(ret); 911 #endif 912 error_code m_ec; 913 file_status st = detail::posix_stat(p, &m_ec); 914 if (!status_known(st)) 915 return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str()); 916 917 if (!exists(st) || !is_directory(st)) 918 return err.report(errc::not_a_directory, "path " PATH_CSTR_FMT " is not a directory", p.c_str()); 919 920 return p; 921 } 922 923 path __weakly_canonical(const path& p, error_code* ec) { 924 ErrorHandler<path> err("weakly_canonical", ec, &p); 925 926 if (p.empty()) 927 return __canonical("", ec); 928 929 path result; 930 path tmp; 931 tmp.__reserve(p.native().size()); 932 auto PP = PathParser::CreateEnd(p.native()); 933 --PP; 934 vector<string_view_t> DNEParts; 935 936 error_code m_ec; 937 while (PP.State_ != PathParser::PS_BeforeBegin) { 938 tmp.assign(createView(p.native().data(), &PP.RawEntry.back())); 939 file_status st = __status(tmp, &m_ec); 940 if (!status_known(st)) { 941 return err.report(m_ec); 942 } else if (exists(st)) { 943 result = __canonical(tmp, &m_ec); 944 if (m_ec) { 945 return err.report(m_ec); 946 } 947 break; 948 } 949 DNEParts.push_back(*PP); 950 --PP; 951 } 952 if (PP.State_ == PathParser::PS_BeforeBegin) { 953 result = __canonical("", &m_ec); 954 if (m_ec) { 955 return err.report(m_ec); 956 } 957 } 958 if (DNEParts.empty()) 959 return result; 960 for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It) 961 result /= *It; 962 return result.lexically_normal(); 963 } 964 965 _LIBCPP_END_NAMESPACE_FILESYSTEM 966