xref: /freebsd-src/contrib/llvm-project/libcxx/src/filesystem/operations.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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