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