1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 981ad6265SDimitry Andric #include <__assert> 1006c3fb27SDimitry Andric #include <__config> 1181ad6265SDimitry Andric #include <__utility/unreachable.h> 1281ad6265SDimitry Andric #include <array> 1381ad6265SDimitry Andric #include <climits> 1481ad6265SDimitry Andric #include <cstdlib> 1581ad6265SDimitry Andric #include <filesystem> 1681ad6265SDimitry Andric #include <iterator> 1781ad6265SDimitry Andric #include <string_view> 1881ad6265SDimitry Andric #include <type_traits> 1981ad6265SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 2106c3fb27SDimitry Andric #include "error.h" 2206c3fb27SDimitry Andric #include "file_descriptor.h" 2306c3fb27SDimitry Andric #include "path_parser.h" 24fe6060f1SDimitry Andric #include "posix_compat.h" 2506c3fb27SDimitry Andric #include "time_utils.h" 26fe6060f1SDimitry Andric 27e8d8bef9SDimitry Andric #if defined(_LIBCPP_WIN32API) 28e8d8bef9SDimitry Andric # define WIN32_LEAN_AND_MEAN 29e8d8bef9SDimitry Andric # define NOMINMAX 30e8d8bef9SDimitry Andric # include <windows.h> 31e8d8bef9SDimitry Andric #else 321fd87a68SDimitry Andric # include <dirent.h> 330b57cec5SDimitry Andric # include <sys/stat.h> 340b57cec5SDimitry Andric # include <sys/statvfs.h> 351fd87a68SDimitry Andric # include <unistd.h> 36e8d8bef9SDimitry Andric #endif 370b57cec5SDimitry Andric #include <fcntl.h> /* values for fchmodat */ 38cb14a3feSDimitry Andric #include <time.h> 390b57cec5SDimitry Andric 40e8d8bef9SDimitry Andric #if __has_include(<sys/sendfile.h>) 410b57cec5SDimitry Andric # include <sys/sendfile.h> 42e8d8bef9SDimitry Andric # define _LIBCPP_FILESYSTEM_USE_SENDFILE 430b57cec5SDimitry Andric #elif defined(__APPLE__) || __has_include(<copyfile.h>) 440b57cec5SDimitry Andric # include <copyfile.h> 45e8d8bef9SDimitry Andric # define _LIBCPP_FILESYSTEM_USE_COPYFILE 46e8d8bef9SDimitry Andric #else 4781ad6265SDimitry Andric # include <fstream> 48e8d8bef9SDimitry Andric # define _LIBCPP_FILESYSTEM_USE_FSTREAM 490b57cec5SDimitry Andric #endif 500b57cec5SDimitry Andric 51480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) 520b57cec5SDimitry Andric # pragma comment(lib, "rt") 530b57cec5SDimitry Andric #endif 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric using detail::capture_errno; 580b57cec5SDimitry Andric using detail::ErrorHandler; 590b57cec5SDimitry Andric using detail::StatT; 600b57cec5SDimitry Andric using detail::TimeSpec; 610b57cec5SDimitry Andric using parser::createView; 620b57cec5SDimitry Andric using parser::PathParser; 630b57cec5SDimitry Andric using parser::string_view_t; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric static path __do_absolute(const path& p, path* cwd, error_code* ec) { 660b57cec5SDimitry Andric if (ec) 670b57cec5SDimitry Andric ec->clear(); 680b57cec5SDimitry Andric if (p.is_absolute()) 690b57cec5SDimitry Andric return p; 700b57cec5SDimitry Andric *cwd = __current_path(ec); 710b57cec5SDimitry Andric if (ec && *ec) 720b57cec5SDimitry Andric return {}; 730b57cec5SDimitry Andric return (*cwd) / p; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric path __absolute(const path& p, error_code* ec) { 770b57cec5SDimitry Andric path cwd; 780b57cec5SDimitry Andric return __do_absolute(p, &cwd, ec); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric path __canonical(path const& orig_p, error_code* ec) { 820b57cec5SDimitry Andric path cwd; 830b57cec5SDimitry Andric ErrorHandler<path> err("canonical", ec, &orig_p, &cwd); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric path p = __do_absolute(orig_p, &cwd, ec); 86fe6060f1SDimitry Andric #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API) 87cb14a3feSDimitry Andric std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free); 880b57cec5SDimitry Andric if (hold.get() == nullptr) 890b57cec5SDimitry Andric return err.report(capture_errno()); 900b57cec5SDimitry Andric return {hold.get()}; 910b57cec5SDimitry Andric #else 92e8d8bef9SDimitry Andric # if defined(__MVS__) && !defined(PATH_MAX) 93fe6060f1SDimitry Andric path::value_type buff[_XOPEN_PATH_MAX + 1]; 94e8d8bef9SDimitry Andric # else 95fe6060f1SDimitry Andric path::value_type buff[PATH_MAX + 1]; 96e8d8bef9SDimitry Andric # endif 97fe6060f1SDimitry Andric path::value_type* ret; 98fe6060f1SDimitry Andric if ((ret = detail::realpath(p.c_str(), buff)) == nullptr) 990b57cec5SDimitry Andric return err.report(capture_errno()); 1000b57cec5SDimitry Andric return {ret}; 1010b57cec5SDimitry Andric #endif 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 104cb14a3feSDimitry Andric void __copy(const path& from, const path& to, copy_options options, error_code* ec) { 1050b57cec5SDimitry Andric ErrorHandler<void> err("copy", ec, &from, &to); 1060b57cec5SDimitry Andric 107cb14a3feSDimitry Andric const bool sym_status = bool(options & (copy_options::create_symlinks | copy_options::skip_symlinks)); 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric const bool sym_status2 = bool(options & copy_options::copy_symlinks); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric error_code m_ec1; 112*0fca6ea1SDimitry Andric StatT f_st; 113cb14a3feSDimitry Andric const file_status f = 114cb14a3feSDimitry Andric sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1); 1150b57cec5SDimitry Andric if (m_ec1) 1160b57cec5SDimitry Andric return err.report(m_ec1); 1170b57cec5SDimitry Andric 118*0fca6ea1SDimitry Andric StatT t_st; 119cb14a3feSDimitry Andric const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric if (not status_known(t)) 1220b57cec5SDimitry Andric return err.report(m_ec1); 1230b57cec5SDimitry Andric 124cb14a3feSDimitry Andric if (!exists(f) || is_other(f) || is_other(t) || (is_directory(f) && is_regular_file(t)) || 125*0fca6ea1SDimitry Andric (exists(t) && detail::stat_equivalent(f_st, t_st))) { 1260b57cec5SDimitry Andric return err.report(errc::function_not_supported); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if (is_symlink(f)) { 1300b57cec5SDimitry Andric if (bool(copy_options::skip_symlinks & options)) { 1310b57cec5SDimitry Andric // do nothing 1320b57cec5SDimitry Andric } else if (not exists(t)) { 1330b57cec5SDimitry Andric __copy_symlink(from, to, ec); 1340b57cec5SDimitry Andric } else { 1350b57cec5SDimitry Andric return err.report(errc::file_exists); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric return; 1380b57cec5SDimitry Andric } else if (is_regular_file(f)) { 1390b57cec5SDimitry Andric if (bool(copy_options::directories_only & options)) { 1400b57cec5SDimitry Andric // do nothing 1410b57cec5SDimitry Andric } else if (bool(copy_options::create_symlinks & options)) { 1420b57cec5SDimitry Andric __create_symlink(from, to, ec); 1430b57cec5SDimitry Andric } else if (bool(copy_options::create_hard_links & options)) { 1440b57cec5SDimitry Andric __create_hard_link(from, to, ec); 1450b57cec5SDimitry Andric } else if (is_directory(t)) { 1460b57cec5SDimitry Andric __copy_file(from, to / from.filename(), options, ec); 1470b57cec5SDimitry Andric } else { 1480b57cec5SDimitry Andric __copy_file(from, to, options, ec); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric return; 1510b57cec5SDimitry Andric } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) { 1520b57cec5SDimitry Andric return err.report(errc::is_a_directory); 153cb14a3feSDimitry Andric } else if (is_directory(f) && (bool(copy_options::recursive & options) || copy_options::none == options)) { 1540b57cec5SDimitry Andric if (!exists(t)) { 1550b57cec5SDimitry Andric // create directory to with attributes from 'from'. 1560b57cec5SDimitry Andric __create_directory(to, from, ec); 1570b57cec5SDimitry Andric if (ec && *ec) { 1580b57cec5SDimitry Andric return; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } 161cb14a3feSDimitry Andric directory_iterator it = ec ? directory_iterator(from, *ec) : directory_iterator(from); 1620b57cec5SDimitry Andric if (ec && *ec) { 1630b57cec5SDimitry Andric return; 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric error_code m_ec2; 166*0fca6ea1SDimitry Andric for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) { 167cb14a3feSDimitry Andric __copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec); 1680b57cec5SDimitry Andric if (ec && *ec) { 1690b57cec5SDimitry Andric return; 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric } 172*0fca6ea1SDimitry Andric if (m_ec2) { 173*0fca6ea1SDimitry Andric return err.report(m_ec2); 174*0fca6ea1SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric namespace detail { 1790b57cec5SDimitry Andric namespace { 1800b57cec5SDimitry Andric 181e8d8bef9SDimitry Andric #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) 182e8d8bef9SDimitry Andric bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 1830b57cec5SDimitry Andric size_t count = read_fd.get_stat().st_size; 1840b57cec5SDimitry Andric do { 1850b57cec5SDimitry Andric ssize_t res; 1860b57cec5SDimitry Andric if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) { 1870b57cec5SDimitry Andric ec = capture_errno(); 1880b57cec5SDimitry Andric return false; 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric count -= res; 1910b57cec5SDimitry Andric } while (count > 0); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric ec.clear(); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric return true; 1960b57cec5SDimitry Andric } 197e8d8bef9SDimitry Andric #elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE) 198e8d8bef9SDimitry Andric bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 1990b57cec5SDimitry Andric struct CopyFileState { 2000b57cec5SDimitry Andric copyfile_state_t state; 2010b57cec5SDimitry Andric CopyFileState() { state = copyfile_state_alloc(); } 2020b57cec5SDimitry Andric ~CopyFileState() { copyfile_state_free(state); } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric private: 2050b57cec5SDimitry Andric CopyFileState(CopyFileState const&) = delete; 2060b57cec5SDimitry Andric CopyFileState& operator=(CopyFileState const&) = delete; 2070b57cec5SDimitry Andric }; 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric CopyFileState cfs; 2100b57cec5SDimitry Andric if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) { 2110b57cec5SDimitry Andric ec = capture_errno(); 2120b57cec5SDimitry Andric return false; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric ec.clear(); 2160b57cec5SDimitry Andric return true; 2170b57cec5SDimitry Andric } 218e8d8bef9SDimitry Andric #elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM) 219e8d8bef9SDimitry Andric bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 2200b57cec5SDimitry Andric ifstream in; 2210b57cec5SDimitry Andric in.__open(read_fd.fd, ios::binary); 2220b57cec5SDimitry Andric if (!in.is_open()) { 2230b57cec5SDimitry Andric // This assumes that __open didn't reset the error code. 2240b57cec5SDimitry Andric ec = capture_errno(); 2250b57cec5SDimitry Andric return false; 2260b57cec5SDimitry Andric } 227e8d8bef9SDimitry Andric read_fd.fd = -1; 2280b57cec5SDimitry Andric ofstream out; 2290b57cec5SDimitry Andric out.__open(write_fd.fd, ios::binary); 2300b57cec5SDimitry Andric if (!out.is_open()) { 2310b57cec5SDimitry Andric ec = capture_errno(); 2320b57cec5SDimitry Andric return false; 2330b57cec5SDimitry Andric } 234e8d8bef9SDimitry Andric write_fd.fd = -1; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric if (in.good() && out.good()) { 2370b57cec5SDimitry Andric using InIt = istreambuf_iterator<char>; 2380b57cec5SDimitry Andric using OutIt = ostreambuf_iterator<char>; 2390b57cec5SDimitry Andric InIt bin(in); 2400b57cec5SDimitry Andric InIt ein; 2410b57cec5SDimitry Andric OutIt bout(out); 2420b57cec5SDimitry Andric copy(bin, ein, bout); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric if (out.fail() || in.fail()) { 2450b57cec5SDimitry Andric ec = make_error_code(errc::io_error); 2460b57cec5SDimitry Andric return false; 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric ec.clear(); 2500b57cec5SDimitry Andric return true; 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric #else 253e8d8bef9SDimitry Andric # error "Unknown implementation for copy_file_impl" 254e8d8bef9SDimitry Andric #endif // copy_file_impl implementation 2550b57cec5SDimitry Andric 256e8d8bef9SDimitry Andric } // end anonymous namespace 257e8d8bef9SDimitry Andric } // end namespace detail 2580b57cec5SDimitry Andric 259cb14a3feSDimitry Andric bool __copy_file(const path& from, const path& to, copy_options options, error_code* ec) { 2600b57cec5SDimitry Andric using detail::FileDescriptor; 2610b57cec5SDimitry Andric ErrorHandler<bool> err("copy_file", ec, &to, &from); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric error_code m_ec; 264cb14a3feSDimitry Andric FileDescriptor from_fd = FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY); 2650b57cec5SDimitry Andric if (m_ec) 2660b57cec5SDimitry Andric return err.report(m_ec); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric auto from_st = from_fd.get_status(); 2690b57cec5SDimitry Andric StatT const& from_stat = from_fd.get_stat(); 2700b57cec5SDimitry Andric if (!is_regular_file(from_st)) { 2710b57cec5SDimitry Andric if (not m_ec) 2720b57cec5SDimitry Andric m_ec = make_error_code(errc::not_supported); 2730b57cec5SDimitry Andric return err.report(m_ec); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric const bool skip_existing = bool(copy_options::skip_existing & options); 2770b57cec5SDimitry Andric const bool update_existing = bool(copy_options::update_existing & options); 278cb14a3feSDimitry Andric const bool overwrite_existing = bool(copy_options::overwrite_existing & options); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric StatT to_stat_path; 2810b57cec5SDimitry Andric file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec); 2820b57cec5SDimitry Andric if (!status_known(to_st)) 2830b57cec5SDimitry Andric return err.report(m_ec); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric const bool to_exists = exists(to_st); 2860b57cec5SDimitry Andric if (to_exists && !is_regular_file(to_st)) 2870b57cec5SDimitry Andric return err.report(errc::not_supported); 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric if (to_exists && detail::stat_equivalent(from_stat, to_stat_path)) 2900b57cec5SDimitry Andric return err.report(errc::file_exists); 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric if (to_exists && skip_existing) 2930b57cec5SDimitry Andric return false; 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric bool ShouldCopy = [&]() { 2960b57cec5SDimitry Andric if (to_exists && update_existing) { 2970b57cec5SDimitry Andric auto from_time = detail::extract_mtime(from_stat); 2980b57cec5SDimitry Andric auto to_time = detail::extract_mtime(to_stat_path); 2990b57cec5SDimitry Andric if (from_time.tv_sec < to_time.tv_sec) 3000b57cec5SDimitry Andric return false; 301cb14a3feSDimitry Andric if (from_time.tv_sec == to_time.tv_sec && from_time.tv_nsec <= to_time.tv_nsec) 3020b57cec5SDimitry Andric return false; 3030b57cec5SDimitry Andric return true; 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric if (!to_exists || overwrite_existing) 3060b57cec5SDimitry Andric return true; 3070b57cec5SDimitry Andric return err.report(errc::file_exists); 3080b57cec5SDimitry Andric }(); 3090b57cec5SDimitry Andric if (!ShouldCopy) 3100b57cec5SDimitry Andric return false; 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric // Don't truncate right away. We may not be opening the file we originally 3130b57cec5SDimitry Andric // looked at; we'll check this later. 314fe6060f1SDimitry Andric int to_open_flags = O_WRONLY | O_BINARY; 3150b57cec5SDimitry Andric if (!to_exists) 3160b57cec5SDimitry Andric to_open_flags |= O_CREAT; 317cb14a3feSDimitry Andric FileDescriptor to_fd = FileDescriptor::create_with_status(&to, m_ec, to_open_flags, from_stat.st_mode); 3180b57cec5SDimitry Andric if (m_ec) 3190b57cec5SDimitry Andric return err.report(m_ec); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric if (to_exists) { 3220b57cec5SDimitry Andric // Check that the file we initially stat'ed is equivalent to the one 3230b57cec5SDimitry Andric // we opened. 3240b57cec5SDimitry Andric // FIXME: report this better. 3250b57cec5SDimitry Andric if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat())) 3260b57cec5SDimitry Andric return err.report(errc::bad_file_descriptor); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric // Set the permissions and truncate the file we opened. 3290b57cec5SDimitry Andric if (detail::posix_fchmod(to_fd, from_stat, m_ec)) 3300b57cec5SDimitry Andric return err.report(m_ec); 3310b57cec5SDimitry Andric if (detail::posix_ftruncate(to_fd, 0, m_ec)) 3320b57cec5SDimitry Andric return err.report(m_ec); 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 33506c3fb27SDimitry Andric if (!detail::copy_file_impl(from_fd, to_fd, m_ec)) { 3360b57cec5SDimitry Andric // FIXME: Remove the dest file if we failed, and it didn't exist previously. 3370b57cec5SDimitry Andric return err.report(m_ec); 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric return true; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 343cb14a3feSDimitry Andric void __copy_symlink(const path& existing_symlink, const path& new_symlink, error_code* ec) { 3440b57cec5SDimitry Andric const path real_path(__read_symlink(existing_symlink, ec)); 3450b57cec5SDimitry Andric if (ec && *ec) { 3460b57cec5SDimitry Andric return; 3470b57cec5SDimitry Andric } 348fe6060f1SDimitry Andric #if defined(_LIBCPP_WIN32API) 349fe6060f1SDimitry Andric error_code local_ec; 350fe6060f1SDimitry Andric if (is_directory(real_path, local_ec)) 351fe6060f1SDimitry Andric __create_directory_symlink(real_path, new_symlink, ec); 352fe6060f1SDimitry Andric else 353fe6060f1SDimitry Andric #endif 3540b57cec5SDimitry Andric __create_symlink(real_path, new_symlink, ec); 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric bool __create_directories(const path& p, error_code* ec) { 3580b57cec5SDimitry Andric ErrorHandler<bool> err("create_directories", ec, &p); 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric error_code m_ec; 3610b57cec5SDimitry Andric auto const st = detail::posix_stat(p, &m_ec); 3620b57cec5SDimitry Andric if (!status_known(st)) 3630b57cec5SDimitry Andric return err.report(m_ec); 3640b57cec5SDimitry Andric else if (is_directory(st)) 3650b57cec5SDimitry Andric return false; 3660b57cec5SDimitry Andric else if (exists(st)) 3670b57cec5SDimitry Andric return err.report(errc::file_exists); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric const path parent = p.parent_path(); 3700b57cec5SDimitry Andric if (!parent.empty()) { 3710b57cec5SDimitry Andric const file_status parent_st = status(parent, m_ec); 3720b57cec5SDimitry Andric if (not status_known(parent_st)) 3730b57cec5SDimitry Andric return err.report(m_ec); 3740b57cec5SDimitry Andric if (not exists(parent_st)) { 375fe6060f1SDimitry Andric if (parent == p) 376fe6060f1SDimitry Andric return err.report(errc::invalid_argument); 3770b57cec5SDimitry Andric __create_directories(parent, ec); 3780b57cec5SDimitry Andric if (ec && *ec) { 3790b57cec5SDimitry Andric return false; 3800b57cec5SDimitry Andric } 381fe6060f1SDimitry Andric } else if (not is_directory(parent_st)) 382fe6060f1SDimitry Andric return err.report(errc::not_a_directory); 3830b57cec5SDimitry Andric } 384fe6060f1SDimitry Andric bool ret = __create_directory(p, &m_ec); 385fe6060f1SDimitry Andric if (m_ec) 386fe6060f1SDimitry Andric return err.report(m_ec); 387fe6060f1SDimitry Andric return ret; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric bool __create_directory(const path& p, error_code* ec) { 3910b57cec5SDimitry Andric ErrorHandler<bool> err("create_directory", ec, &p); 3920b57cec5SDimitry Andric 393fe6060f1SDimitry Andric if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0) 3940b57cec5SDimitry Andric return true; 395e8d8bef9SDimitry Andric 396fe6060f1SDimitry Andric if (errno != EEXIST) 397fe6060f1SDimitry Andric return err.report(capture_errno()); 398e8d8bef9SDimitry Andric error_code mec = capture_errno(); 399e8d8bef9SDimitry Andric error_code ignored_ec; 400e8d8bef9SDimitry Andric const file_status st = status(p, ignored_ec); 401fe6060f1SDimitry Andric if (!is_directory(st)) 402fe6060f1SDimitry Andric return err.report(mec); 4030b57cec5SDimitry Andric return false; 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric bool __create_directory(path const& p, path const& attributes, error_code* ec) { 4070b57cec5SDimitry Andric ErrorHandler<bool> err("create_directory", ec, &p, &attributes); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric StatT attr_stat; 4100b57cec5SDimitry Andric error_code mec; 411fe6060f1SDimitry Andric file_status st = detail::posix_stat(attributes, attr_stat, &mec); 4120b57cec5SDimitry Andric if (!status_known(st)) 4130b57cec5SDimitry Andric return err.report(mec); 4140b57cec5SDimitry Andric if (!is_directory(st)) 415cb14a3feSDimitry Andric return err.report(errc::not_a_directory, "the specified attribute path is invalid"); 4160b57cec5SDimitry Andric 417fe6060f1SDimitry Andric if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0) 4180b57cec5SDimitry Andric return true; 419e8d8bef9SDimitry Andric 420fe6060f1SDimitry Andric if (errno != EEXIST) 421fe6060f1SDimitry Andric return err.report(capture_errno()); 422fe6060f1SDimitry Andric 423fe6060f1SDimitry Andric mec = capture_errno(); 424e8d8bef9SDimitry Andric error_code ignored_ec; 425fe6060f1SDimitry Andric st = status(p, ignored_ec); 426fe6060f1SDimitry Andric if (!is_directory(st)) 427fe6060f1SDimitry Andric return err.report(mec); 4280b57cec5SDimitry Andric return false; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 431cb14a3feSDimitry Andric void __create_directory_symlink(path const& from, path const& to, error_code* ec) { 4320b57cec5SDimitry Andric ErrorHandler<void> err("create_directory_symlink", ec, &from, &to); 433fe6060f1SDimitry Andric if (detail::symlink_dir(from.c_str(), to.c_str()) == -1) 4340b57cec5SDimitry Andric return err.report(capture_errno()); 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric void __create_hard_link(const path& from, const path& to, error_code* ec) { 4380b57cec5SDimitry Andric ErrorHandler<void> err("create_hard_link", ec, &from, &to); 439fe6060f1SDimitry Andric if (detail::link(from.c_str(), to.c_str()) == -1) 4400b57cec5SDimitry Andric return err.report(capture_errno()); 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric void __create_symlink(path const& from, path const& to, error_code* ec) { 4440b57cec5SDimitry Andric ErrorHandler<void> err("create_symlink", ec, &from, &to); 445fe6060f1SDimitry Andric if (detail::symlink_file(from.c_str(), to.c_str()) == -1) 4460b57cec5SDimitry Andric return err.report(capture_errno()); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric path __current_path(error_code* ec) { 4500b57cec5SDimitry Andric ErrorHandler<path> err("current_path", ec); 4510b57cec5SDimitry Andric 452fe6060f1SDimitry Andric #if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__) 453fe6060f1SDimitry Andric // Common extension outside of POSIX getcwd() spec, without needing to 454fe6060f1SDimitry Andric // preallocate a buffer. Also supported by a number of other POSIX libcs. 455fe6060f1SDimitry Andric int size = 0; 456fe6060f1SDimitry Andric path::value_type* ptr = nullptr; 457fe6060f1SDimitry Andric typedef decltype(&::free) Deleter; 458fe6060f1SDimitry Andric Deleter deleter = &::free; 459fe6060f1SDimitry Andric #else 4607a6dacacSDimitry Andric errno = 0; // Note: POSIX mandates that modifying `errno` is thread-safe. 4610b57cec5SDimitry Andric auto size = ::pathconf(".", _PC_PATH_MAX); 4627a6dacacSDimitry Andric if (size == -1) { 4637a6dacacSDimitry Andric if (errno != 0) { 4647a6dacacSDimitry Andric return err.report(capture_errno(), "call to pathconf failed"); 4657a6dacacSDimitry Andric 4667a6dacacSDimitry Andric // `pathconf` returns `-1` without an error to indicate no limit. 4677a6dacacSDimitry Andric } else { 4687a6dacacSDimitry Andric # if defined(__MVS__) && !defined(PATH_MAX) 4697a6dacacSDimitry Andric size = _XOPEN_PATH_MAX + 1; 4707a6dacacSDimitry Andric # else 4717a6dacacSDimitry Andric size = PATH_MAX + 1; 4727a6dacacSDimitry Andric # endif 4737a6dacacSDimitry Andric } 4747a6dacacSDimitry Andric } 4750b57cec5SDimitry Andric 476fe6060f1SDimitry Andric auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]); 477fe6060f1SDimitry Andric path::value_type* ptr = buff.get(); 478fe6060f1SDimitry Andric 479fe6060f1SDimitry Andric // Preallocated buffer, don't free the buffer in the second unique_ptr 480fe6060f1SDimitry Andric // below. 481cb14a3feSDimitry Andric struct Deleter { 482cb14a3feSDimitry Andric void operator()(void*) const {} 483cb14a3feSDimitry Andric }; 484fe6060f1SDimitry Andric Deleter deleter; 485fe6060f1SDimitry Andric #endif 486fe6060f1SDimitry Andric 487cb14a3feSDimitry Andric unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter); 488fe6060f1SDimitry Andric if (hold.get() == nullptr) 4890b57cec5SDimitry Andric return err.report(capture_errno(), "call to getcwd failed"); 4900b57cec5SDimitry Andric 491fe6060f1SDimitry Andric return {hold.get()}; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric void __current_path(const path& p, error_code* ec) { 4950b57cec5SDimitry Andric ErrorHandler<void> err("current_path", ec, &p); 496fe6060f1SDimitry Andric if (detail::chdir(p.c_str()) == -1) 4970b57cec5SDimitry Andric err.report(capture_errno()); 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric bool __equivalent(const path& p1, const path& p2, error_code* ec) { 5010b57cec5SDimitry Andric ErrorHandler<bool> err("equivalent", ec, &p1, &p2); 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric error_code ec1, ec2; 5040b57cec5SDimitry Andric StatT st1 = {}, st2 = {}; 5050b57cec5SDimitry Andric auto s1 = detail::posix_stat(p1.native(), st1, &ec1); 5060b57cec5SDimitry Andric if (!exists(s1)) 5070b57cec5SDimitry Andric return err.report(errc::not_supported); 5080b57cec5SDimitry Andric auto s2 = detail::posix_stat(p2.native(), st2, &ec2); 5090b57cec5SDimitry Andric if (!exists(s2)) 5100b57cec5SDimitry Andric return err.report(errc::not_supported); 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric return detail::stat_equivalent(st1, st2); 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric uintmax_t __file_size(const path& p, error_code* ec) { 5160b57cec5SDimitry Andric ErrorHandler<uintmax_t> err("file_size", ec, &p); 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric error_code m_ec; 5190b57cec5SDimitry Andric StatT st; 5200b57cec5SDimitry Andric file_status fst = detail::posix_stat(p, st, &m_ec); 5210b57cec5SDimitry Andric if (!exists(fst) || !is_regular_file(fst)) { 522cb14a3feSDimitry Andric errc error_kind = is_directory(fst) ? errc::is_a_directory : errc::not_supported; 5230b57cec5SDimitry Andric if (!m_ec) 5240b57cec5SDimitry Andric m_ec = make_error_code(error_kind); 5250b57cec5SDimitry Andric return err.report(m_ec); 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric // is_regular_file(p) == true 5280b57cec5SDimitry Andric return static_cast<uintmax_t>(st.st_size); 5290b57cec5SDimitry Andric } 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric uintmax_t __hard_link_count(const path& p, error_code* ec) { 5320b57cec5SDimitry Andric ErrorHandler<uintmax_t> err("hard_link_count", ec, &p); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric error_code m_ec; 5350b57cec5SDimitry Andric StatT st; 5360b57cec5SDimitry Andric detail::posix_stat(p, st, &m_ec); 5370b57cec5SDimitry Andric if (m_ec) 5380b57cec5SDimitry Andric return err.report(m_ec); 5390b57cec5SDimitry Andric return static_cast<uintmax_t>(st.st_nlink); 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric bool __fs_is_empty(const path& p, error_code* ec) { 5430b57cec5SDimitry Andric ErrorHandler<bool> err("is_empty", ec, &p); 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric error_code m_ec; 5460b57cec5SDimitry Andric StatT pst; 5470b57cec5SDimitry Andric auto st = detail::posix_stat(p, pst, &m_ec); 5480b57cec5SDimitry Andric if (m_ec) 5490b57cec5SDimitry Andric return err.report(m_ec); 5500b57cec5SDimitry Andric else if (!is_directory(st) && !is_regular_file(st)) 5510b57cec5SDimitry Andric return err.report(errc::not_supported); 5520b57cec5SDimitry Andric else if (is_directory(st)) { 5530b57cec5SDimitry Andric auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p); 5540b57cec5SDimitry Andric if (ec && *ec) 5550b57cec5SDimitry Andric return false; 5560b57cec5SDimitry Andric return it == directory_iterator{}; 5570b57cec5SDimitry Andric } else if (is_regular_file(st)) 5580b57cec5SDimitry Andric return static_cast<uintmax_t>(pst.st_size) == 0; 5590b57cec5SDimitry Andric 56081ad6265SDimitry Andric __libcpp_unreachable(); 5610b57cec5SDimitry Andric } 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric file_time_type __last_write_time(const path& p, error_code* ec) { 5640b57cec5SDimitry Andric using namespace chrono; 5650b57cec5SDimitry Andric ErrorHandler<file_time_type> err("last_write_time", ec, &p); 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric error_code m_ec; 5680b57cec5SDimitry Andric StatT st; 5690b57cec5SDimitry Andric detail::posix_stat(p, st, &m_ec); 5700b57cec5SDimitry Andric if (m_ec) 5710b57cec5SDimitry Andric return err.report(m_ec); 57206c3fb27SDimitry Andric return detail::__extract_last_write_time(p, st, ec); 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { 5760b57cec5SDimitry Andric using detail::fs_time; 5770b57cec5SDimitry Andric ErrorHandler<void> err("last_write_time", ec, &p); 5780b57cec5SDimitry Andric 579fe6060f1SDimitry Andric #if defined(_LIBCPP_WIN32API) 580fe6060f1SDimitry Andric TimeSpec ts; 581fe6060f1SDimitry Andric if (!fs_time::convert_to_timespec(ts, new_time)) 582fe6060f1SDimitry Andric return err.report(errc::value_too_large); 583fe6060f1SDimitry Andric detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0); 584fe6060f1SDimitry Andric if (!h) 585fe6060f1SDimitry Andric return err.report(detail::make_windows_error(GetLastError())); 586fe6060f1SDimitry Andric FILETIME last_write = timespec_to_filetime(ts); 587fe6060f1SDimitry Andric if (!SetFileTime(h, nullptr, nullptr, &last_write)) 588fe6060f1SDimitry Andric return err.report(detail::make_windows_error(GetLastError())); 589fe6060f1SDimitry Andric #else 5900b57cec5SDimitry Andric error_code m_ec; 5910b57cec5SDimitry Andric array<TimeSpec, 2> tbuf; 5920b57cec5SDimitry Andric # if !defined(_LIBCPP_USE_UTIMENSAT) 5930b57cec5SDimitry Andric // This implementation has a race condition between determining the 5940b57cec5SDimitry Andric // last access time and attempting to set it to the same value using 5950b57cec5SDimitry Andric // ::utimes 5960b57cec5SDimitry Andric StatT st; 5970b57cec5SDimitry Andric file_status fst = detail::posix_stat(p, st, &m_ec); 5980b57cec5SDimitry Andric if (m_ec) 5990b57cec5SDimitry Andric return err.report(m_ec); 6000b57cec5SDimitry Andric tbuf[0] = detail::extract_atime(st); 6010b57cec5SDimitry Andric # else 6020b57cec5SDimitry Andric tbuf[0].tv_sec = 0; 6030b57cec5SDimitry Andric tbuf[0].tv_nsec = UTIME_OMIT; 6040b57cec5SDimitry Andric # endif 6050b57cec5SDimitry Andric if (!fs_time::convert_to_timespec(tbuf[1], new_time)) 6060b57cec5SDimitry Andric return err.report(errc::value_too_large); 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric detail::set_file_times(p, tbuf, m_ec); 6090b57cec5SDimitry Andric if (m_ec) 6100b57cec5SDimitry Andric return err.report(m_ec); 611fe6060f1SDimitry Andric #endif 6120b57cec5SDimitry Andric } 6130b57cec5SDimitry Andric 614cb14a3feSDimitry Andric void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) { 6150b57cec5SDimitry Andric ErrorHandler<void> err("permissions", ec, &p); 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric auto has_opt = [&](perm_options o) { return bool(o & opts); }; 6180b57cec5SDimitry Andric const bool resolve_symlinks = !has_opt(perm_options::nofollow); 6190b57cec5SDimitry Andric const bool add_perms = has_opt(perm_options::add); 6200b57cec5SDimitry Andric const bool remove_perms = has_opt(perm_options::remove); 6217a6dacacSDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 6220b57cec5SDimitry Andric (add_perms + remove_perms + has_opt(perm_options::replace)) == 1, 6237a6dacacSDimitry Andric "One and only one of the perm_options constants 'replace', 'add', or 'remove' must be present in opts"); 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric bool set_sym_perms = false; 6260b57cec5SDimitry Andric prms &= perms::mask; 6270b57cec5SDimitry Andric if (!resolve_symlinks || (add_perms || remove_perms)) { 6280b57cec5SDimitry Andric error_code m_ec; 629cb14a3feSDimitry Andric file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) : detail::posix_lstat(p, &m_ec); 6300b57cec5SDimitry Andric set_sym_perms = is_symlink(st); 6310b57cec5SDimitry Andric if (m_ec) 6320b57cec5SDimitry Andric return err.report(m_ec); 6337a6dacacSDimitry Andric // TODO(hardening): double-check this assertion -- it might be a valid (if rare) case when the permissions are 6347a6dacacSDimitry Andric // unknown. 6357a6dacacSDimitry Andric _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(st.permissions() != perms::unknown, "Permissions unexpectedly unknown"); 6360b57cec5SDimitry Andric if (add_perms) 6370b57cec5SDimitry Andric prms |= st.permissions(); 6380b57cec5SDimitry Andric else if (remove_perms) 6390b57cec5SDimitry Andric prms = st.permissions() & ~prms; 6400b57cec5SDimitry Andric } 641fe6060f1SDimitry Andric const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) 6440b57cec5SDimitry Andric const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; 645fe6060f1SDimitry Andric if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { 6460b57cec5SDimitry Andric return err.report(capture_errno()); 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric #else 6490b57cec5SDimitry Andric if (set_sym_perms) 6500b57cec5SDimitry Andric return err.report(errc::operation_not_supported); 6510b57cec5SDimitry Andric if (::chmod(p.c_str(), real_perms) == -1) { 6520b57cec5SDimitry Andric return err.report(capture_errno()); 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric #endif 6550b57cec5SDimitry Andric } 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric path __read_symlink(const path& p, error_code* ec) { 6580b57cec5SDimitry Andric ErrorHandler<path> err("read_symlink", ec, &p); 6590b57cec5SDimitry Andric 660fe6060f1SDimitry Andric #if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE) 661cb14a3feSDimitry Andric struct NullDeleter { 662cb14a3feSDimitry Andric void operator()(void*) const {} 663cb14a3feSDimitry Andric }; 664fe6060f1SDimitry Andric # ifdef MAX_SYMLINK_SIZE 665fe6060f1SDimitry Andric const size_t size = MAX_SYMLINK_SIZE + 1; 666fe6060f1SDimitry Andric # else 6670b57cec5SDimitry Andric const size_t size = PATH_MAX + 1; 668fe6060f1SDimitry Andric # endif 669fe6060f1SDimitry Andric path::value_type stack_buff[size]; 670fe6060f1SDimitry Andric auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff); 6710b57cec5SDimitry Andric #else 6720b57cec5SDimitry Andric StatT sb; 673fe6060f1SDimitry Andric if (detail::lstat(p.c_str(), &sb) == -1) { 6740b57cec5SDimitry Andric return err.report(capture_errno()); 6750b57cec5SDimitry Andric } 6760b57cec5SDimitry Andric const size_t size = sb.st_size + 1; 677fe6060f1SDimitry Andric auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]); 6780b57cec5SDimitry Andric #endif 679fe6060f1SDimitry Andric detail::SSizeT ret; 680fe6060f1SDimitry Andric if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) 6810b57cec5SDimitry Andric return err.report(capture_errno()); 6827a6dacacSDimitry Andric // Note that `ret` returning `0` would work, resulting in a valid empty string being returned. 6830b57cec5SDimitry Andric if (static_cast<size_t>(ret) >= size) 6840b57cec5SDimitry Andric return err.report(errc::value_too_large); 6850b57cec5SDimitry Andric buff[ret] = 0; 6860b57cec5SDimitry Andric return {buff.get()}; 6870b57cec5SDimitry Andric } 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric bool __remove(const path& p, error_code* ec) { 6900b57cec5SDimitry Andric ErrorHandler<bool> err("remove", ec, &p); 691fe6060f1SDimitry Andric if (detail::remove(p.c_str()) == -1) { 6920b57cec5SDimitry Andric if (errno != ENOENT) 6930b57cec5SDimitry Andric err.report(capture_errno()); 6940b57cec5SDimitry Andric return false; 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric return true; 6970b57cec5SDimitry Andric } 6980b57cec5SDimitry Andric 6991fd87a68SDimitry Andric // We currently have two implementations of `__remove_all`. The first one is general and 7001fd87a68SDimitry Andric // used on platforms where we don't have access to the `openat()` family of POSIX functions. 7011fd87a68SDimitry Andric // That implementation uses `directory_iterator`, however it is vulnerable to some race 7021fd87a68SDimitry Andric // conditions, see https://reviews.llvm.org/D118134 for details. 7031fd87a68SDimitry Andric // 7041fd87a68SDimitry Andric // The second implementation is used on platforms where `openat()` & friends are available, 7051fd87a68SDimitry Andric // and it threads file descriptors through recursive calls to avoid such race conditions. 706bdd1243dSDimitry Andric #if defined(_LIBCPP_WIN32API) || defined(__MVS__) 7071fd87a68SDimitry Andric # define REMOVE_ALL_USE_DIRECTORY_ITERATOR 7081fd87a68SDimitry Andric #endif 7091fd87a68SDimitry Andric 7101fd87a68SDimitry Andric #if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR) 7111fd87a68SDimitry Andric 7120b57cec5SDimitry Andric namespace { 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric uintmax_t remove_all_impl(path const& p, error_code& ec) { 7150b57cec5SDimitry Andric const auto npos = static_cast<uintmax_t>(-1); 7160b57cec5SDimitry Andric const file_status st = __symlink_status(p, &ec); 7170b57cec5SDimitry Andric if (ec) 7180b57cec5SDimitry Andric return npos; 7190b57cec5SDimitry Andric uintmax_t count = 1; 7200b57cec5SDimitry Andric if (is_directory(st)) { 721cb14a3feSDimitry Andric for (directory_iterator it(p, ec); !ec && it != directory_iterator(); it.increment(ec)) { 7220b57cec5SDimitry Andric auto other_count = remove_all_impl(it->path(), ec); 7230b57cec5SDimitry Andric if (ec) 7240b57cec5SDimitry Andric return npos; 7250b57cec5SDimitry Andric count += other_count; 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric if (ec) 7280b57cec5SDimitry Andric return npos; 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric if (!__remove(p, &ec)) 7310b57cec5SDimitry Andric return npos; 7320b57cec5SDimitry Andric return count; 7330b57cec5SDimitry Andric } 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric } // end namespace 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric uintmax_t __remove_all(const path& p, error_code* ec) { 7380b57cec5SDimitry Andric ErrorHandler<uintmax_t> err("remove_all", ec, &p); 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric error_code mec; 7410b57cec5SDimitry Andric auto count = remove_all_impl(p, mec); 7420b57cec5SDimitry Andric if (mec) { 7430b57cec5SDimitry Andric if (mec == errc::no_such_file_or_directory) 7440b57cec5SDimitry Andric return 0; 7450b57cec5SDimitry Andric return err.report(mec); 7460b57cec5SDimitry Andric } 7470b57cec5SDimitry Andric return count; 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric 7501fd87a68SDimitry Andric #else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR 7511fd87a68SDimitry Andric 7521fd87a68SDimitry Andric namespace { 7531fd87a68SDimitry Andric 7541fd87a68SDimitry Andric template <class Cleanup> 7551fd87a68SDimitry Andric struct scope_exit { 756cb14a3feSDimitry Andric explicit scope_exit(Cleanup const& cleanup) : cleanup_(cleanup) {} 7571fd87a68SDimitry Andric 7581fd87a68SDimitry Andric ~scope_exit() { cleanup_(); } 7591fd87a68SDimitry Andric 7601fd87a68SDimitry Andric private: 7611fd87a68SDimitry Andric Cleanup cleanup_; 7621fd87a68SDimitry Andric }; 763bdd1243dSDimitry Andric _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scope_exit); 7641fd87a68SDimitry Andric 7651fd87a68SDimitry Andric uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) { 7661fd87a68SDimitry Andric // First, try to open the path as a directory. 7671fd87a68SDimitry Andric const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW; 7681fd87a68SDimitry Andric int fd = ::openat(parent_directory, p.c_str(), options); 7691fd87a68SDimitry Andric if (fd != -1) { 7701fd87a68SDimitry Andric // If that worked, iterate over the contents of the directory and 7711fd87a68SDimitry Andric // remove everything in it, recursively. 7721fd87a68SDimitry Andric DIR* stream = ::fdopendir(fd); 7731fd87a68SDimitry Andric if (stream == nullptr) { 774d781ede6SDimitry Andric ::close(fd); 7751fd87a68SDimitry Andric ec = detail::capture_errno(); 7761fd87a68SDimitry Andric return 0; 7771fd87a68SDimitry Andric } 778d781ede6SDimitry Andric // Note: `::closedir` will also close the associated file descriptor, so 779d781ede6SDimitry Andric // there should be no call to `close(fd)`. 7801fd87a68SDimitry Andric scope_exit close_stream([=] { ::closedir(stream); }); 7811fd87a68SDimitry Andric 7821fd87a68SDimitry Andric uintmax_t count = 0; 7831fd87a68SDimitry Andric while (true) { 7841fd87a68SDimitry Andric auto [str, type] = detail::posix_readdir(stream, ec); 7851fd87a68SDimitry Andric static_assert(std::is_same_v<decltype(str), std::string_view>); 7861fd87a68SDimitry Andric if (str == "." || str == "..") { 7871fd87a68SDimitry Andric continue; 7881fd87a68SDimitry Andric } else if (ec || str.empty()) { 7891fd87a68SDimitry Andric break; // we're done iterating through the directory 7901fd87a68SDimitry Andric } else { 7911fd87a68SDimitry Andric count += remove_all_impl(fd, str, ec); 7921fd87a68SDimitry Andric } 7931fd87a68SDimitry Andric } 7941fd87a68SDimitry Andric 7951fd87a68SDimitry Andric // Then, remove the now-empty directory itself. 7961fd87a68SDimitry Andric if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) { 7971fd87a68SDimitry Andric ec = detail::capture_errno(); 7981fd87a68SDimitry Andric return count; 7991fd87a68SDimitry Andric } 8001fd87a68SDimitry Andric 8011fd87a68SDimitry Andric return count + 1; // the contents of the directory + the directory itself 8021fd87a68SDimitry Andric } 8031fd87a68SDimitry Andric 8041fd87a68SDimitry Andric ec = detail::capture_errno(); 8051fd87a68SDimitry Andric 8061fd87a68SDimitry Andric // If we failed to open `p` because it didn't exist, it's not an 8071fd87a68SDimitry Andric // error -- it might have moved or have been deleted already. 8081fd87a68SDimitry Andric if (ec == errc::no_such_file_or_directory) { 8091fd87a68SDimitry Andric ec.clear(); 8101fd87a68SDimitry Andric return 0; 8111fd87a68SDimitry Andric } 8121fd87a68SDimitry Andric 8131fd87a68SDimitry Andric // If opening `p` failed because it wasn't a directory, remove it as 8141fd87a68SDimitry Andric // a normal file instead. Note that `openat()` can return either ENOTDIR 815ee14a972SDimitry Andric // or ELOOP depending on the exact reason of the failure. On FreeBSD it 816ee14a972SDimitry Andric // may return EMLINK instead of ELOOP, contradicting POSIX. 817ee14a972SDimitry Andric if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) { 8181fd87a68SDimitry Andric ec.clear(); 8191fd87a68SDimitry Andric if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) { 8201fd87a68SDimitry Andric ec = detail::capture_errno(); 8211fd87a68SDimitry Andric return 0; 8221fd87a68SDimitry Andric } 8231fd87a68SDimitry Andric return 1; 8241fd87a68SDimitry Andric } 8251fd87a68SDimitry Andric 8261fd87a68SDimitry Andric // Otherwise, it's a real error -- we don't remove anything. 8271fd87a68SDimitry Andric return 0; 8281fd87a68SDimitry Andric } 8291fd87a68SDimitry Andric 8301fd87a68SDimitry Andric } // end namespace 8311fd87a68SDimitry Andric 8321fd87a68SDimitry Andric uintmax_t __remove_all(const path& p, error_code* ec) { 8331fd87a68SDimitry Andric ErrorHandler<uintmax_t> err("remove_all", ec, &p); 8341fd87a68SDimitry Andric error_code mec; 8351fd87a68SDimitry Andric uintmax_t count = remove_all_impl(AT_FDCWD, p, mec); 8361fd87a68SDimitry Andric if (mec) 8371fd87a68SDimitry Andric return err.report(mec); 8381fd87a68SDimitry Andric return count; 8391fd87a68SDimitry Andric } 8401fd87a68SDimitry Andric 8411fd87a68SDimitry Andric #endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR 8421fd87a68SDimitry Andric 8430b57cec5SDimitry Andric void __rename(const path& from, const path& to, error_code* ec) { 8440b57cec5SDimitry Andric ErrorHandler<void> err("rename", ec, &from, &to); 845fe6060f1SDimitry Andric if (detail::rename(from.c_str(), to.c_str()) == -1) 8460b57cec5SDimitry Andric err.report(capture_errno()); 8470b57cec5SDimitry Andric } 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric void __resize_file(const path& p, uintmax_t size, error_code* ec) { 8500b57cec5SDimitry Andric ErrorHandler<void> err("resize_file", ec, &p); 851fe6060f1SDimitry Andric if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1) 8520b57cec5SDimitry Andric return err.report(capture_errno()); 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric space_info __space(const path& p, error_code* ec) { 8560b57cec5SDimitry Andric ErrorHandler<void> err("space", ec, &p); 8570b57cec5SDimitry Andric space_info si; 858fe6060f1SDimitry Andric detail::StatVFS m_svfs = {}; 859fe6060f1SDimitry Andric if (detail::statvfs(p.c_str(), &m_svfs) == -1) { 8600b57cec5SDimitry Andric err.report(capture_errno()); 8610b57cec5SDimitry Andric si.capacity = si.free = si.available = static_cast<uintmax_t>(-1); 8620b57cec5SDimitry Andric return si; 8630b57cec5SDimitry Andric } 8640b57cec5SDimitry Andric // Multiply with overflow checking. 8650b57cec5SDimitry Andric auto do_mult = [&](uintmax_t& out, uintmax_t other) { 8660b57cec5SDimitry Andric out = other * m_svfs.f_frsize; 8670b57cec5SDimitry Andric if (other == 0 || out / other != m_svfs.f_frsize) 8680b57cec5SDimitry Andric out = static_cast<uintmax_t>(-1); 8690b57cec5SDimitry Andric }; 8700b57cec5SDimitry Andric do_mult(si.capacity, m_svfs.f_blocks); 8710b57cec5SDimitry Andric do_mult(si.free, m_svfs.f_bfree); 8720b57cec5SDimitry Andric do_mult(si.available, m_svfs.f_bavail); 8730b57cec5SDimitry Andric return si; 8740b57cec5SDimitry Andric } 8750b57cec5SDimitry Andric 876cb14a3feSDimitry Andric file_status __status(const path& p, error_code* ec) { return detail::posix_stat(p, ec); } 8770b57cec5SDimitry Andric 878cb14a3feSDimitry Andric file_status __symlink_status(const path& p, error_code* ec) { return detail::posix_lstat(p, ec); } 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric path __temp_directory_path(error_code* ec) { 8810b57cec5SDimitry Andric ErrorHandler<path> err("temp_directory_path", ec); 8820b57cec5SDimitry Andric 883fe6060f1SDimitry Andric #if defined(_LIBCPP_WIN32API) 884fe6060f1SDimitry Andric wchar_t buf[MAX_PATH]; 885fe6060f1SDimitry Andric DWORD retval = GetTempPathW(MAX_PATH, buf); 886fe6060f1SDimitry Andric if (!retval) 887fe6060f1SDimitry Andric return err.report(detail::make_windows_error(GetLastError())); 888fe6060f1SDimitry Andric if (retval > MAX_PATH) 889fe6060f1SDimitry Andric return err.report(errc::filename_too_long); 890fe6060f1SDimitry Andric // GetTempPathW returns a path with a trailing slash, which we 891fe6060f1SDimitry Andric // shouldn't include for consistency. 892fe6060f1SDimitry Andric if (buf[retval - 1] == L'\\') 893fe6060f1SDimitry Andric buf[retval - 1] = L'\0'; 894fe6060f1SDimitry Andric path p(buf); 895fe6060f1SDimitry Andric #else 8960b57cec5SDimitry Andric const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; 8970b57cec5SDimitry Andric const char* ret = nullptr; 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric for (auto& ep : env_paths) 9000b57cec5SDimitry Andric if ((ret = getenv(ep))) 9010b57cec5SDimitry Andric break; 90206c3fb27SDimitry Andric if (ret == nullptr) { 90306c3fb27SDimitry Andric # if defined(__ANDROID__) 90406c3fb27SDimitry Andric ret = "/data/local/tmp"; 90506c3fb27SDimitry Andric # else 9060b57cec5SDimitry Andric ret = "/tmp"; 90706c3fb27SDimitry Andric # endif 90806c3fb27SDimitry Andric } 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric path p(ret); 911fe6060f1SDimitry Andric #endif 9120b57cec5SDimitry Andric error_code m_ec; 9130b57cec5SDimitry Andric file_status st = detail::posix_stat(p, &m_ec); 9140b57cec5SDimitry Andric if (!status_known(st)) 915fe6060f1SDimitry Andric return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str()); 9160b57cec5SDimitry Andric 9170b57cec5SDimitry Andric if (!exists(st) || !is_directory(st)) 918cb14a3feSDimitry Andric return err.report(errc::not_a_directory, "path " PATH_CSTR_FMT " is not a directory", p.c_str()); 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric return p; 9210b57cec5SDimitry Andric } 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric path __weakly_canonical(const path& p, error_code* ec) { 9240b57cec5SDimitry Andric ErrorHandler<path> err("weakly_canonical", ec, &p); 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric if (p.empty()) 9270b57cec5SDimitry Andric return __canonical("", ec); 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric path result; 9300b57cec5SDimitry Andric path tmp; 9310b57cec5SDimitry Andric tmp.__reserve(p.native().size()); 9320b57cec5SDimitry Andric auto PP = PathParser::CreateEnd(p.native()); 9330b57cec5SDimitry Andric --PP; 9340b57cec5SDimitry Andric vector<string_view_t> DNEParts; 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric error_code m_ec; 937*0fca6ea1SDimitry Andric while (PP.State_ != PathParser::PS_BeforeBegin) { 938*0fca6ea1SDimitry Andric tmp.assign(createView(p.native().data(), &PP.RawEntry.back())); 9390b57cec5SDimitry Andric file_status st = __status(tmp, &m_ec); 9400b57cec5SDimitry Andric if (!status_known(st)) { 9410b57cec5SDimitry Andric return err.report(m_ec); 9420b57cec5SDimitry Andric } else if (exists(st)) { 943*0fca6ea1SDimitry Andric result = __canonical(tmp, &m_ec); 944*0fca6ea1SDimitry Andric if (m_ec) { 945*0fca6ea1SDimitry Andric return err.report(m_ec); 946*0fca6ea1SDimitry Andric } 9470b57cec5SDimitry Andric break; 9480b57cec5SDimitry Andric } 9490b57cec5SDimitry Andric DNEParts.push_back(*PP); 9500b57cec5SDimitry Andric --PP; 9510b57cec5SDimitry Andric } 952*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_BeforeBegin) { 953*0fca6ea1SDimitry Andric result = __canonical("", &m_ec); 954*0fca6ea1SDimitry Andric if (m_ec) { 955*0fca6ea1SDimitry Andric return err.report(m_ec); 956*0fca6ea1SDimitry Andric } 957*0fca6ea1SDimitry Andric } 9580b57cec5SDimitry Andric if (DNEParts.empty()) 9590b57cec5SDimitry Andric return result; 9600b57cec5SDimitry Andric for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It) 9610b57cec5SDimitry Andric result /= *It; 9620b57cec5SDimitry Andric return result.lexically_normal(); 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM 966