chromium/third_party/libc++/src/src/filesystem/operations.cpp

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include <__assert>
#include <__config>
#include <__utility/unreachable.h>
#include <array>
#include <climits>
#include <cstdlib>
#include <filesystem>
#include <iterator>
#include <string_view>
#include <type_traits>
#include <vector>

#include "error.h"
#include "file_descriptor.h"
#include "path_parser.h"
#include "posix_compat.h"
#include "time_utils.h"

#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#  include <windows.h>
#else
#  include <dirent.h>
#  include <sys/stat.h>
#  include <sys/statvfs.h>
#  include <unistd.h>
#endif
#include <fcntl.h> /* values for fchmodat */
#include <time.h>

#if __has_include(<sys/sendfile.h>)
#  include <sys/sendfile.h>
#define _LIBCPP_FILESYSTEM_USE_SENDFILE
#elif defined(__APPLE__) || __has_include(<copyfile.h>)
#  include <copyfile.h>
#define _LIBCPP_FILESYSTEM_USE_COPYFILE
#else
#  include <fstream>
#define _LIBCPP_FILESYSTEM_USE_FSTREAM
#endif

#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
#  pragma comment(lib, "rt")
#endif

_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM

capture_errno;
ErrorHandler;
StatT;
TimeSpec;
createView;
PathParser;
string_view_t;

static path __do_absolute(const path& p, path* cwd, error_code* ec) {}

path __absolute(const path& p, error_code* ec) {}

path __canonical(path const& orig_p, error_code* ec) {}

void __copy(const path& from, const path& to, copy_options options, error_code* ec) {}

namespace detail {
namespace {

#if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {}
#elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
  struct CopyFileState {
    copyfile_state_t state;
    CopyFileState() { state = copyfile_state_alloc(); }
    ~CopyFileState() { copyfile_state_free(state); }

  private:
    CopyFileState(CopyFileState const&)            = delete;
    CopyFileState& operator=(CopyFileState const&) = delete;
  };

  CopyFileState cfs;
  if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
    ec = capture_errno();
    return false;
  }

  ec.clear();
  return true;
}
#elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
  ifstream in;
  in.__open(read_fd.fd, ios::binary);
  if (!in.is_open()) {
    // This assumes that __open didn't reset the error code.
    ec = capture_errno();
    return false;
  }
  read_fd.fd = -1;
  ofstream out;
  out.__open(write_fd.fd, ios::binary);
  if (!out.is_open()) {
    ec = capture_errno();
    return false;
  }
  write_fd.fd = -1;

  if (in.good() && out.good()) {
    using InIt  = istreambuf_iterator<char>;
    using OutIt = ostreambuf_iterator<char>;
    InIt bin(in);
    InIt ein;
    OutIt bout(out);
    copy(bin, ein, bout);
  }
  if (out.fail() || in.fail()) {
    ec = make_error_code(errc::io_error);
    return false;
  }

  ec.clear();
  return true;
}
#else
#  error "Unknown implementation for copy_file_impl"
#endif // copy_file_impl implementation

} // end anonymous namespace
} // end namespace detail

bool __copy_file(const path& from, const path& to, copy_options options, error_code* ec) {}

void __copy_symlink(const path& existing_symlink, const path& new_symlink, error_code* ec) {}

bool __create_directories(const path& p, error_code* ec) {}

bool __create_directory(const path& p, error_code* ec) {}

bool __create_directory(path const& p, path const& attributes, error_code* ec) {}

void __create_directory_symlink(path const& from, path const& to, error_code* ec) {}

void __create_hard_link(const path& from, const path& to, error_code* ec) {}

void __create_symlink(path const& from, path const& to, error_code* ec) {}

path __current_path(error_code* ec) {}

void __current_path(const path& p, error_code* ec) {}

bool __equivalent(const path& p1, const path& p2, error_code* ec) {}

uintmax_t __file_size(const path& p, error_code* ec) {}

uintmax_t __hard_link_count(const path& p, error_code* ec) {}

bool __fs_is_empty(const path& p, error_code* ec) {}

file_time_type __last_write_time(const path& p, error_code* ec) {}

void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {}

void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) {}

path __read_symlink(const path& p, error_code* ec) {}

bool __remove(const path& p, error_code* ec) {}

// We currently have two implementations of `__remove_all`. The first one is general and
// used on platforms where we don't have access to the `openat()` family of POSIX functions.
// That implementation uses `directory_iterator`, however it is vulnerable to some race
// conditions, see https://reviews.llvm.org/D118134 for details.
//
// The second implementation is used on platforms where `openat()` & friends are available,
// and it threads file descriptors through recursive calls to avoid such race conditions.
#if defined(_LIBCPP_WIN32API) || defined(__MVS__)
#define REMOVE_ALL_USE_DIRECTORY_ITERATOR
#endif

#if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR)

namespace {

uintmax_t remove_all_impl(path const& p, error_code& ec) {
  const auto npos      = static_cast<uintmax_t>(-1);
  const file_status st = __symlink_status(p, &ec);
  if (ec)
    return npos;
  uintmax_t count = 1;
  if (is_directory(st)) {
    for (directory_iterator it(p, ec); !ec && it != directory_iterator(); it.increment(ec)) {
      auto other_count = remove_all_impl(it->path(), ec);
      if (ec)
        return npos;
      count += other_count;
    }
    if (ec)
      return npos;
  }
  if (!__remove(p, &ec))
    return npos;
  return count;
}

} // end namespace

uintmax_t __remove_all(const path& p, error_code* ec) {
  ErrorHandler<uintmax_t> err("remove_all", ec, &p);

  error_code mec;
  auto count = remove_all_impl(p, mec);
  if (mec) {
    if (mec == errc::no_such_file_or_directory)
      return 0;
    return err.report(mec);
  }
  return count;
}

#else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR

namespace // end namespace

uintmax_t __remove_all(const path& p, error_code* ec) {}

#endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR

void __rename(const path& from, const path& to, error_code* ec) {}

void __resize_file(const path& p, uintmax_t size, error_code* ec) {}

space_info __space(const path& p, error_code* ec) {}

file_status __status(const path& p, error_code* ec) {}

file_status __symlink_status(const path& p, error_code* ec) {}

path __temp_directory_path(error_code* ec) {}

path __weakly_canonical(const path& p, error_code* ec) {}

_LIBCPP_END_NAMESPACE_FILESYSTEM