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