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