1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===// 2998a5c88SEric Fiselier // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6998a5c88SEric Fiselier // 7998a5c88SEric Fiselier //===----------------------------------------------------------------------===// 8998a5c88SEric Fiselier 9f87aa19bSLouis Dionne #include <__assert> 10c7d3c844SLouis Dionne #include <__config> 112a8f9a5eSNikolas Klauser #include <__utility/unreachable.h> 12bbb0f2c7SArthur O'Dwyer #include <array> 13bbb0f2c7SArthur O'Dwyer #include <climits> 14bbb0f2c7SArthur O'Dwyer #include <cstdlib> 15bbb0f2c7SArthur O'Dwyer #include <filesystem> 16bbb0f2c7SArthur O'Dwyer #include <iterator> 17bbb0f2c7SArthur O'Dwyer #include <string_view> 18cb1c1563SJannik Glückert #include <system_error> 19bbb0f2c7SArthur O'Dwyer #include <type_traits> 20bbb0f2c7SArthur O'Dwyer #include <vector> 21998a5c88SEric Fiselier 22c7d3c844SLouis Dionne #include "error.h" 23c7d3c844SLouis Dionne #include "file_descriptor.h" 24c7d3c844SLouis Dionne #include "path_parser.h" 252ff8662bSMartin Storsjö #include "posix_compat.h" 26c7d3c844SLouis Dionne #include "time_utils.h" 272ff8662bSMartin Storsjö 28de698ae7SMartin Storsjö #if defined(_LIBCPP_WIN32API) 29de698ae7SMartin Storsjö # define WIN32_LEAN_AND_MEAN 30de698ae7SMartin Storsjö # define NOMINMAX 31de698ae7SMartin Storsjö # include <windows.h> 32de698ae7SMartin Storsjö #else 334f67a909SLouis Dionne # include <dirent.h> 34998a5c88SEric Fiselier # include <sys/stat.h> 35998a5c88SEric Fiselier # include <sys/statvfs.h> 36cb1c1563SJannik Glückert # include <sys/types.h> 374f67a909SLouis Dionne # include <unistd.h> 38de698ae7SMartin Storsjö #endif 39998a5c88SEric Fiselier #include <fcntl.h> /* values for fchmodat */ 409783f28cSLouis Dionne #include <time.h> 41998a5c88SEric Fiselier 42cda43e1bSYi Kong // since Linux 4.5 and FreeBSD 13, but the Linux libc wrapper is only provided by glibc >= 2.27 and musl 43cda43e1bSYi Kong #if defined(__linux__) 44cda43e1bSYi Kong # if defined(_LIBCPP_GLIBC_PREREQ) 45cda43e1bSYi Kong # if _LIBCPP_GLIBC_PREREQ(2, 27) 46cda43e1bSYi Kong # define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE 47cda43e1bSYi Kong # endif 48cda43e1bSYi Kong # elif _LIBCPP_HAS_MUSL_LIBC 49cda43e1bSYi Kong # define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE 50cda43e1bSYi Kong # endif 51cda43e1bSYi Kong #elif defined(__FreeBSD__) 52cb1c1563SJannik Glückert # define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE 53cb1c1563SJannik Glückert #endif 5417dcf85eSLouis Dionne #if __has_include(<sys/sendfile.h>) 55998a5c88SEric Fiselier # include <sys/sendfile.h> 5617dcf85eSLouis Dionne # define _LIBCPP_FILESYSTEM_USE_SENDFILE 57998a5c88SEric Fiselier #elif defined(__APPLE__) || __has_include(<copyfile.h>) 58998a5c88SEric Fiselier # include <copyfile.h> 5917dcf85eSLouis Dionne # define _LIBCPP_FILESYSTEM_USE_COPYFILE 6017dcf85eSLouis Dionne #else 6117dcf85eSLouis Dionne # define _LIBCPP_FILESYSTEM_USE_FSTREAM 62998a5c88SEric Fiselier #endif 63998a5c88SEric Fiselier 64cb1c1563SJannik Glückert // sendfile and copy_file_range need to fall back 65cb1c1563SJannik Glückert // to the fstream implementation for special files 66cb1c1563SJannik Glückert #if (defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) || defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) || \ 67cb1c1563SJannik Glückert defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)) && \ 68cb1c1563SJannik Glückert _LIBCPP_HAS_LOCALIZATION 69cb1c1563SJannik Glückert # include <fstream> 70cb1c1563SJannik Glückert # define _LIBCPP_FILESYSTEM_NEED_FSTREAM 71cb1c1563SJannik Glückert #endif 72cb1c1563SJannik Glückert 73a9b5fff5SMichał Górny #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) 74996e62eeSPetr Hosek # pragma comment(lib, "rt") 75996e62eeSPetr Hosek #endif 76996e62eeSPetr Hosek 77998a5c88SEric Fiselier _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 78998a5c88SEric Fiselier 79998a5c88SEric Fiselier using detail::capture_errno; 80998a5c88SEric Fiselier using detail::ErrorHandler; 81998a5c88SEric Fiselier using detail::StatT; 82998a5c88SEric Fiselier using detail::TimeSpec; 83998a5c88SEric Fiselier using parser::createView; 84998a5c88SEric Fiselier using parser::PathParser; 85998a5c88SEric Fiselier using parser::string_view_t; 86998a5c88SEric Fiselier 87998a5c88SEric Fiselier static path __do_absolute(const path& p, path* cwd, error_code* ec) { 88998a5c88SEric Fiselier if (ec) 89998a5c88SEric Fiselier ec->clear(); 90998a5c88SEric Fiselier if (p.is_absolute()) 91998a5c88SEric Fiselier return p; 92998a5c88SEric Fiselier *cwd = __current_path(ec); 93998a5c88SEric Fiselier if (ec && *ec) 94998a5c88SEric Fiselier return {}; 95998a5c88SEric Fiselier return (*cwd) / p; 96998a5c88SEric Fiselier } 97998a5c88SEric Fiselier 98998a5c88SEric Fiselier path __absolute(const path& p, error_code* ec) { 99998a5c88SEric Fiselier path cwd; 100998a5c88SEric Fiselier return __do_absolute(p, &cwd, ec); 101998a5c88SEric Fiselier } 102998a5c88SEric Fiselier 103998a5c88SEric Fiselier path __canonical(path const& orig_p, error_code* ec) { 104998a5c88SEric Fiselier path cwd; 105998a5c88SEric Fiselier ErrorHandler<path> err("canonical", ec, &orig_p, &cwd); 106998a5c88SEric Fiselier 107998a5c88SEric Fiselier path p = __do_absolute(orig_p, &cwd, ec); 10883d705adSMartin Storsjö #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API) 1099783f28cSLouis Dionne std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free); 1100e997efdSEric Fiselier if (hold.get() == nullptr) 111*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 1120e997efdSEric Fiselier return {hold.get()}; 1130e997efdSEric Fiselier #else 11492bb81aaSZbigniew Sarbinowski # if defined(__MVS__) && !defined(PATH_MAX) 11583d705adSMartin Storsjö path::value_type buff[_XOPEN_PATH_MAX + 1]; 11692bb81aaSZbigniew Sarbinowski # else 11783d705adSMartin Storsjö path::value_type buff[PATH_MAX + 1]; 11892bb81aaSZbigniew Sarbinowski # endif 11983d705adSMartin Storsjö path::value_type* ret; 12083d705adSMartin Storsjö if ((ret = detail::realpath(p.c_str(), buff)) == nullptr) 121*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 122998a5c88SEric Fiselier return {ret}; 1230e997efdSEric Fiselier #endif 124998a5c88SEric Fiselier } 125998a5c88SEric Fiselier 1269783f28cSLouis Dionne void __copy(const path& from, const path& to, copy_options options, error_code* ec) { 127998a5c88SEric Fiselier ErrorHandler<void> err("copy", ec, &from, &to); 128998a5c88SEric Fiselier 1299783f28cSLouis Dionne const bool sym_status = bool(options & (copy_options::create_symlinks | copy_options::skip_symlinks)); 130998a5c88SEric Fiselier 131998a5c88SEric Fiselier const bool sym_status2 = bool(options & copy_options::copy_symlinks); 132998a5c88SEric Fiselier 133998a5c88SEric Fiselier error_code m_ec1; 1347e5bc715SAfanasyev Ivan StatT f_st; 1359783f28cSLouis Dionne const file_status f = 1369783f28cSLouis Dionne sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1); 137998a5c88SEric Fiselier if (m_ec1) 138998a5c88SEric Fiselier return err.report(m_ec1); 139998a5c88SEric Fiselier 1407e5bc715SAfanasyev Ivan StatT t_st; 1419783f28cSLouis Dionne const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1); 142998a5c88SEric Fiselier 143998a5c88SEric Fiselier if (not status_known(t)) 144998a5c88SEric Fiselier return err.report(m_ec1); 145998a5c88SEric Fiselier 1469783f28cSLouis Dionne if (!exists(f) || is_other(f) || is_other(t) || (is_directory(f) && is_regular_file(t)) || 1477e5bc715SAfanasyev Ivan (exists(t) && detail::stat_equivalent(f_st, t_st))) { 148998a5c88SEric Fiselier return err.report(errc::function_not_supported); 149998a5c88SEric Fiselier } 150998a5c88SEric Fiselier 151998a5c88SEric Fiselier if (is_symlink(f)) { 152998a5c88SEric Fiselier if (bool(copy_options::skip_symlinks & options)) { 153998a5c88SEric Fiselier // do nothing 154998a5c88SEric Fiselier } else if (not exists(t)) { 155998a5c88SEric Fiselier __copy_symlink(from, to, ec); 156998a5c88SEric Fiselier } else { 157998a5c88SEric Fiselier return err.report(errc::file_exists); 158998a5c88SEric Fiselier } 159998a5c88SEric Fiselier return; 160998a5c88SEric Fiselier } else if (is_regular_file(f)) { 161998a5c88SEric Fiselier if (bool(copy_options::directories_only & options)) { 162998a5c88SEric Fiselier // do nothing 163998a5c88SEric Fiselier } else if (bool(copy_options::create_symlinks & options)) { 164998a5c88SEric Fiselier __create_symlink(from, to, ec); 165998a5c88SEric Fiselier } else if (bool(copy_options::create_hard_links & options)) { 166998a5c88SEric Fiselier __create_hard_link(from, to, ec); 167998a5c88SEric Fiselier } else if (is_directory(t)) { 168998a5c88SEric Fiselier __copy_file(from, to / from.filename(), options, ec); 169998a5c88SEric Fiselier } else { 170998a5c88SEric Fiselier __copy_file(from, to, options, ec); 171998a5c88SEric Fiselier } 172998a5c88SEric Fiselier return; 173998a5c88SEric Fiselier } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) { 174998a5c88SEric Fiselier return err.report(errc::is_a_directory); 1759783f28cSLouis Dionne } else if (is_directory(f) && (bool(copy_options::recursive & options) || copy_options::none == options)) { 176998a5c88SEric Fiselier if (!exists(t)) { 177998a5c88SEric Fiselier // create directory to with attributes from 'from'. 178998a5c88SEric Fiselier __create_directory(to, from, ec); 179998a5c88SEric Fiselier if (ec && *ec) { 180998a5c88SEric Fiselier return; 181998a5c88SEric Fiselier } 182998a5c88SEric Fiselier } 1839783f28cSLouis Dionne directory_iterator it = ec ? directory_iterator(from, *ec) : directory_iterator(from); 184998a5c88SEric Fiselier if (ec && *ec) { 185998a5c88SEric Fiselier return; 186998a5c88SEric Fiselier } 187998a5c88SEric Fiselier error_code m_ec2; 18811399028SRodrigo Salazar for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) { 1899783f28cSLouis Dionne __copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec); 190998a5c88SEric Fiselier if (ec && *ec) { 191998a5c88SEric Fiselier return; 192998a5c88SEric Fiselier } 193998a5c88SEric Fiselier } 19411399028SRodrigo Salazar if (m_ec2) { 19511399028SRodrigo Salazar return err.report(m_ec2); 19611399028SRodrigo Salazar } 197998a5c88SEric Fiselier } 198998a5c88SEric Fiselier } 199998a5c88SEric Fiselier 200998a5c88SEric Fiselier namespace detail { 201998a5c88SEric Fiselier namespace { 202998a5c88SEric Fiselier 203cb1c1563SJannik Glückert #if defined(_LIBCPP_FILESYSTEM_NEED_FSTREAM) 204cb1c1563SJannik Glückert bool copy_file_impl_fstream(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 205998a5c88SEric Fiselier ifstream in; 206998a5c88SEric Fiselier in.__open(read_fd.fd, ios::binary); 207998a5c88SEric Fiselier if (!in.is_open()) { 208998a5c88SEric Fiselier // This assumes that __open didn't reset the error code. 209998a5c88SEric Fiselier ec = capture_errno(); 210998a5c88SEric Fiselier return false; 211998a5c88SEric Fiselier } 21208b4cc5eSMartin Storsjö read_fd.fd = -1; 213998a5c88SEric Fiselier ofstream out; 214998a5c88SEric Fiselier out.__open(write_fd.fd, ios::binary); 215998a5c88SEric Fiselier if (!out.is_open()) { 216998a5c88SEric Fiselier ec = capture_errno(); 217998a5c88SEric Fiselier return false; 218998a5c88SEric Fiselier } 21908b4cc5eSMartin Storsjö write_fd.fd = -1; 220998a5c88SEric Fiselier 221998a5c88SEric Fiselier if (in.good() && out.good()) { 222998a5c88SEric Fiselier using InIt = istreambuf_iterator<char>; 223998a5c88SEric Fiselier using OutIt = ostreambuf_iterator<char>; 224998a5c88SEric Fiselier InIt bin(in); 225998a5c88SEric Fiselier InIt ein; 226998a5c88SEric Fiselier OutIt bout(out); 227998a5c88SEric Fiselier copy(bin, ein, bout); 228998a5c88SEric Fiselier } 229998a5c88SEric Fiselier if (out.fail() || in.fail()) { 230998a5c88SEric Fiselier ec = make_error_code(errc::io_error); 231998a5c88SEric Fiselier return false; 232998a5c88SEric Fiselier } 233998a5c88SEric Fiselier 234998a5c88SEric Fiselier ec.clear(); 235998a5c88SEric Fiselier return true; 236998a5c88SEric Fiselier } 237cb1c1563SJannik Glückert #endif 238cb1c1563SJannik Glückert 239cb1c1563SJannik Glückert #if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) 240cb1c1563SJannik Glückert bool copy_file_impl_copy_file_range(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 241cb1c1563SJannik Glückert size_t count = read_fd.get_stat().st_size; 242cb1c1563SJannik Glückert // a zero-length file is either empty, or not copyable by this syscall 243cb1c1563SJannik Glückert // return early to avoid the syscall cost 244cb1c1563SJannik Glückert if (count == 0) { 245cb1c1563SJannik Glückert ec = {EINVAL, generic_category()}; 246cb1c1563SJannik Glückert return false; 247cb1c1563SJannik Glückert } 248cb1c1563SJannik Glückert // do not modify the fd positions as copy_file_impl_sendfile may be called after a partial copy 249faa3f752SJannik Glückert # if defined(__linux__) 250faa3f752SJannik Glückert loff_t off_in = 0; 251faa3f752SJannik Glückert loff_t off_out = 0; 252faa3f752SJannik Glückert # else 253cb1c1563SJannik Glückert off_t off_in = 0; 254cb1c1563SJannik Glückert off_t off_out = 0; 255faa3f752SJannik Glückert # endif 256faa3f752SJannik Glückert 257cb1c1563SJannik Glückert do { 258cb1c1563SJannik Glückert ssize_t res; 259cb1c1563SJannik Glückert 260cb1c1563SJannik Glückert if ((res = ::copy_file_range(read_fd.fd, &off_in, write_fd.fd, &off_out, count, 0)) == -1) { 261cb1c1563SJannik Glückert ec = capture_errno(); 262cb1c1563SJannik Glückert return false; 263cb1c1563SJannik Glückert } 264cb1c1563SJannik Glückert count -= res; 265cb1c1563SJannik Glückert } while (count > 0); 266cb1c1563SJannik Glückert 267cb1c1563SJannik Glückert ec.clear(); 268cb1c1563SJannik Glückert 269cb1c1563SJannik Glückert return true; 270cb1c1563SJannik Glückert } 271cb1c1563SJannik Glückert #endif 272cb1c1563SJannik Glückert 273cb1c1563SJannik Glückert #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) 274cb1c1563SJannik Glückert bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 275cb1c1563SJannik Glückert size_t count = read_fd.get_stat().st_size; 276cb1c1563SJannik Glückert // a zero-length file is either empty, or not copyable by this syscall 277cb1c1563SJannik Glückert // return early to avoid the syscall cost 278cb1c1563SJannik Glückert // however, we can't afford this luxury in the no-locale build, 279cb1c1563SJannik Glückert // as we can't utilize the fstream impl to copy empty files 280cb1c1563SJannik Glückert # if _LIBCPP_HAS_LOCALIZATION 281cb1c1563SJannik Glückert if (count == 0) { 282cb1c1563SJannik Glückert ec = {EINVAL, generic_category()}; 283cb1c1563SJannik Glückert return false; 284cb1c1563SJannik Glückert } 285cb1c1563SJannik Glückert # endif 286cb1c1563SJannik Glückert do { 287cb1c1563SJannik Glückert ssize_t res; 288cb1c1563SJannik Glückert if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) { 289cb1c1563SJannik Glückert ec = capture_errno(); 290cb1c1563SJannik Glückert return false; 291cb1c1563SJannik Glückert } 292cb1c1563SJannik Glückert count -= res; 293cb1c1563SJannik Glückert } while (count > 0); 294cb1c1563SJannik Glückert 295cb1c1563SJannik Glückert ec.clear(); 296cb1c1563SJannik Glückert 297cb1c1563SJannik Glückert return true; 298cb1c1563SJannik Glückert } 299cb1c1563SJannik Glückert #endif 300cb1c1563SJannik Glückert 301cb1c1563SJannik Glückert #if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) || defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) 302cb1c1563SJannik Glückert // If we have copy_file_range or sendfile, try both in succession (if available). 303cb1c1563SJannik Glückert // If both fail, fall back to using fstream. 304cb1c1563SJannik Glückert bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 305cb1c1563SJannik Glückert # if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) 306cb1c1563SJannik Glückert if (copy_file_impl_copy_file_range(read_fd, write_fd, ec)) { 307cb1c1563SJannik Glückert return true; 308cb1c1563SJannik Glückert } 309cb1c1563SJannik Glückert // EINVAL: src and dst are the same file (this is not cheaply 310cb1c1563SJannik Glückert // detectable from userspace) 311cb1c1563SJannik Glückert // EINVAL: copy_file_range is unsupported for this file type by the 312cb1c1563SJannik Glückert // underlying filesystem 313cb1c1563SJannik Glückert // ENOTSUP: undocumented, can arise with old kernels and NFS 314cb1c1563SJannik Glückert // EOPNOTSUPP: filesystem does not implement copy_file_range 315cb1c1563SJannik Glückert // ETXTBSY: src or dst is an active swapfile (nonsensical, but allowed 316cb1c1563SJannik Glückert // with normal copying) 317cb1c1563SJannik Glückert // EXDEV: src and dst are on different filesystems that do not support 318cb1c1563SJannik Glückert // cross-fs copy_file_range 319cb1c1563SJannik Glückert // ENOENT: undocumented, can arise with CIFS 320cb1c1563SJannik Glückert // ENOSYS: unsupported by kernel or blocked by seccomp 321cb1c1563SJannik Glückert if (ec.value() != EINVAL && ec.value() != ENOTSUP && ec.value() != EOPNOTSUPP && ec.value() != ETXTBSY && 322cb1c1563SJannik Glückert ec.value() != EXDEV && ec.value() != ENOENT && ec.value() != ENOSYS) { 323cb1c1563SJannik Glückert return false; 324cb1c1563SJannik Glückert } 325cb1c1563SJannik Glückert ec.clear(); 326cb1c1563SJannik Glückert # endif 327cb1c1563SJannik Glückert 328cb1c1563SJannik Glückert # if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) 329cb1c1563SJannik Glückert if (copy_file_impl_sendfile(read_fd, write_fd, ec)) { 330cb1c1563SJannik Glückert return true; 331cb1c1563SJannik Glückert } 332cb1c1563SJannik Glückert // EINVAL: unsupported file type 333cb1c1563SJannik Glückert if (ec.value() != EINVAL) { 334cb1c1563SJannik Glückert return false; 335cb1c1563SJannik Glückert } 336cb1c1563SJannik Glückert ec.clear(); 337cb1c1563SJannik Glückert # endif 338cb1c1563SJannik Glückert 339cb1c1563SJannik Glückert # if defined(_LIBCPP_FILESYSTEM_NEED_FSTREAM) 340cb1c1563SJannik Glückert return copy_file_impl_fstream(read_fd, write_fd, ec); 341cb1c1563SJannik Glückert # else 342cb1c1563SJannik Glückert // since iostreams are unavailable in the no-locale build, just fail after a failed sendfile 343cb1c1563SJannik Glückert ec.assign(EINVAL, std::system_category()); 344cb1c1563SJannik Glückert return false; 345cb1c1563SJannik Glückert # endif 346cb1c1563SJannik Glückert } 347cb1c1563SJannik Glückert #elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE) 348cb1c1563SJannik Glückert bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 349cb1c1563SJannik Glückert struct CopyFileState { 350cb1c1563SJannik Glückert copyfile_state_t state; 351cb1c1563SJannik Glückert CopyFileState() { state = copyfile_state_alloc(); } 352cb1c1563SJannik Glückert ~CopyFileState() { copyfile_state_free(state); } 353cb1c1563SJannik Glückert 354cb1c1563SJannik Glückert private: 355cb1c1563SJannik Glückert CopyFileState(CopyFileState const&) = delete; 356cb1c1563SJannik Glückert CopyFileState& operator=(CopyFileState const&) = delete; 357cb1c1563SJannik Glückert }; 358cb1c1563SJannik Glückert 359cb1c1563SJannik Glückert CopyFileState cfs; 360cb1c1563SJannik Glückert if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) { 361cb1c1563SJannik Glückert ec = capture_errno(); 362cb1c1563SJannik Glückert return false; 363cb1c1563SJannik Glückert } 364cb1c1563SJannik Glückert 365cb1c1563SJannik Glückert ec.clear(); 366cb1c1563SJannik Glückert return true; 367cb1c1563SJannik Glückert } 368cb1c1563SJannik Glückert #elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM) 369cb1c1563SJannik Glückert bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { 370cb1c1563SJannik Glückert return copy_file_impl_fstream(read_fd, write_fd, ec); 371cb1c1563SJannik Glückert } 372998a5c88SEric Fiselier #else 37317dcf85eSLouis Dionne # error "Unknown implementation for copy_file_impl" 37417dcf85eSLouis Dionne #endif // copy_file_impl implementation 375998a5c88SEric Fiselier 37617dcf85eSLouis Dionne } // end anonymous namespace 377953af0e7SLouis Dionne } // namespace detail 378998a5c88SEric Fiselier 3799783f28cSLouis Dionne bool __copy_file(const path& from, const path& to, copy_options options, error_code* ec) { 380998a5c88SEric Fiselier using detail::FileDescriptor; 381998a5c88SEric Fiselier ErrorHandler<bool> err("copy_file", ec, &to, &from); 382998a5c88SEric Fiselier 383998a5c88SEric Fiselier error_code m_ec; 3849783f28cSLouis Dionne FileDescriptor from_fd = FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY); 385998a5c88SEric Fiselier if (m_ec) 386998a5c88SEric Fiselier return err.report(m_ec); 387998a5c88SEric Fiselier 388998a5c88SEric Fiselier auto from_st = from_fd.get_status(); 389998a5c88SEric Fiselier StatT const& from_stat = from_fd.get_stat(); 390998a5c88SEric Fiselier if (!is_regular_file(from_st)) { 391998a5c88SEric Fiselier if (not m_ec) 392998a5c88SEric Fiselier m_ec = make_error_code(errc::not_supported); 393998a5c88SEric Fiselier return err.report(m_ec); 394998a5c88SEric Fiselier } 395998a5c88SEric Fiselier 396998a5c88SEric Fiselier const bool skip_existing = bool(copy_options::skip_existing & options); 397998a5c88SEric Fiselier const bool update_existing = bool(copy_options::update_existing & options); 3989783f28cSLouis Dionne const bool overwrite_existing = bool(copy_options::overwrite_existing & options); 399998a5c88SEric Fiselier 400998a5c88SEric Fiselier StatT to_stat_path; 401998a5c88SEric Fiselier file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec); 402998a5c88SEric Fiselier if (!status_known(to_st)) 403998a5c88SEric Fiselier return err.report(m_ec); 404998a5c88SEric Fiselier 405998a5c88SEric Fiselier const bool to_exists = exists(to_st); 406998a5c88SEric Fiselier if (to_exists && !is_regular_file(to_st)) 407998a5c88SEric Fiselier return err.report(errc::not_supported); 408998a5c88SEric Fiselier 409998a5c88SEric Fiselier if (to_exists && detail::stat_equivalent(from_stat, to_stat_path)) 410998a5c88SEric Fiselier return err.report(errc::file_exists); 411998a5c88SEric Fiselier 412998a5c88SEric Fiselier if (to_exists && skip_existing) 413998a5c88SEric Fiselier return false; 414998a5c88SEric Fiselier 415998a5c88SEric Fiselier bool ShouldCopy = [&]() { 416998a5c88SEric Fiselier if (to_exists && update_existing) { 417998a5c88SEric Fiselier auto from_time = detail::extract_mtime(from_stat); 418998a5c88SEric Fiselier auto to_time = detail::extract_mtime(to_stat_path); 419998a5c88SEric Fiselier if (from_time.tv_sec < to_time.tv_sec) 420998a5c88SEric Fiselier return false; 4219783f28cSLouis Dionne if (from_time.tv_sec == to_time.tv_sec && from_time.tv_nsec <= to_time.tv_nsec) 422998a5c88SEric Fiselier return false; 423998a5c88SEric Fiselier return true; 424998a5c88SEric Fiselier } 425998a5c88SEric Fiselier if (!to_exists || overwrite_existing) 426998a5c88SEric Fiselier return true; 427998a5c88SEric Fiselier return err.report(errc::file_exists); 428998a5c88SEric Fiselier }(); 429998a5c88SEric Fiselier if (!ShouldCopy) 430998a5c88SEric Fiselier return false; 431998a5c88SEric Fiselier 432998a5c88SEric Fiselier // Don't truncate right away. We may not be opening the file we originally 433998a5c88SEric Fiselier // looked at; we'll check this later. 434efec3cc6SMartin Storsjö int to_open_flags = O_WRONLY | O_BINARY; 435998a5c88SEric Fiselier if (!to_exists) 436998a5c88SEric Fiselier to_open_flags |= O_CREAT; 4379783f28cSLouis Dionne FileDescriptor to_fd = FileDescriptor::create_with_status(&to, m_ec, to_open_flags, from_stat.st_mode); 438998a5c88SEric Fiselier if (m_ec) 439998a5c88SEric Fiselier return err.report(m_ec); 440998a5c88SEric Fiselier 441998a5c88SEric Fiselier if (to_exists) { 442998a5c88SEric Fiselier // Check that the file we initially stat'ed is equivalent to the one 443998a5c88SEric Fiselier // we opened. 444998a5c88SEric Fiselier // FIXME: report this better. 445998a5c88SEric Fiselier if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat())) 446998a5c88SEric Fiselier return err.report(errc::bad_file_descriptor); 447998a5c88SEric Fiselier 448998a5c88SEric Fiselier // Set the permissions and truncate the file we opened. 449998a5c88SEric Fiselier if (detail::posix_fchmod(to_fd, from_stat, m_ec)) 450998a5c88SEric Fiselier return err.report(m_ec); 451998a5c88SEric Fiselier if (detail::posix_ftruncate(to_fd, 0, m_ec)) 452998a5c88SEric Fiselier return err.report(m_ec); 453998a5c88SEric Fiselier } 454998a5c88SEric Fiselier 45521853b96SLouis Dionne if (!detail::copy_file_impl(from_fd, to_fd, m_ec)) { 456998a5c88SEric Fiselier // FIXME: Remove the dest file if we failed, and it didn't exist previously. 457998a5c88SEric Fiselier return err.report(m_ec); 458998a5c88SEric Fiselier } 459998a5c88SEric Fiselier 460998a5c88SEric Fiselier return true; 461998a5c88SEric Fiselier } 462998a5c88SEric Fiselier 4639783f28cSLouis Dionne void __copy_symlink(const path& existing_symlink, const path& new_symlink, error_code* ec) { 464998a5c88SEric Fiselier const path real_path(__read_symlink(existing_symlink, ec)); 465998a5c88SEric Fiselier if (ec && *ec) { 466998a5c88SEric Fiselier return; 467998a5c88SEric Fiselier } 468efec3cc6SMartin Storsjö #if defined(_LIBCPP_WIN32API) 469efec3cc6SMartin Storsjö error_code local_ec; 470efec3cc6SMartin Storsjö if (is_directory(real_path, local_ec)) 471efec3cc6SMartin Storsjö __create_directory_symlink(real_path, new_symlink, ec); 472efec3cc6SMartin Storsjö else 473efec3cc6SMartin Storsjö #endif 474998a5c88SEric Fiselier __create_symlink(real_path, new_symlink, ec); 475998a5c88SEric Fiselier } 476998a5c88SEric Fiselier 477998a5c88SEric Fiselier bool __create_directories(const path& p, error_code* ec) { 478998a5c88SEric Fiselier ErrorHandler<bool> err("create_directories", ec, &p); 479998a5c88SEric Fiselier 480998a5c88SEric Fiselier error_code m_ec; 481998a5c88SEric Fiselier auto const st = detail::posix_stat(p, &m_ec); 482998a5c88SEric Fiselier if (!status_known(st)) 483998a5c88SEric Fiselier return err.report(m_ec); 484998a5c88SEric Fiselier else if (is_directory(st)) 485998a5c88SEric Fiselier return false; 486998a5c88SEric Fiselier else if (exists(st)) 487998a5c88SEric Fiselier return err.report(errc::file_exists); 488998a5c88SEric Fiselier 489998a5c88SEric Fiselier const path parent = p.parent_path(); 490998a5c88SEric Fiselier if (!parent.empty()) { 491998a5c88SEric Fiselier const file_status parent_st = status(parent, m_ec); 492998a5c88SEric Fiselier if (not status_known(parent_st)) 493998a5c88SEric Fiselier return err.report(m_ec); 494998a5c88SEric Fiselier if (not exists(parent_st)) { 49599c7b532SMartin Storsjö if (parent == p) 49699c7b532SMartin Storsjö return err.report(errc::invalid_argument); 497998a5c88SEric Fiselier __create_directories(parent, ec); 498998a5c88SEric Fiselier if (ec && *ec) { 499998a5c88SEric Fiselier return false; 500998a5c88SEric Fiselier } 501c5e8f024SMartin Storsjö } else if (not is_directory(parent_st)) 502c5e8f024SMartin Storsjö return err.report(errc::not_a_directory); 503998a5c88SEric Fiselier } 50468e45962SMartin Storsjö bool ret = __create_directory(p, &m_ec); 50568e45962SMartin Storsjö if (m_ec) 50668e45962SMartin Storsjö return err.report(m_ec); 50768e45962SMartin Storsjö return ret; 508998a5c88SEric Fiselier } 509998a5c88SEric Fiselier 510998a5c88SEric Fiselier bool __create_directory(const path& p, error_code* ec) { 511998a5c88SEric Fiselier ErrorHandler<bool> err("create_directory", ec, &p); 512998a5c88SEric Fiselier 513efec3cc6SMartin Storsjö if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0) 514998a5c88SEric Fiselier return true; 515e4ed349cSMarek Kurdej 516*2b26ee6eSJames Y Knight error_code mec = detail::get_last_error(); 517*2b26ee6eSJames Y Knight if (mec != errc::file_exists) 518*2b26ee6eSJames Y Knight return err.report(mec); 519e4ed349cSMarek Kurdej error_code ignored_ec; 520e4ed349cSMarek Kurdej const file_status st = status(p, ignored_ec); 521cb151164SJoerg Sonnenberger if (!is_directory(st)) 522cb151164SJoerg Sonnenberger return err.report(mec); 523998a5c88SEric Fiselier return false; 524998a5c88SEric Fiselier } 525998a5c88SEric Fiselier 526998a5c88SEric Fiselier bool __create_directory(path const& p, path const& attributes, error_code* ec) { 527998a5c88SEric Fiselier ErrorHandler<bool> err("create_directory", ec, &p, &attributes); 528998a5c88SEric Fiselier 529998a5c88SEric Fiselier StatT attr_stat; 530998a5c88SEric Fiselier error_code mec; 531a77e9180SJoerg Sonnenberger file_status st = detail::posix_stat(attributes, attr_stat, &mec); 532998a5c88SEric Fiselier if (!status_known(st)) 533998a5c88SEric Fiselier return err.report(mec); 534998a5c88SEric Fiselier if (!is_directory(st)) 5359783f28cSLouis Dionne return err.report(errc::not_a_directory, "the specified attribute path is invalid"); 536998a5c88SEric Fiselier 537efec3cc6SMartin Storsjö if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0) 538998a5c88SEric Fiselier return true; 539e4ed349cSMarek Kurdej 540*2b26ee6eSJames Y Knight mec = detail::get_last_error(); 541*2b26ee6eSJames Y Knight if (mec != errc::file_exists) 542*2b26ee6eSJames Y Knight return err.report(mec); 543a77e9180SJoerg Sonnenberger 544e4ed349cSMarek Kurdej error_code ignored_ec; 545a77e9180SJoerg Sonnenberger st = status(p, ignored_ec); 546a77e9180SJoerg Sonnenberger if (!is_directory(st)) 547a77e9180SJoerg Sonnenberger return err.report(mec); 548998a5c88SEric Fiselier return false; 549998a5c88SEric Fiselier } 550998a5c88SEric Fiselier 5519783f28cSLouis Dionne void __create_directory_symlink(path const& from, path const& to, error_code* ec) { 552998a5c88SEric Fiselier ErrorHandler<void> err("create_directory_symlink", ec, &from, &to); 553efec3cc6SMartin Storsjö if (detail::symlink_dir(from.c_str(), to.c_str()) == -1) 554*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 555998a5c88SEric Fiselier } 556998a5c88SEric Fiselier 557998a5c88SEric Fiselier void __create_hard_link(const path& from, const path& to, error_code* ec) { 558998a5c88SEric Fiselier ErrorHandler<void> err("create_hard_link", ec, &from, &to); 559efec3cc6SMartin Storsjö if (detail::link(from.c_str(), to.c_str()) == -1) 560*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 561998a5c88SEric Fiselier } 562998a5c88SEric Fiselier 563998a5c88SEric Fiselier void __create_symlink(path const& from, path const& to, error_code* ec) { 564998a5c88SEric Fiselier ErrorHandler<void> err("create_symlink", ec, &from, &to); 565efec3cc6SMartin Storsjö if (detail::symlink_file(from.c_str(), to.c_str()) == -1) 566*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 567998a5c88SEric Fiselier } 568998a5c88SEric Fiselier 569998a5c88SEric Fiselier path __current_path(error_code* ec) { 570998a5c88SEric Fiselier ErrorHandler<path> err("current_path", ec); 571998a5c88SEric Fiselier 572c7d46f22SMartin Storsjö #if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__) 5730c71c914SMartin Storsjö // Common extension outside of POSIX getcwd() spec, without needing to 5740c71c914SMartin Storsjö // preallocate a buffer. Also supported by a number of other POSIX libcs. 5750c71c914SMartin Storsjö int size = 0; 5760c71c914SMartin Storsjö path::value_type* ptr = nullptr; 5770c71c914SMartin Storsjö typedef decltype(&::free) Deleter; 5780c71c914SMartin Storsjö Deleter deleter = &::free; 5790c71c914SMartin Storsjö #else 5806082478eSKonstantin Varlamov errno = 0; // Note: POSIX mandates that modifying `errno` is thread-safe. 581998a5c88SEric Fiselier auto size = ::pathconf(".", _PC_PATH_MAX); 5826082478eSKonstantin Varlamov if (size == -1) { 5836082478eSKonstantin Varlamov if (errno != 0) { 5846082478eSKonstantin Varlamov return err.report(capture_errno(), "call to pathconf failed"); 5856082478eSKonstantin Varlamov 5866082478eSKonstantin Varlamov // `pathconf` returns `-1` without an error to indicate no limit. 5876082478eSKonstantin Varlamov } else { 5886082478eSKonstantin Varlamov # if defined(__MVS__) && !defined(PATH_MAX) 5896082478eSKonstantin Varlamov size = _XOPEN_PATH_MAX + 1; 5906082478eSKonstantin Varlamov # else 5916082478eSKonstantin Varlamov size = PATH_MAX + 1; 5926082478eSKonstantin Varlamov # endif 5936082478eSKonstantin Varlamov } 5946082478eSKonstantin Varlamov } 595998a5c88SEric Fiselier 5960c71c914SMartin Storsjö auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]); 5970c71c914SMartin Storsjö path::value_type* ptr = buff.get(); 5980c71c914SMartin Storsjö 5990c71c914SMartin Storsjö // Preallocated buffer, don't free the buffer in the second unique_ptr 6000c71c914SMartin Storsjö // below. 6019783f28cSLouis Dionne struct Deleter { 6029783f28cSLouis Dionne void operator()(void*) const {} 6039783f28cSLouis Dionne }; 6040c71c914SMartin Storsjö Deleter deleter; 6050c71c914SMartin Storsjö #endif 6060c71c914SMartin Storsjö 6079783f28cSLouis Dionne unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter); 6080c71c914SMartin Storsjö if (hold.get() == nullptr) 609*2b26ee6eSJames Y Knight return err.report(detail::get_last_error(), "call to getcwd failed"); 610998a5c88SEric Fiselier 6110c71c914SMartin Storsjö return {hold.get()}; 612998a5c88SEric Fiselier } 613998a5c88SEric Fiselier 614998a5c88SEric Fiselier void __current_path(const path& p, error_code* ec) { 615998a5c88SEric Fiselier ErrorHandler<void> err("current_path", ec, &p); 616efec3cc6SMartin Storsjö if (detail::chdir(p.c_str()) == -1) 617*2b26ee6eSJames Y Knight err.report(detail::get_last_error()); 618998a5c88SEric Fiselier } 619998a5c88SEric Fiselier 620998a5c88SEric Fiselier bool __equivalent(const path& p1, const path& p2, error_code* ec) { 621998a5c88SEric Fiselier ErrorHandler<bool> err("equivalent", ec, &p1, &p2); 622998a5c88SEric Fiselier 623998a5c88SEric Fiselier error_code ec1, ec2; 624998a5c88SEric Fiselier StatT st1 = {}, st2 = {}; 625998a5c88SEric Fiselier auto s1 = detail::posix_stat(p1.native(), st1, &ec1); 626998a5c88SEric Fiselier if (!exists(s1)) 627998a5c88SEric Fiselier return err.report(errc::not_supported); 628998a5c88SEric Fiselier auto s2 = detail::posix_stat(p2.native(), st2, &ec2); 629998a5c88SEric Fiselier if (!exists(s2)) 630998a5c88SEric Fiselier return err.report(errc::not_supported); 631998a5c88SEric Fiselier 632998a5c88SEric Fiselier return detail::stat_equivalent(st1, st2); 633998a5c88SEric Fiselier } 634998a5c88SEric Fiselier 635998a5c88SEric Fiselier uintmax_t __file_size(const path& p, error_code* ec) { 636998a5c88SEric Fiselier ErrorHandler<uintmax_t> err("file_size", ec, &p); 637998a5c88SEric Fiselier 638998a5c88SEric Fiselier error_code m_ec; 639998a5c88SEric Fiselier StatT st; 640998a5c88SEric Fiselier file_status fst = detail::posix_stat(p, st, &m_ec); 641998a5c88SEric Fiselier if (!exists(fst) || !is_regular_file(fst)) { 6429783f28cSLouis Dionne errc error_kind = is_directory(fst) ? errc::is_a_directory : errc::not_supported; 643998a5c88SEric Fiselier if (!m_ec) 644998a5c88SEric Fiselier m_ec = make_error_code(error_kind); 645998a5c88SEric Fiselier return err.report(m_ec); 646998a5c88SEric Fiselier } 647998a5c88SEric Fiselier // is_regular_file(p) == true 648998a5c88SEric Fiselier return static_cast<uintmax_t>(st.st_size); 649998a5c88SEric Fiselier } 650998a5c88SEric Fiselier 651998a5c88SEric Fiselier uintmax_t __hard_link_count(const path& p, error_code* ec) { 652998a5c88SEric Fiselier ErrorHandler<uintmax_t> err("hard_link_count", ec, &p); 653998a5c88SEric Fiselier 654998a5c88SEric Fiselier error_code m_ec; 655998a5c88SEric Fiselier StatT st; 656998a5c88SEric Fiselier detail::posix_stat(p, st, &m_ec); 657998a5c88SEric Fiselier if (m_ec) 658998a5c88SEric Fiselier return err.report(m_ec); 659998a5c88SEric Fiselier return static_cast<uintmax_t>(st.st_nlink); 660998a5c88SEric Fiselier } 661998a5c88SEric Fiselier 662998a5c88SEric Fiselier bool __fs_is_empty(const path& p, error_code* ec) { 663998a5c88SEric Fiselier ErrorHandler<bool> err("is_empty", ec, &p); 664998a5c88SEric Fiselier 665998a5c88SEric Fiselier error_code m_ec; 666998a5c88SEric Fiselier StatT pst; 667998a5c88SEric Fiselier auto st = detail::posix_stat(p, pst, &m_ec); 668998a5c88SEric Fiselier if (m_ec) 669998a5c88SEric Fiselier return err.report(m_ec); 670998a5c88SEric Fiselier else if (!is_directory(st) && !is_regular_file(st)) 671998a5c88SEric Fiselier return err.report(errc::not_supported); 672998a5c88SEric Fiselier else if (is_directory(st)) { 673998a5c88SEric Fiselier auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p); 674998a5c88SEric Fiselier if (ec && *ec) 675998a5c88SEric Fiselier return false; 676998a5c88SEric Fiselier return it == directory_iterator{}; 677998a5c88SEric Fiselier } else if (is_regular_file(st)) 678998a5c88SEric Fiselier return static_cast<uintmax_t>(pst.st_size) == 0; 679998a5c88SEric Fiselier 6802a8f9a5eSNikolas Klauser __libcpp_unreachable(); 681998a5c88SEric Fiselier } 682998a5c88SEric Fiselier 683998a5c88SEric Fiselier file_time_type __last_write_time(const path& p, error_code* ec) { 684998a5c88SEric Fiselier using namespace chrono; 685998a5c88SEric Fiselier ErrorHandler<file_time_type> err("last_write_time", ec, &p); 686998a5c88SEric Fiselier 687998a5c88SEric Fiselier error_code m_ec; 688998a5c88SEric Fiselier StatT st; 689998a5c88SEric Fiselier detail::posix_stat(p, st, &m_ec); 690998a5c88SEric Fiselier if (m_ec) 691998a5c88SEric Fiselier return err.report(m_ec); 692c7d3c844SLouis Dionne return detail::__extract_last_write_time(p, st, ec); 693998a5c88SEric Fiselier } 694998a5c88SEric Fiselier 695998a5c88SEric Fiselier void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { 696998a5c88SEric Fiselier using detail::fs_time; 697998a5c88SEric Fiselier ErrorHandler<void> err("last_write_time", ec, &p); 698998a5c88SEric Fiselier 699592d6235SMartin Storsjö #if defined(_LIBCPP_WIN32API) 700592d6235SMartin Storsjö TimeSpec ts; 701592d6235SMartin Storsjö if (!fs_time::convert_to_timespec(ts, new_time)) 702592d6235SMartin Storsjö return err.report(errc::value_too_large); 703592d6235SMartin Storsjö detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0); 704592d6235SMartin Storsjö if (!h) 705*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 706592d6235SMartin Storsjö FILETIME last_write = timespec_to_filetime(ts); 707592d6235SMartin Storsjö if (!SetFileTime(h, nullptr, nullptr, &last_write)) 708*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 709592d6235SMartin Storsjö #else 710998a5c88SEric Fiselier error_code m_ec; 711998a5c88SEric Fiselier array<TimeSpec, 2> tbuf; 712998a5c88SEric Fiselier # if !defined(_LIBCPP_USE_UTIMENSAT) 713998a5c88SEric Fiselier // This implementation has a race condition between determining the 714998a5c88SEric Fiselier // last access time and attempting to set it to the same value using 715998a5c88SEric Fiselier // ::utimes 716998a5c88SEric Fiselier StatT st; 717998a5c88SEric Fiselier file_status fst = detail::posix_stat(p, st, &m_ec); 718998a5c88SEric Fiselier if (m_ec) 719998a5c88SEric Fiselier return err.report(m_ec); 720998a5c88SEric Fiselier tbuf[0] = detail::extract_atime(st); 721998a5c88SEric Fiselier # else 722998a5c88SEric Fiselier tbuf[0].tv_sec = 0; 723998a5c88SEric Fiselier tbuf[0].tv_nsec = UTIME_OMIT; 724998a5c88SEric Fiselier # endif 725998a5c88SEric Fiselier if (!fs_time::convert_to_timespec(tbuf[1], new_time)) 726998a5c88SEric Fiselier return err.report(errc::value_too_large); 727998a5c88SEric Fiselier 728998a5c88SEric Fiselier detail::set_file_times(p, tbuf, m_ec); 729998a5c88SEric Fiselier if (m_ec) 730998a5c88SEric Fiselier return err.report(m_ec); 731592d6235SMartin Storsjö #endif 732998a5c88SEric Fiselier } 733998a5c88SEric Fiselier 7349783f28cSLouis Dionne void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) { 735998a5c88SEric Fiselier ErrorHandler<void> err("permissions", ec, &p); 736998a5c88SEric Fiselier 737998a5c88SEric Fiselier auto has_opt = [&](perm_options o) { return bool(o & opts); }; 738998a5c88SEric Fiselier const bool resolve_symlinks = !has_opt(perm_options::nofollow); 739998a5c88SEric Fiselier const bool add_perms = has_opt(perm_options::add); 740998a5c88SEric Fiselier const bool remove_perms = has_opt(perm_options::remove); 741dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 742998a5c88SEric Fiselier (add_perms + remove_perms + has_opt(perm_options::replace)) == 1, 743dc577520SKonstantin Varlamov "One and only one of the perm_options constants 'replace', 'add', or 'remove' must be present in opts"); 744998a5c88SEric Fiselier 745998a5c88SEric Fiselier bool set_sym_perms = false; 746998a5c88SEric Fiselier prms &= perms::mask; 747998a5c88SEric Fiselier if (!resolve_symlinks || (add_perms || remove_perms)) { 748998a5c88SEric Fiselier error_code m_ec; 7499783f28cSLouis Dionne file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) : detail::posix_lstat(p, &m_ec); 750998a5c88SEric Fiselier set_sym_perms = is_symlink(st); 751998a5c88SEric Fiselier if (m_ec) 752998a5c88SEric Fiselier return err.report(m_ec); 7536082478eSKonstantin Varlamov // TODO(hardening): double-check this assertion -- it might be a valid (if rare) case when the permissions are 7546082478eSKonstantin Varlamov // unknown. 7556082478eSKonstantin Varlamov _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(st.permissions() != perms::unknown, "Permissions unexpectedly unknown"); 756998a5c88SEric Fiselier if (add_perms) 757998a5c88SEric Fiselier prms |= st.permissions(); 758998a5c88SEric Fiselier else if (remove_perms) 759998a5c88SEric Fiselier prms = st.permissions() & ~prms; 760998a5c88SEric Fiselier } 76140117b70SMartin Storsjö const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask); 762998a5c88SEric Fiselier 763998a5c88SEric Fiselier #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) 764998a5c88SEric Fiselier const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; 76540117b70SMartin Storsjö if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { 766*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 767998a5c88SEric Fiselier } 768998a5c88SEric Fiselier #else 769998a5c88SEric Fiselier if (set_sym_perms) 770998a5c88SEric Fiselier return err.report(errc::operation_not_supported); 771998a5c88SEric Fiselier if (::chmod(p.c_str(), real_perms) == -1) { 772998a5c88SEric Fiselier return err.report(capture_errno()); 773998a5c88SEric Fiselier } 774998a5c88SEric Fiselier #endif 775998a5c88SEric Fiselier } 776998a5c88SEric Fiselier 777998a5c88SEric Fiselier path __read_symlink(const path& p, error_code* ec) { 778998a5c88SEric Fiselier ErrorHandler<path> err("read_symlink", ec, &p); 779998a5c88SEric Fiselier 780cdc60a3bSMartin Storsjö #if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE) 7819783f28cSLouis Dionne struct NullDeleter { 7829783f28cSLouis Dionne void operator()(void*) const {} 7839783f28cSLouis Dionne }; 784cdc60a3bSMartin Storsjö # ifdef MAX_SYMLINK_SIZE 785cdc60a3bSMartin Storsjö const size_t size = MAX_SYMLINK_SIZE + 1; 786cdc60a3bSMartin Storsjö # else 7870e997efdSEric Fiselier const size_t size = PATH_MAX + 1; 788cdc60a3bSMartin Storsjö # endif 789cdc60a3bSMartin Storsjö path::value_type stack_buff[size]; 790cdc60a3bSMartin Storsjö auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff); 7910e997efdSEric Fiselier #else 7920e997efdSEric Fiselier StatT sb; 7932ff8662bSMartin Storsjö if (detail::lstat(p.c_str(), &sb) == -1) { 794*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 795998a5c88SEric Fiselier } 7960e997efdSEric Fiselier const size_t size = sb.st_size + 1; 797cdc60a3bSMartin Storsjö auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]); 7980e997efdSEric Fiselier #endif 799cdc60a3bSMartin Storsjö detail::SSizeT ret; 800cdc60a3bSMartin Storsjö if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) 801*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 8026082478eSKonstantin Varlamov // Note that `ret` returning `0` would work, resulting in a valid empty string being returned. 8030e997efdSEric Fiselier if (static_cast<size_t>(ret) >= size) 8040e997efdSEric Fiselier return err.report(errc::value_too_large); 805998a5c88SEric Fiselier buff[ret] = 0; 8060e997efdSEric Fiselier return {buff.get()}; 807998a5c88SEric Fiselier } 808998a5c88SEric Fiselier 809998a5c88SEric Fiselier bool __remove(const path& p, error_code* ec) { 810998a5c88SEric Fiselier ErrorHandler<bool> err("remove", ec, &p); 811efec3cc6SMartin Storsjö if (detail::remove(p.c_str()) == -1) { 812*2b26ee6eSJames Y Knight error_code mec = detail::get_last_error(); 813*2b26ee6eSJames Y Knight if (mec != errc::no_such_file_or_directory) 814*2b26ee6eSJames Y Knight err.report(mec); 815998a5c88SEric Fiselier return false; 816998a5c88SEric Fiselier } 817998a5c88SEric Fiselier return true; 818998a5c88SEric Fiselier } 819998a5c88SEric Fiselier 8204f67a909SLouis Dionne // We currently have two implementations of `__remove_all`. The first one is general and 8214f67a909SLouis Dionne // used on platforms where we don't have access to the `openat()` family of POSIX functions. 8224f67a909SLouis Dionne // That implementation uses `directory_iterator`, however it is vulnerable to some race 8234f67a909SLouis Dionne // conditions, see https://reviews.llvm.org/D118134 for details. 8244f67a909SLouis Dionne // 8254f67a909SLouis Dionne // The second implementation is used on platforms where `openat()` & friends are available, 8264f67a909SLouis Dionne // and it threads file descriptors through recursive calls to avoid such race conditions. 8271b445cadSMuiez Ahmed #if defined(_LIBCPP_WIN32API) || defined(__MVS__) 8284f67a909SLouis Dionne # define REMOVE_ALL_USE_DIRECTORY_ITERATOR 8294f67a909SLouis Dionne #endif 8304f67a909SLouis Dionne 8314f67a909SLouis Dionne #if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR) 8324f67a909SLouis Dionne 833998a5c88SEric Fiselier namespace { 834998a5c88SEric Fiselier 835998a5c88SEric Fiselier uintmax_t remove_all_impl(path const& p, error_code& ec) { 836998a5c88SEric Fiselier const auto npos = static_cast<uintmax_t>(-1); 837998a5c88SEric Fiselier const file_status st = __symlink_status(p, &ec); 838998a5c88SEric Fiselier if (ec) 839998a5c88SEric Fiselier return npos; 840998a5c88SEric Fiselier uintmax_t count = 1; 841998a5c88SEric Fiselier if (is_directory(st)) { 8429783f28cSLouis Dionne for (directory_iterator it(p, ec); !ec && it != directory_iterator(); it.increment(ec)) { 843998a5c88SEric Fiselier auto other_count = remove_all_impl(it->path(), ec); 844998a5c88SEric Fiselier if (ec) 845998a5c88SEric Fiselier return npos; 846998a5c88SEric Fiselier count += other_count; 847998a5c88SEric Fiselier } 848998a5c88SEric Fiselier if (ec) 849998a5c88SEric Fiselier return npos; 850998a5c88SEric Fiselier } 851998a5c88SEric Fiselier if (!__remove(p, &ec)) 852998a5c88SEric Fiselier return npos; 853998a5c88SEric Fiselier return count; 854998a5c88SEric Fiselier } 855998a5c88SEric Fiselier 856953af0e7SLouis Dionne } // namespace 857998a5c88SEric Fiselier 858998a5c88SEric Fiselier uintmax_t __remove_all(const path& p, error_code* ec) { 859998a5c88SEric Fiselier ErrorHandler<uintmax_t> err("remove_all", ec, &p); 860998a5c88SEric Fiselier 861998a5c88SEric Fiselier error_code mec; 862998a5c88SEric Fiselier auto count = remove_all_impl(p, mec); 863998a5c88SEric Fiselier if (mec) { 864998a5c88SEric Fiselier if (mec == errc::no_such_file_or_directory) 865998a5c88SEric Fiselier return 0; 866998a5c88SEric Fiselier return err.report(mec); 867998a5c88SEric Fiselier } 868998a5c88SEric Fiselier return count; 869998a5c88SEric Fiselier } 870998a5c88SEric Fiselier 8714f67a909SLouis Dionne #else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR 8724f67a909SLouis Dionne 8734f67a909SLouis Dionne namespace { 8744f67a909SLouis Dionne 8754f67a909SLouis Dionne template <class Cleanup> 8764f67a909SLouis Dionne struct scope_exit { 8779783f28cSLouis Dionne explicit scope_exit(Cleanup const& cleanup) : cleanup_(cleanup) {} 8784f67a909SLouis Dionne 8794f67a909SLouis Dionne ~scope_exit() { cleanup_(); } 8804f67a909SLouis Dionne 8814f67a909SLouis Dionne private: 8824f67a909SLouis Dionne Cleanup cleanup_; 8834f67a909SLouis Dionne }; 884c2df7076SLouis Dionne _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scope_exit); 8854f67a909SLouis Dionne 8864f67a909SLouis Dionne uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) { 8874f67a909SLouis Dionne // First, try to open the path as a directory. 8884f67a909SLouis Dionne const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW; 8894f67a909SLouis Dionne int fd = ::openat(parent_directory, p.c_str(), options); 8904f67a909SLouis Dionne if (fd != -1) { 8914f67a909SLouis Dionne // If that worked, iterate over the contents of the directory and 8924f67a909SLouis Dionne // remove everything in it, recursively. 8934f67a909SLouis Dionne DIR* stream = ::fdopendir(fd); 8944f67a909SLouis Dionne if (stream == nullptr) { 8953906ebf7SKonstantin Varlamov ::close(fd); 8964f67a909SLouis Dionne ec = detail::capture_errno(); 8974f67a909SLouis Dionne return 0; 8984f67a909SLouis Dionne } 8993906ebf7SKonstantin Varlamov // Note: `::closedir` will also close the associated file descriptor, so 9003906ebf7SKonstantin Varlamov // there should be no call to `close(fd)`. 9014f67a909SLouis Dionne scope_exit close_stream([=] { ::closedir(stream); }); 9024f67a909SLouis Dionne 9034f67a909SLouis Dionne uintmax_t count = 0; 9044f67a909SLouis Dionne while (true) { 9054f67a909SLouis Dionne auto [str, type] = detail::posix_readdir(stream, ec); 9064f67a909SLouis Dionne static_assert(std::is_same_v<decltype(str), std::string_view>); 9074f67a909SLouis Dionne if (str == "." || str == "..") { 9084f67a909SLouis Dionne continue; 9094f67a909SLouis Dionne } else if (ec || str.empty()) { 9104f67a909SLouis Dionne break; // we're done iterating through the directory 9114f67a909SLouis Dionne } else { 9124f67a909SLouis Dionne count += remove_all_impl(fd, str, ec); 9134f67a909SLouis Dionne } 9144f67a909SLouis Dionne } 9154f67a909SLouis Dionne 9164f67a909SLouis Dionne // Then, remove the now-empty directory itself. 9174f67a909SLouis Dionne if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) { 9184f67a909SLouis Dionne ec = detail::capture_errno(); 9194f67a909SLouis Dionne return count; 9204f67a909SLouis Dionne } 9214f67a909SLouis Dionne 9224f67a909SLouis Dionne return count + 1; // the contents of the directory + the directory itself 9234f67a909SLouis Dionne } 9244f67a909SLouis Dionne 9254f67a909SLouis Dionne ec = detail::capture_errno(); 9264f67a909SLouis Dionne 9274f67a909SLouis Dionne // If we failed to open `p` because it didn't exist, it's not an 9284f67a909SLouis Dionne // error -- it might have moved or have been deleted already. 9294f67a909SLouis Dionne if (ec == errc::no_such_file_or_directory) { 9304f67a909SLouis Dionne ec.clear(); 9314f67a909SLouis Dionne return 0; 9324f67a909SLouis Dionne } 9334f67a909SLouis Dionne 9344f67a909SLouis Dionne // If opening `p` failed because it wasn't a directory, remove it as 9354f67a909SLouis Dionne // a normal file instead. Note that `openat()` can return either ENOTDIR 9364a39d089SMark Johnston // or ELOOP depending on the exact reason of the failure. On FreeBSD it 9374a39d089SMark Johnston // may return EMLINK instead of ELOOP, contradicting POSIX. 9384a39d089SMark Johnston if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) { 9394f67a909SLouis Dionne ec.clear(); 9404f67a909SLouis Dionne if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) { 9414f67a909SLouis Dionne ec = detail::capture_errno(); 9424f67a909SLouis Dionne return 0; 9434f67a909SLouis Dionne } 9444f67a909SLouis Dionne return 1; 9454f67a909SLouis Dionne } 9464f67a909SLouis Dionne 9474f67a909SLouis Dionne // Otherwise, it's a real error -- we don't remove anything. 9484f67a909SLouis Dionne return 0; 9494f67a909SLouis Dionne } 9504f67a909SLouis Dionne 951953af0e7SLouis Dionne } // namespace 9524f67a909SLouis Dionne 9534f67a909SLouis Dionne uintmax_t __remove_all(const path& p, error_code* ec) { 9544f67a909SLouis Dionne ErrorHandler<uintmax_t> err("remove_all", ec, &p); 9554f67a909SLouis Dionne error_code mec; 9564f67a909SLouis Dionne uintmax_t count = remove_all_impl(AT_FDCWD, p, mec); 9574f67a909SLouis Dionne if (mec) 9584f67a909SLouis Dionne return err.report(mec); 9594f67a909SLouis Dionne return count; 9604f67a909SLouis Dionne } 9614f67a909SLouis Dionne 9624f67a909SLouis Dionne #endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR 9634f67a909SLouis Dionne 964998a5c88SEric Fiselier void __rename(const path& from, const path& to, error_code* ec) { 965998a5c88SEric Fiselier ErrorHandler<void> err("rename", ec, &from, &to); 966efec3cc6SMartin Storsjö if (detail::rename(from.c_str(), to.c_str()) == -1) 967*2b26ee6eSJames Y Knight err.report(detail::get_last_error()); 968998a5c88SEric Fiselier } 969998a5c88SEric Fiselier 970998a5c88SEric Fiselier void __resize_file(const path& p, uintmax_t size, error_code* ec) { 971998a5c88SEric Fiselier ErrorHandler<void> err("resize_file", ec, &p); 972efec3cc6SMartin Storsjö if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1) 973*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 974998a5c88SEric Fiselier } 975998a5c88SEric Fiselier 976998a5c88SEric Fiselier space_info __space(const path& p, error_code* ec) { 977998a5c88SEric Fiselier ErrorHandler<void> err("space", ec, &p); 978998a5c88SEric Fiselier space_info si; 979a3cc9965SMartin Storsjö detail::StatVFS m_svfs = {}; 980a3cc9965SMartin Storsjö if (detail::statvfs(p.c_str(), &m_svfs) == -1) { 981*2b26ee6eSJames Y Knight err.report(detail::get_last_error()); 982998a5c88SEric Fiselier si.capacity = si.free = si.available = static_cast<uintmax_t>(-1); 983998a5c88SEric Fiselier return si; 984998a5c88SEric Fiselier } 985998a5c88SEric Fiselier // Multiply with overflow checking. 986998a5c88SEric Fiselier auto do_mult = [&](uintmax_t& out, uintmax_t other) { 987998a5c88SEric Fiselier out = other * m_svfs.f_frsize; 988998a5c88SEric Fiselier if (other == 0 || out / other != m_svfs.f_frsize) 989998a5c88SEric Fiselier out = static_cast<uintmax_t>(-1); 990998a5c88SEric Fiselier }; 991998a5c88SEric Fiselier do_mult(si.capacity, m_svfs.f_blocks); 992998a5c88SEric Fiselier do_mult(si.free, m_svfs.f_bfree); 993998a5c88SEric Fiselier do_mult(si.available, m_svfs.f_bavail); 994998a5c88SEric Fiselier return si; 995998a5c88SEric Fiselier } 996998a5c88SEric Fiselier 9979783f28cSLouis Dionne file_status __status(const path& p, error_code* ec) { return detail::posix_stat(p, ec); } 998998a5c88SEric Fiselier 9999783f28cSLouis Dionne file_status __symlink_status(const path& p, error_code* ec) { return detail::posix_lstat(p, ec); } 1000998a5c88SEric Fiselier 1001998a5c88SEric Fiselier path __temp_directory_path(error_code* ec) { 1002998a5c88SEric Fiselier ErrorHandler<path> err("temp_directory_path", ec); 1003998a5c88SEric Fiselier 1004d4f4e723SMartin Storsjö #if defined(_LIBCPP_WIN32API) 1005d4f4e723SMartin Storsjö wchar_t buf[MAX_PATH]; 1006d4f4e723SMartin Storsjö DWORD retval = GetTempPathW(MAX_PATH, buf); 1007d4f4e723SMartin Storsjö if (!retval) 1008*2b26ee6eSJames Y Knight return err.report(detail::get_last_error()); 1009d4f4e723SMartin Storsjö if (retval > MAX_PATH) 1010d4f4e723SMartin Storsjö return err.report(errc::filename_too_long); 1011d4f4e723SMartin Storsjö // GetTempPathW returns a path with a trailing slash, which we 1012d4f4e723SMartin Storsjö // shouldn't include for consistency. 1013d4f4e723SMartin Storsjö if (buf[retval - 1] == L'\\') 1014d4f4e723SMartin Storsjö buf[retval - 1] = L'\0'; 1015d4f4e723SMartin Storsjö path p(buf); 1016d4f4e723SMartin Storsjö #else 1017998a5c88SEric Fiselier const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; 1018998a5c88SEric Fiselier const char* ret = nullptr; 1019998a5c88SEric Fiselier 1020998a5c88SEric Fiselier for (auto& ep : env_paths) 1021998a5c88SEric Fiselier if ((ret = getenv(ep))) 1022998a5c88SEric Fiselier break; 10231da06804SRyan Prichard if (ret == nullptr) { 10241da06804SRyan Prichard # if defined(__ANDROID__) 10251da06804SRyan Prichard ret = "/data/local/tmp"; 10261da06804SRyan Prichard # else 1027998a5c88SEric Fiselier ret = "/tmp"; 10281da06804SRyan Prichard # endif 10291da06804SRyan Prichard } 1030998a5c88SEric Fiselier 1031998a5c88SEric Fiselier path p(ret); 1032d4f4e723SMartin Storsjö #endif 1033998a5c88SEric Fiselier error_code m_ec; 1034998a5c88SEric Fiselier file_status st = detail::posix_stat(p, &m_ec); 1035998a5c88SEric Fiselier if (!status_known(st)) 10360aa637b2SArthur O'Dwyer return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str()); 1037998a5c88SEric Fiselier 1038998a5c88SEric Fiselier if (!exists(st) || !is_directory(st)) 10399783f28cSLouis Dionne return err.report(errc::not_a_directory, "path " PATH_CSTR_FMT " is not a directory", p.c_str()); 1040998a5c88SEric Fiselier 1041998a5c88SEric Fiselier return p; 1042998a5c88SEric Fiselier } 1043998a5c88SEric Fiselier 1044998a5c88SEric Fiselier path __weakly_canonical(const path& p, error_code* ec) { 1045998a5c88SEric Fiselier ErrorHandler<path> err("weakly_canonical", ec, &p); 1046998a5c88SEric Fiselier 1047998a5c88SEric Fiselier if (p.empty()) 1048998a5c88SEric Fiselier return __canonical("", ec); 1049998a5c88SEric Fiselier 1050998a5c88SEric Fiselier path result; 1051998a5c88SEric Fiselier path tmp; 1052998a5c88SEric Fiselier tmp.__reserve(p.native().size()); 1053998a5c88SEric Fiselier auto PP = PathParser::CreateEnd(p.native()); 1054998a5c88SEric Fiselier --PP; 1055998a5c88SEric Fiselier vector<string_view_t> DNEParts; 1056998a5c88SEric Fiselier 105711399028SRodrigo Salazar error_code m_ec; 1058731db06aSNikolas Klauser while (PP.State_ != PathParser::PS_BeforeBegin) { 1059998a5c88SEric Fiselier tmp.assign(createView(p.native().data(), &PP.RawEntry.back())); 1060998a5c88SEric Fiselier file_status st = __status(tmp, &m_ec); 1061998a5c88SEric Fiselier if (!status_known(st)) { 1062998a5c88SEric Fiselier return err.report(m_ec); 1063998a5c88SEric Fiselier } else if (exists(st)) { 106411399028SRodrigo Salazar result = __canonical(tmp, &m_ec); 106511399028SRodrigo Salazar if (m_ec) { 106611399028SRodrigo Salazar return err.report(m_ec); 106711399028SRodrigo Salazar } 1068998a5c88SEric Fiselier break; 1069998a5c88SEric Fiselier } 1070998a5c88SEric Fiselier DNEParts.push_back(*PP); 1071998a5c88SEric Fiselier --PP; 1072998a5c88SEric Fiselier } 1073731db06aSNikolas Klauser if (PP.State_ == PathParser::PS_BeforeBegin) { 107411399028SRodrigo Salazar result = __canonical("", &m_ec); 107511399028SRodrigo Salazar if (m_ec) { 107611399028SRodrigo Salazar return err.report(m_ec); 107711399028SRodrigo Salazar } 107811399028SRodrigo Salazar } 1079998a5c88SEric Fiselier if (DNEParts.empty()) 1080998a5c88SEric Fiselier return result; 1081998a5c88SEric Fiselier for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It) 1082998a5c88SEric Fiselier result /= *It; 1083998a5c88SEric Fiselier return result.lexically_normal(); 1084998a5c88SEric Fiselier } 1085998a5c88SEric Fiselier 1086998a5c88SEric Fiselier _LIBCPP_END_NAMESPACE_FILESYSTEM 1087