1 //===--------------------- filesystem/ops.cpp -----------------------------===//
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 "filesystem"
10 #include "array"
11 #include "iterator"
12 #include "fstream"
13 #include "random" /* for unique_path */
14 #include "string_view"
15 #include "type_traits"
16 #include "vector"
17 #include "cstdlib"
18 #include "climits"
19 
20 #include "filesystem_common.h"
21 
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <sys/statvfs.h>
25 #include <time.h>
26 #include <fcntl.h> /* values for fchmodat */
27 
28 #if defined(__linux__)
29 #include <linux/version.h>
30 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
31 #include <sys/sendfile.h>
32 #define _LIBCPP_USE_SENDFILE
33 #endif
34 #elif defined(__APPLE__) || __has_include(<copyfile.h>)
35 #include <copyfile.h>
36 #define _LIBCPP_USE_COPYFILE
37 #endif
38 
39 #if !defined(__APPLE__)
40 #define _LIBCPP_USE_CLOCK_GETTIME
41 #endif
42 
43 #if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
44 #include <sys/time.h> // for gettimeofday and timeval
45 #endif                // !defined(CLOCK_REALTIME)
46 
47 #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
48 #pragma comment(lib, "rt")
49 #endif
50 
51 #if defined(_LIBCPP_COMPILER_GCC)
52 #if _GNUC_VER < 500
53 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
54 #endif
55 #endif
56 
57 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
58 
59 namespace {
60 namespace parser {
61 
62 using string_view_t = path::__string_view;
63 using string_view_pair = pair<string_view_t, string_view_t>;
64 using PosPtr = path::value_type const*;
65 
66 struct PathParser {
67   enum ParserState : unsigned char {
68     // Zero is a special sentinel value used by default constructed iterators.
69     PS_BeforeBegin = path::iterator::_BeforeBegin,
70     PS_InRootName = path::iterator::_InRootName,
71     PS_InRootDir = path::iterator::_InRootDir,
72     PS_InFilenames = path::iterator::_InFilenames,
73     PS_InTrailingSep = path::iterator::_InTrailingSep,
74     PS_AtEnd = path::iterator::_AtEnd
75   };
76 
77   const string_view_t Path;
78   string_view_t RawEntry;
79   ParserState State;
80 
81 private:
82   PathParser(string_view_t P, ParserState State) noexcept : Path(P),
83                                                             State(State) {}
84 
85 public:
86   PathParser(string_view_t P, string_view_t E, unsigned char S)
87       : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
88     // S cannot be '0' or PS_BeforeBegin.
89   }
90 
91   static PathParser CreateBegin(string_view_t P) noexcept {
92     PathParser PP(P, PS_BeforeBegin);
93     PP.increment();
94     return PP;
95   }
96 
97   static PathParser CreateEnd(string_view_t P) noexcept {
98     PathParser PP(P, PS_AtEnd);
99     return PP;
100   }
101 
102   PosPtr peek() const noexcept {
103     auto TkEnd = getNextTokenStartPos();
104     auto End = getAfterBack();
105     return TkEnd == End ? nullptr : TkEnd;
106   }
107 
108   void increment() noexcept {
109     const PosPtr End = getAfterBack();
110     const PosPtr Start = getNextTokenStartPos();
111     if (Start == End)
112       return makeState(PS_AtEnd);
113 
114     switch (State) {
115     case PS_BeforeBegin: {
116       PosPtr TkEnd = consumeSeparator(Start, End);
117       if (TkEnd)
118         return makeState(PS_InRootDir, Start, TkEnd);
119       else
120         return makeState(PS_InFilenames, Start, consumeName(Start, End));
121     }
122     case PS_InRootDir:
123       return makeState(PS_InFilenames, Start, consumeName(Start, End));
124 
125     case PS_InFilenames: {
126       PosPtr SepEnd = consumeSeparator(Start, End);
127       if (SepEnd != End) {
128         PosPtr TkEnd = consumeName(SepEnd, End);
129         if (TkEnd)
130           return makeState(PS_InFilenames, SepEnd, TkEnd);
131       }
132       return makeState(PS_InTrailingSep, Start, SepEnd);
133     }
134 
135     case PS_InTrailingSep:
136       return makeState(PS_AtEnd);
137 
138     case PS_InRootName:
139     case PS_AtEnd:
140       _LIBCPP_UNREACHABLE();
141     }
142   }
143 
144   void decrement() noexcept {
145     const PosPtr REnd = getBeforeFront();
146     const PosPtr RStart = getCurrentTokenStartPos() - 1;
147     if (RStart == REnd) // we're decrementing the begin
148       return makeState(PS_BeforeBegin);
149 
150     switch (State) {
151     case PS_AtEnd: {
152       // Try to consume a trailing separator or root directory first.
153       if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
154         if (SepEnd == REnd)
155           return makeState(PS_InRootDir, Path.data(), RStart + 1);
156         return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
157       } else {
158         PosPtr TkStart = consumeName(RStart, REnd);
159         return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
160       }
161     }
162     case PS_InTrailingSep:
163       return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
164                        RStart + 1);
165     case PS_InFilenames: {
166       PosPtr SepEnd = consumeSeparator(RStart, REnd);
167       if (SepEnd == REnd)
168         return makeState(PS_InRootDir, Path.data(), RStart + 1);
169       PosPtr TkEnd = consumeName(SepEnd, REnd);
170       return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
171     }
172     case PS_InRootDir:
173       // return makeState(PS_InRootName, Path.data(), RStart + 1);
174     case PS_InRootName:
175     case PS_BeforeBegin:
176       _LIBCPP_UNREACHABLE();
177     }
178   }
179 
180   /// \brief Return a view with the "preferred representation" of the current
181   ///   element. For example trailing separators are represented as a '.'
182   string_view_t operator*() const noexcept {
183     switch (State) {
184     case PS_BeforeBegin:
185     case PS_AtEnd:
186       return "";
187     case PS_InRootDir:
188       return "/";
189     case PS_InTrailingSep:
190       return "";
191     case PS_InRootName:
192     case PS_InFilenames:
193       return RawEntry;
194     }
195     _LIBCPP_UNREACHABLE();
196   }
197 
198   explicit operator bool() const noexcept {
199     return State != PS_BeforeBegin && State != PS_AtEnd;
200   }
201 
202   PathParser& operator++() noexcept {
203     increment();
204     return *this;
205   }
206 
207   PathParser& operator--() noexcept {
208     decrement();
209     return *this;
210   }
211 
212   bool atEnd() const noexcept {
213     return State == PS_AtEnd;
214   }
215 
216   bool inRootDir() const noexcept {
217     return State == PS_InRootDir;
218   }
219 
220   bool inRootName() const noexcept {
221     return State == PS_InRootName;
222   }
223 
224   bool inRootPath() const noexcept {
225     return inRootName() || inRootDir();
226   }
227 
228 private:
229   void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
230     State = NewState;
231     RawEntry = string_view_t(Start, End - Start);
232   }
233   void makeState(ParserState NewState) noexcept {
234     State = NewState;
235     RawEntry = {};
236   }
237 
238   PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
239 
240   PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
241 
242   /// \brief Return a pointer to the first character after the currently
243   ///   lexed element.
244   PosPtr getNextTokenStartPos() const noexcept {
245     switch (State) {
246     case PS_BeforeBegin:
247       return Path.data();
248     case PS_InRootName:
249     case PS_InRootDir:
250     case PS_InFilenames:
251       return &RawEntry.back() + 1;
252     case PS_InTrailingSep:
253     case PS_AtEnd:
254       return getAfterBack();
255     }
256     _LIBCPP_UNREACHABLE();
257   }
258 
259   /// \brief Return a pointer to the first character in the currently lexed
260   ///   element.
261   PosPtr getCurrentTokenStartPos() const noexcept {
262     switch (State) {
263     case PS_BeforeBegin:
264     case PS_InRootName:
265       return &Path.front();
266     case PS_InRootDir:
267     case PS_InFilenames:
268     case PS_InTrailingSep:
269       return &RawEntry.front();
270     case PS_AtEnd:
271       return &Path.back() + 1;
272     }
273     _LIBCPP_UNREACHABLE();
274   }
275 
276   PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
277     if (P == End || *P != '/')
278       return nullptr;
279     const int Inc = P < End ? 1 : -1;
280     P += Inc;
281     while (P != End && *P == '/')
282       P += Inc;
283     return P;
284   }
285 
286   PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
287     if (P == End || *P == '/')
288       return nullptr;
289     const int Inc = P < End ? 1 : -1;
290     P += Inc;
291     while (P != End && *P != '/')
292       P += Inc;
293     return P;
294   }
295 };
296 
297 string_view_pair separate_filename(string_view_t const& s) {
298   if (s == "." || s == ".." || s.empty())
299     return string_view_pair{s, ""};
300   auto pos = s.find_last_of('.');
301   if (pos == string_view_t::npos || pos == 0)
302     return string_view_pair{s, string_view_t{}};
303   return string_view_pair{s.substr(0, pos), s.substr(pos)};
304 }
305 
306 string_view_t createView(PosPtr S, PosPtr E) noexcept {
307   return {S, static_cast<size_t>(E - S) + 1};
308 }
309 
310 } // namespace parser
311 } // namespace
312 
313 //                       POSIX HELPERS
314 
315 namespace detail {
316 namespace {
317 
318 using value_type = path::value_type;
319 using string_type = path::string_type;
320 
321 struct FileDescriptor {
322   const path& name;
323   int fd = -1;
324   StatT m_stat;
325   file_status m_status;
326 
327   template <class... Args>
328   static FileDescriptor create(const path* p, error_code& ec, Args... args) {
329     ec.clear();
330     int fd;
331     if ((fd = ::open(p->c_str(), args...)) == -1) {
332       ec = capture_errno();
333       return FileDescriptor{p};
334     }
335     return FileDescriptor(p, fd);
336   }
337 
338   template <class... Args>
339   static FileDescriptor create_with_status(const path* p, error_code& ec,
340                                            Args... args) {
341     FileDescriptor fd = create(p, ec, args...);
342     if (!ec)
343       fd.refresh_status(ec);
344 
345     return fd;
346   }
347 
348   file_status get_status() const { return m_status; }
349   StatT const& get_stat() const { return m_stat; }
350 
351   bool status_known() const { return _VSTD_FS::status_known(m_status); }
352 
353   file_status refresh_status(error_code& ec);
354 
355   void close() noexcept {
356     if (fd != -1)
357       ::close(fd);
358     fd = -1;
359   }
360 
361   FileDescriptor(FileDescriptor&& other)
362       : name(other.name), fd(other.fd), m_stat(other.m_stat),
363         m_status(other.m_status) {
364     other.fd = -1;
365     other.m_status = file_status{};
366   }
367 
368   ~FileDescriptor() { close(); }
369 
370   FileDescriptor(FileDescriptor const&) = delete;
371   FileDescriptor& operator=(FileDescriptor const&) = delete;
372 
373 private:
374   explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {}
375 };
376 
377 perms posix_get_perms(const StatT& st) noexcept {
378   return static_cast<perms>(st.st_mode) & perms::mask;
379 }
380 
381 ::mode_t posix_convert_perms(perms prms) {
382   return static_cast< ::mode_t>(prms & perms::mask);
383 }
384 
385 file_status create_file_status(error_code& m_ec, path const& p,
386                                const StatT& path_stat, error_code* ec) {
387   if (ec)
388     *ec = m_ec;
389   if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
390     return file_status(file_type::not_found);
391   } else if (m_ec) {
392     ErrorHandler<void> err("posix_stat", ec, &p);
393     err.report(m_ec, "failed to determine attributes for the specified path");
394     return file_status(file_type::none);
395   }
396   // else
397 
398   file_status fs_tmp;
399   auto const mode = path_stat.st_mode;
400   if (S_ISLNK(mode))
401     fs_tmp.type(file_type::symlink);
402   else if (S_ISREG(mode))
403     fs_tmp.type(file_type::regular);
404   else if (S_ISDIR(mode))
405     fs_tmp.type(file_type::directory);
406   else if (S_ISBLK(mode))
407     fs_tmp.type(file_type::block);
408   else if (S_ISCHR(mode))
409     fs_tmp.type(file_type::character);
410   else if (S_ISFIFO(mode))
411     fs_tmp.type(file_type::fifo);
412   else if (S_ISSOCK(mode))
413     fs_tmp.type(file_type::socket);
414   else
415     fs_tmp.type(file_type::unknown);
416 
417   fs_tmp.permissions(detail::posix_get_perms(path_stat));
418   return fs_tmp;
419 }
420 
421 file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
422   error_code m_ec;
423   if (::stat(p.c_str(), &path_stat) == -1)
424     m_ec = detail::capture_errno();
425   return create_file_status(m_ec, p, path_stat, ec);
426 }
427 
428 file_status posix_stat(path const& p, error_code* ec) {
429   StatT path_stat;
430   return posix_stat(p, path_stat, ec);
431 }
432 
433 file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
434   error_code m_ec;
435   if (::lstat(p.c_str(), &path_stat) == -1)
436     m_ec = detail::capture_errno();
437   return create_file_status(m_ec, p, path_stat, ec);
438 }
439 
440 file_status posix_lstat(path const& p, error_code* ec) {
441   StatT path_stat;
442   return posix_lstat(p, path_stat, ec);
443 }
444 
445 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
446 bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
447   if (::ftruncate(fd.fd, to_size) == -1) {
448     ec = capture_errno();
449     return true;
450   }
451   ec.clear();
452   return false;
453 }
454 
455 bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
456   if (::fchmod(fd.fd, st.st_mode) == -1) {
457     ec = capture_errno();
458     return true;
459   }
460   ec.clear();
461   return false;
462 }
463 
464 bool stat_equivalent(const StatT& st1, const StatT& st2) {
465   return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
466 }
467 
468 file_status FileDescriptor::refresh_status(error_code& ec) {
469   // FD must be open and good.
470   m_status = file_status{};
471   m_stat = {};
472   error_code m_ec;
473   if (::fstat(fd, &m_stat) == -1)
474     m_ec = capture_errno();
475   m_status = create_file_status(m_ec, name, m_stat, &ec);
476   return m_status;
477 }
478 } // namespace
479 } // end namespace detail
480 
481 using detail::capture_errno;
482 using detail::ErrorHandler;
483 using detail::StatT;
484 using detail::TimeSpec;
485 using parser::createView;
486 using parser::PathParser;
487 using parser::string_view_t;
488 
489 const bool _FilesystemClock::is_steady;
490 
491 _FilesystemClock::time_point _FilesystemClock::now() noexcept {
492   typedef chrono::duration<rep> __secs;
493 #if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
494   typedef chrono::duration<rep, nano> __nsecs;
495   struct timespec tp;
496   if (0 != clock_gettime(CLOCK_REALTIME, &tp))
497     __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
498   return time_point(__secs(tp.tv_sec) +
499                     chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
500 #else
501   typedef chrono::duration<rep, micro> __microsecs;
502   timeval tv;
503   gettimeofday(&tv, 0);
504   return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
505 #endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
506 }
507 
508 filesystem_error::~filesystem_error() {}
509 
510 void filesystem_error::__create_what(int __num_paths) {
511   const char* derived_what = system_error::what();
512   __storage_->__what_ = [&]() -> string {
513     const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str();
514     const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str();
515     switch (__num_paths) {
516     default:
517       return detail::format_string("filesystem error: %s", derived_what);
518     case 1:
519       return detail::format_string("filesystem error: %s [%s]", derived_what,
520                                    p1);
521     case 2:
522       return detail::format_string("filesystem error: %s [%s] [%s]",
523                                    derived_what, p1, p2);
524     }
525   }();
526 }
527 
528 static path __do_absolute(const path& p, path* cwd, error_code* ec) {
529   if (ec)
530     ec->clear();
531   if (p.is_absolute())
532     return p;
533   *cwd = __current_path(ec);
534   if (ec && *ec)
535     return {};
536   return (*cwd) / p;
537 }
538 
539 path __absolute(const path& p, error_code* ec) {
540   path cwd;
541   return __do_absolute(p, &cwd, ec);
542 }
543 
544 path __canonical(path const& orig_p, error_code* ec) {
545   path cwd;
546   ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
547 
548   path p = __do_absolute(orig_p, &cwd, ec);
549 #if _POSIX_VERSION >= 200112
550   std::unique_ptr<char, decltype(&::free)>
551     hold(::realpath(p.c_str(), nullptr), &::free);
552   if (hold.get() == nullptr)
553     return err.report(capture_errno());
554   return {hold.get()};
555 #else
556   char buff[PATH_MAX + 1];
557   char* ret;
558   if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
559     return err.report(capture_errno());
560   return {ret};
561 #endif
562 }
563 
564 void __copy(const path& from, const path& to, copy_options options,
565             error_code* ec) {
566   ErrorHandler<void> err("copy", ec, &from, &to);
567 
568   const bool sym_status = bool(
569       options & (copy_options::create_symlinks | copy_options::skip_symlinks));
570 
571   const bool sym_status2 = bool(options & copy_options::copy_symlinks);
572 
573   error_code m_ec1;
574   StatT f_st = {};
575   const file_status f = sym_status || sym_status2
576                             ? detail::posix_lstat(from, f_st, &m_ec1)
577                             : detail::posix_stat(from, f_st, &m_ec1);
578   if (m_ec1)
579     return err.report(m_ec1);
580 
581   StatT t_st = {};
582   const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
583                                    : detail::posix_stat(to, t_st, &m_ec1);
584 
585   if (not status_known(t))
586     return err.report(m_ec1);
587 
588   if (!exists(f) || is_other(f) || is_other(t) ||
589       (is_directory(f) && is_regular_file(t)) ||
590       detail::stat_equivalent(f_st, t_st)) {
591     return err.report(errc::function_not_supported);
592   }
593 
594   if (ec)
595     ec->clear();
596 
597   if (is_symlink(f)) {
598     if (bool(copy_options::skip_symlinks & options)) {
599       // do nothing
600     } else if (not exists(t)) {
601       __copy_symlink(from, to, ec);
602     } else {
603       return err.report(errc::file_exists);
604     }
605     return;
606   } else if (is_regular_file(f)) {
607     if (bool(copy_options::directories_only & options)) {
608       // do nothing
609     } else if (bool(copy_options::create_symlinks & options)) {
610       __create_symlink(from, to, ec);
611     } else if (bool(copy_options::create_hard_links & options)) {
612       __create_hard_link(from, to, ec);
613     } else if (is_directory(t)) {
614       __copy_file(from, to / from.filename(), options, ec);
615     } else {
616       __copy_file(from, to, options, ec);
617     }
618     return;
619   } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
620     return err.report(errc::is_a_directory);
621   } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
622                                  copy_options::none == options)) {
623 
624     if (!exists(t)) {
625       // create directory to with attributes from 'from'.
626       __create_directory(to, from, ec);
627       if (ec && *ec) {
628         return;
629       }
630     }
631     directory_iterator it =
632         ec ? directory_iterator(from, *ec) : directory_iterator(from);
633     if (ec && *ec) {
634       return;
635     }
636     error_code m_ec2;
637     for (; it != directory_iterator(); it.increment(m_ec2)) {
638       if (m_ec2) {
639         return err.report(m_ec2);
640       }
641       __copy(it->path(), to / it->path().filename(),
642              options | copy_options::__in_recursive_copy, ec);
643       if (ec && *ec) {
644         return;
645       }
646     }
647   }
648 }
649 
650 namespace detail {
651 namespace {
652 
653 #ifdef _LIBCPP_USE_SENDFILE
654 bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
655                              error_code& ec) {
656 
657   size_t count = read_fd.get_stat().st_size;
658   do {
659     ssize_t res;
660     if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
661       ec = capture_errno();
662       return false;
663     }
664     count -= res;
665   } while (count > 0);
666 
667   ec.clear();
668 
669   return true;
670 }
671 #elif defined(_LIBCPP_USE_COPYFILE)
672 bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
673                              error_code& ec) {
674   struct CopyFileState {
675     copyfile_state_t state;
676     CopyFileState() { state = copyfile_state_alloc(); }
677     ~CopyFileState() { copyfile_state_free(state); }
678 
679   private:
680     CopyFileState(CopyFileState const&) = delete;
681     CopyFileState& operator=(CopyFileState const&) = delete;
682   };
683 
684   CopyFileState cfs;
685   if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
686     ec = capture_errno();
687     return false;
688   }
689 
690   ec.clear();
691   return true;
692 }
693 #endif
694 
695 // Note: This function isn't guarded by ifdef's even though it may be unused
696 // in order to assure it still compiles.
697 __attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd,
698                                                     FileDescriptor& write_fd,
699                                                     error_code& ec) {
700   ifstream in;
701   in.__open(read_fd.fd, ios::binary);
702   if (!in.is_open()) {
703     // This assumes that __open didn't reset the error code.
704     ec = capture_errno();
705     return false;
706   }
707   ofstream out;
708   out.__open(write_fd.fd, ios::binary);
709   if (!out.is_open()) {
710     ec = capture_errno();
711     return false;
712   }
713 
714   if (in.good() && out.good()) {
715     using InIt = istreambuf_iterator<char>;
716     using OutIt = ostreambuf_iterator<char>;
717     InIt bin(in);
718     InIt ein;
719     OutIt bout(out);
720     copy(bin, ein, bout);
721   }
722   if (out.fail() || in.fail()) {
723     ec = make_error_code(errc::io_error);
724     return false;
725   }
726 
727   ec.clear();
728   return true;
729 }
730 
731 bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) {
732 #if defined(_LIBCPP_USE_SENDFILE)
733   return copy_file_impl_sendfile(from, to, ec);
734 #elif defined(_LIBCPP_USE_COPYFILE)
735   return copy_file_impl_copyfile(from, to, ec);
736 #else
737   return copy_file_impl_default(from, to, ec);
738 #endif
739 }
740 
741 } // namespace
742 } // namespace detail
743 
744 bool __copy_file(const path& from, const path& to, copy_options options,
745                  error_code* ec) {
746   using detail::FileDescriptor;
747   ErrorHandler<bool> err("copy_file", ec, &to, &from);
748 
749   error_code m_ec;
750   FileDescriptor from_fd =
751       FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
752   if (m_ec)
753     return err.report(m_ec);
754 
755   auto from_st = from_fd.get_status();
756   StatT const& from_stat = from_fd.get_stat();
757   if (!is_regular_file(from_st)) {
758     if (not m_ec)
759       m_ec = make_error_code(errc::not_supported);
760     return err.report(m_ec);
761   }
762 
763   const bool skip_existing = bool(copy_options::skip_existing & options);
764   const bool update_existing = bool(copy_options::update_existing & options);
765   const bool overwrite_existing =
766       bool(copy_options::overwrite_existing & options);
767 
768   StatT to_stat_path;
769   file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
770   if (!status_known(to_st))
771     return err.report(m_ec);
772 
773   const bool to_exists = exists(to_st);
774   if (to_exists && !is_regular_file(to_st))
775     return err.report(errc::not_supported);
776 
777   if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
778     return err.report(errc::file_exists);
779 
780   if (to_exists && skip_existing)
781     return false;
782 
783   bool ShouldCopy = [&]() {
784     if (to_exists && update_existing) {
785       auto from_time = detail::extract_mtime(from_stat);
786       auto to_time = detail::extract_mtime(to_stat_path);
787       if (from_time.tv_sec < to_time.tv_sec)
788         return false;
789       if (from_time.tv_sec == to_time.tv_sec &&
790           from_time.tv_nsec <= to_time.tv_nsec)
791         return false;
792       return true;
793     }
794     if (!to_exists || overwrite_existing)
795       return true;
796     return err.report(errc::file_exists);
797   }();
798   if (!ShouldCopy)
799     return false;
800 
801   // Don't truncate right away. We may not be opening the file we originally
802   // looked at; we'll check this later.
803   int to_open_flags = O_WRONLY;
804   if (!to_exists)
805     to_open_flags |= O_CREAT;
806   FileDescriptor to_fd = FileDescriptor::create_with_status(
807       &to, m_ec, to_open_flags, from_stat.st_mode);
808   if (m_ec)
809     return err.report(m_ec);
810 
811   if (to_exists) {
812     // Check that the file we initially stat'ed is equivalent to the one
813     // we opened.
814     // FIXME: report this better.
815     if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
816       return err.report(errc::bad_file_descriptor);
817 
818     // Set the permissions and truncate the file we opened.
819     if (detail::posix_fchmod(to_fd, from_stat, m_ec))
820       return err.report(m_ec);
821     if (detail::posix_ftruncate(to_fd, 0, m_ec))
822       return err.report(m_ec);
823   }
824 
825   if (!copy_file_impl(from_fd, to_fd, m_ec)) {
826     // FIXME: Remove the dest file if we failed, and it didn't exist previously.
827     return err.report(m_ec);
828   }
829 
830   return true;
831 }
832 
833 void __copy_symlink(const path& existing_symlink, const path& new_symlink,
834                     error_code* ec) {
835   const path real_path(__read_symlink(existing_symlink, ec));
836   if (ec && *ec) {
837     return;
838   }
839   // NOTE: proposal says you should detect if you should call
840   // create_symlink or create_directory_symlink. I don't think this
841   // is needed with POSIX
842   __create_symlink(real_path, new_symlink, ec);
843 }
844 
845 bool __create_directories(const path& p, error_code* ec) {
846   ErrorHandler<bool> err("create_directories", ec, &p);
847 
848   error_code m_ec;
849   auto const st = detail::posix_stat(p, &m_ec);
850   if (!status_known(st))
851     return err.report(m_ec);
852   else if (is_directory(st))
853     return false;
854   else if (exists(st))
855     return err.report(errc::file_exists);
856 
857   const path parent = p.parent_path();
858   if (!parent.empty()) {
859     const file_status parent_st = status(parent, m_ec);
860     if (not status_known(parent_st))
861       return err.report(m_ec);
862     if (not exists(parent_st)) {
863       __create_directories(parent, ec);
864       if (ec && *ec) {
865         return false;
866       }
867     }
868   }
869   return __create_directory(p, ec);
870 }
871 
872 bool __create_directory(const path& p, error_code* ec) {
873   ErrorHandler<bool> err("create_directory", ec, &p);
874 
875   if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
876     return true;
877   if (errno != EEXIST)
878     err.report(capture_errno());
879   return false;
880 }
881 
882 bool __create_directory(path const& p, path const& attributes, error_code* ec) {
883   ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
884 
885   StatT attr_stat;
886   error_code mec;
887   auto st = detail::posix_stat(attributes, attr_stat, &mec);
888   if (!status_known(st))
889     return err.report(mec);
890   if (!is_directory(st))
891     return err.report(errc::not_a_directory,
892                       "the specified attribute path is invalid");
893 
894   if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
895     return true;
896   if (errno != EEXIST)
897     err.report(capture_errno());
898   return false;
899 }
900 
901 void __create_directory_symlink(path const& from, path const& to,
902                                 error_code* ec) {
903   ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
904   if (::symlink(from.c_str(), to.c_str()) != 0)
905     return err.report(capture_errno());
906 }
907 
908 void __create_hard_link(const path& from, const path& to, error_code* ec) {
909   ErrorHandler<void> err("create_hard_link", ec, &from, &to);
910   if (::link(from.c_str(), to.c_str()) == -1)
911     return err.report(capture_errno());
912 }
913 
914 void __create_symlink(path const& from, path const& to, error_code* ec) {
915   ErrorHandler<void> err("create_symlink", ec, &from, &to);
916   if (::symlink(from.c_str(), to.c_str()) == -1)
917     return err.report(capture_errno());
918 }
919 
920 path __current_path(error_code* ec) {
921   ErrorHandler<path> err("current_path", ec);
922 
923   auto size = ::pathconf(".", _PC_PATH_MAX);
924   _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
925 
926   auto buff = unique_ptr<char[]>(new char[size + 1]);
927   char* ret;
928   if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
929     return err.report(capture_errno(), "call to getcwd failed");
930 
931   return {buff.get()};
932 }
933 
934 void __current_path(const path& p, error_code* ec) {
935   ErrorHandler<void> err("current_path", ec, &p);
936   if (::chdir(p.c_str()) == -1)
937     err.report(capture_errno());
938 }
939 
940 bool __equivalent(const path& p1, const path& p2, error_code* ec) {
941   ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
942 
943   error_code ec1, ec2;
944   StatT st1 = {}, st2 = {};
945   auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
946   if (!exists(s1))
947     return err.report(errc::not_supported);
948   auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
949   if (!exists(s2))
950     return err.report(errc::not_supported);
951 
952   return detail::stat_equivalent(st1, st2);
953 }
954 
955 uintmax_t __file_size(const path& p, error_code* ec) {
956   ErrorHandler<uintmax_t> err("file_size", ec, &p);
957 
958   error_code m_ec;
959   StatT st;
960   file_status fst = detail::posix_stat(p, st, &m_ec);
961   if (!exists(fst) || !is_regular_file(fst)) {
962     errc error_kind =
963         is_directory(fst) ? errc::is_a_directory : errc::not_supported;
964     if (!m_ec)
965       m_ec = make_error_code(error_kind);
966     return err.report(m_ec);
967   }
968   // is_regular_file(p) == true
969   return static_cast<uintmax_t>(st.st_size);
970 }
971 
972 uintmax_t __hard_link_count(const path& p, error_code* ec) {
973   ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
974 
975   error_code m_ec;
976   StatT st;
977   detail::posix_stat(p, st, &m_ec);
978   if (m_ec)
979     return err.report(m_ec);
980   return static_cast<uintmax_t>(st.st_nlink);
981 }
982 
983 bool __fs_is_empty(const path& p, error_code* ec) {
984   ErrorHandler<bool> err("is_empty", ec, &p);
985 
986   error_code m_ec;
987   StatT pst;
988   auto st = detail::posix_stat(p, pst, &m_ec);
989   if (m_ec)
990     return err.report(m_ec);
991   else if (!is_directory(st) && !is_regular_file(st))
992     return err.report(errc::not_supported);
993   else if (is_directory(st)) {
994     auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
995     if (ec && *ec)
996       return false;
997     return it == directory_iterator{};
998   } else if (is_regular_file(st))
999     return static_cast<uintmax_t>(pst.st_size) == 0;
1000 
1001   _LIBCPP_UNREACHABLE();
1002 }
1003 
1004 static file_time_type __extract_last_write_time(const path& p, const StatT& st,
1005                                                 error_code* ec) {
1006   using detail::fs_time;
1007   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
1008 
1009   auto ts = detail::extract_mtime(st);
1010   if (!fs_time::is_representable(ts))
1011     return err.report(errc::value_too_large);
1012 
1013   return fs_time::convert_from_timespec(ts);
1014 }
1015 
1016 file_time_type __last_write_time(const path& p, error_code* ec) {
1017   using namespace chrono;
1018   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
1019 
1020   error_code m_ec;
1021   StatT st;
1022   detail::posix_stat(p, st, &m_ec);
1023   if (m_ec)
1024     return err.report(m_ec);
1025   return __extract_last_write_time(p, st, ec);
1026 }
1027 
1028 void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
1029   using detail::fs_time;
1030   ErrorHandler<void> err("last_write_time", ec, &p);
1031 
1032   error_code m_ec;
1033   array<TimeSpec, 2> tbuf;
1034 #if !defined(_LIBCPP_USE_UTIMENSAT)
1035   // This implementation has a race condition between determining the
1036   // last access time and attempting to set it to the same value using
1037   // ::utimes
1038   StatT st;
1039   file_status fst = detail::posix_stat(p, st, &m_ec);
1040   if (m_ec)
1041     return err.report(m_ec);
1042   tbuf[0] = detail::extract_atime(st);
1043 #else
1044   tbuf[0].tv_sec = 0;
1045   tbuf[0].tv_nsec = UTIME_OMIT;
1046 #endif
1047   if (!fs_time::convert_to_timespec(tbuf[1], new_time))
1048     return err.report(errc::value_too_large);
1049 
1050   detail::set_file_times(p, tbuf, m_ec);
1051   if (m_ec)
1052     return err.report(m_ec);
1053 }
1054 
1055 void __permissions(const path& p, perms prms, perm_options opts,
1056                    error_code* ec) {
1057   ErrorHandler<void> err("permissions", ec, &p);
1058 
1059   auto has_opt = [&](perm_options o) { return bool(o & opts); };
1060   const bool resolve_symlinks = !has_opt(perm_options::nofollow);
1061   const bool add_perms = has_opt(perm_options::add);
1062   const bool remove_perms = has_opt(perm_options::remove);
1063   _LIBCPP_ASSERT(
1064       (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
1065       "One and only one of the perm_options constants replace, add, or remove "
1066       "is present in opts");
1067 
1068   bool set_sym_perms = false;
1069   prms &= perms::mask;
1070   if (!resolve_symlinks || (add_perms || remove_perms)) {
1071     error_code m_ec;
1072     file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
1073                                       : detail::posix_lstat(p, &m_ec);
1074     set_sym_perms = is_symlink(st);
1075     if (m_ec)
1076       return err.report(m_ec);
1077     _LIBCPP_ASSERT(st.permissions() != perms::unknown,
1078                    "Permissions unexpectedly unknown");
1079     if (add_perms)
1080       prms |= st.permissions();
1081     else if (remove_perms)
1082       prms = st.permissions() & ~prms;
1083   }
1084   const auto real_perms = detail::posix_convert_perms(prms);
1085 
1086 #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
1087   const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
1088   if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
1089     return err.report(capture_errno());
1090   }
1091 #else
1092   if (set_sym_perms)
1093     return err.report(errc::operation_not_supported);
1094   if (::chmod(p.c_str(), real_perms) == -1) {
1095     return err.report(capture_errno());
1096   }
1097 #endif
1098 }
1099 
1100 path __read_symlink(const path& p, error_code* ec) {
1101   ErrorHandler<path> err("read_symlink", ec, &p);
1102 
1103 #ifdef PATH_MAX
1104   struct NullDeleter { void operator()(void*) const {} };
1105   const size_t size = PATH_MAX + 1;
1106   char stack_buff[size];
1107   auto buff = std::unique_ptr<char[], NullDeleter>(stack_buff);
1108 #else
1109   StatT sb;
1110   if (::lstat(p.c_str(), &sb) == -1) {
1111     return err.report(capture_errno());
1112   }
1113   const size_t size = sb.st_size + 1;
1114   auto buff = unique_ptr<char[]>(new char[size]);
1115 #endif
1116   ::ssize_t ret;
1117   if ((ret = ::readlink(p.c_str(), buff.get(), size)) == -1)
1118     return err.report(capture_errno());
1119   _LIBCPP_ASSERT(ret > 0, "TODO");
1120   if (static_cast<size_t>(ret) >= size)
1121     return err.report(errc::value_too_large);
1122   buff[ret] = 0;
1123   return {buff.get()};
1124 }
1125 
1126 bool __remove(const path& p, error_code* ec) {
1127   ErrorHandler<bool> err("remove", ec, &p);
1128   if (::remove(p.c_str()) == -1) {
1129     if (errno != ENOENT)
1130       err.report(capture_errno());
1131     return false;
1132   }
1133   return true;
1134 }
1135 
1136 namespace {
1137 
1138 uintmax_t remove_all_impl(path const& p, error_code& ec) {
1139   const auto npos = static_cast<uintmax_t>(-1);
1140   const file_status st = __symlink_status(p, &ec);
1141   if (ec)
1142     return npos;
1143   uintmax_t count = 1;
1144   if (is_directory(st)) {
1145     for (directory_iterator it(p, ec); !ec && it != directory_iterator();
1146          it.increment(ec)) {
1147       auto other_count = remove_all_impl(it->path(), ec);
1148       if (ec)
1149         return npos;
1150       count += other_count;
1151     }
1152     if (ec)
1153       return npos;
1154   }
1155   if (!__remove(p, &ec))
1156     return npos;
1157   return count;
1158 }
1159 
1160 } // end namespace
1161 
1162 uintmax_t __remove_all(const path& p, error_code* ec) {
1163   ErrorHandler<uintmax_t> err("remove_all", ec, &p);
1164 
1165   error_code mec;
1166   auto count = remove_all_impl(p, mec);
1167   if (mec) {
1168     if (mec == errc::no_such_file_or_directory)
1169       return 0;
1170     return err.report(mec);
1171   }
1172   return count;
1173 }
1174 
1175 void __rename(const path& from, const path& to, error_code* ec) {
1176   ErrorHandler<void> err("rename", ec, &from, &to);
1177   if (::rename(from.c_str(), to.c_str()) == -1)
1178     err.report(capture_errno());
1179 }
1180 
1181 void __resize_file(const path& p, uintmax_t size, error_code* ec) {
1182   ErrorHandler<void> err("resize_file", ec, &p);
1183   if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
1184     return err.report(capture_errno());
1185 }
1186 
1187 space_info __space(const path& p, error_code* ec) {
1188   ErrorHandler<void> err("space", ec, &p);
1189   space_info si;
1190   struct statvfs m_svfs = {};
1191   if (::statvfs(p.c_str(), &m_svfs) == -1) {
1192     err.report(capture_errno());
1193     si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
1194     return si;
1195   }
1196   // Multiply with overflow checking.
1197   auto do_mult = [&](uintmax_t& out, uintmax_t other) {
1198     out = other * m_svfs.f_frsize;
1199     if (other == 0 || out / other != m_svfs.f_frsize)
1200       out = static_cast<uintmax_t>(-1);
1201   };
1202   do_mult(si.capacity, m_svfs.f_blocks);
1203   do_mult(si.free, m_svfs.f_bfree);
1204   do_mult(si.available, m_svfs.f_bavail);
1205   return si;
1206 }
1207 
1208 file_status __status(const path& p, error_code* ec) {
1209   return detail::posix_stat(p, ec);
1210 }
1211 
1212 file_status __symlink_status(const path& p, error_code* ec) {
1213   return detail::posix_lstat(p, ec);
1214 }
1215 
1216 path __temp_directory_path(error_code* ec) {
1217   ErrorHandler<path> err("temp_directory_path", ec);
1218 
1219   const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
1220   const char* ret = nullptr;
1221 
1222   for (auto& ep : env_paths)
1223     if ((ret = getenv(ep)))
1224       break;
1225   if (ret == nullptr)
1226     ret = "/tmp";
1227 
1228   path p(ret);
1229   error_code m_ec;
1230   file_status st = detail::posix_stat(p, &m_ec);
1231   if (!status_known(st))
1232     return err.report(m_ec, "cannot access path \"%s\"", p);
1233 
1234   if (!exists(st) || !is_directory(st))
1235     return err.report(errc::not_a_directory, "path \"%s\" is not a directory",
1236                       p);
1237 
1238   return p;
1239 }
1240 
1241 path __weakly_canonical(const path& p, error_code* ec) {
1242   ErrorHandler<path> err("weakly_canonical", ec, &p);
1243 
1244   if (p.empty())
1245     return __canonical("", ec);
1246 
1247   path result;
1248   path tmp;
1249   tmp.__reserve(p.native().size());
1250   auto PP = PathParser::CreateEnd(p.native());
1251   --PP;
1252   vector<string_view_t> DNEParts;
1253 
1254   while (PP.State != PathParser::PS_BeforeBegin) {
1255     tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
1256     error_code m_ec;
1257     file_status st = __status(tmp, &m_ec);
1258     if (!status_known(st)) {
1259       return err.report(m_ec);
1260     } else if (exists(st)) {
1261       result = __canonical(tmp, ec);
1262       break;
1263     }
1264     DNEParts.push_back(*PP);
1265     --PP;
1266   }
1267   if (PP.State == PathParser::PS_BeforeBegin)
1268     result = __canonical("", ec);
1269   if (ec)
1270     ec->clear();
1271   if (DNEParts.empty())
1272     return result;
1273   for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
1274     result /= *It;
1275   return result.lexically_normal();
1276 }
1277 
1278 ///////////////////////////////////////////////////////////////////////////////
1279 //                            path definitions
1280 ///////////////////////////////////////////////////////////////////////////////
1281 
1282 constexpr path::value_type path::preferred_separator;
1283 
1284 path& path::replace_extension(path const& replacement) {
1285   path p = extension();
1286   if (not p.empty()) {
1287     __pn_.erase(__pn_.size() - p.native().size());
1288   }
1289   if (!replacement.empty()) {
1290     if (replacement.native()[0] != '.') {
1291       __pn_ += ".";
1292     }
1293     __pn_.append(replacement.__pn_);
1294   }
1295   return *this;
1296 }
1297 
1298 ///////////////////////////////////////////////////////////////////////////////
1299 // path.decompose
1300 
1301 string_view_t path::__root_name() const {
1302   auto PP = PathParser::CreateBegin(__pn_);
1303   if (PP.State == PathParser::PS_InRootName)
1304     return *PP;
1305   return {};
1306 }
1307 
1308 string_view_t path::__root_directory() const {
1309   auto PP = PathParser::CreateBegin(__pn_);
1310   if (PP.State == PathParser::PS_InRootName)
1311     ++PP;
1312   if (PP.State == PathParser::PS_InRootDir)
1313     return *PP;
1314   return {};
1315 }
1316 
1317 string_view_t path::__root_path_raw() const {
1318   auto PP = PathParser::CreateBegin(__pn_);
1319   if (PP.State == PathParser::PS_InRootName) {
1320     auto NextCh = PP.peek();
1321     if (NextCh && *NextCh == '/') {
1322       ++PP;
1323       return createView(__pn_.data(), &PP.RawEntry.back());
1324     }
1325     return PP.RawEntry;
1326   }
1327   if (PP.State == PathParser::PS_InRootDir)
1328     return *PP;
1329   return {};
1330 }
1331 
1332 static bool ConsumeRootName(PathParser *PP) {
1333   static_assert(PathParser::PS_BeforeBegin == 1 &&
1334       PathParser::PS_InRootName == 2,
1335       "Values for enums are incorrect");
1336   while (PP->State <= PathParser::PS_InRootName)
1337     ++(*PP);
1338   return PP->State == PathParser::PS_AtEnd;
1339 }
1340 
1341 static bool ConsumeRootDir(PathParser* PP) {
1342   static_assert(PathParser::PS_BeforeBegin == 1 &&
1343                 PathParser::PS_InRootName == 2 &&
1344                 PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
1345   while (PP->State <= PathParser::PS_InRootDir)
1346     ++(*PP);
1347   return PP->State == PathParser::PS_AtEnd;
1348 }
1349 
1350 string_view_t path::__relative_path() const {
1351   auto PP = PathParser::CreateBegin(__pn_);
1352   if (ConsumeRootDir(&PP))
1353     return {};
1354   return createView(PP.RawEntry.data(), &__pn_.back());
1355 }
1356 
1357 string_view_t path::__parent_path() const {
1358   if (empty())
1359     return {};
1360   // Determine if we have a root path but not a relative path. In that case
1361   // return *this.
1362   {
1363     auto PP = PathParser::CreateBegin(__pn_);
1364     if (ConsumeRootDir(&PP))
1365       return __pn_;
1366   }
1367   // Otherwise remove a single element from the end of the path, and return
1368   // a string representing that path
1369   {
1370     auto PP = PathParser::CreateEnd(__pn_);
1371     --PP;
1372     if (PP.RawEntry.data() == __pn_.data())
1373       return {};
1374     --PP;
1375     return createView(__pn_.data(), &PP.RawEntry.back());
1376   }
1377 }
1378 
1379 string_view_t path::__filename() const {
1380   if (empty())
1381     return {};
1382   {
1383     PathParser PP = PathParser::CreateBegin(__pn_);
1384     if (ConsumeRootDir(&PP))
1385       return {};
1386   }
1387   return *(--PathParser::CreateEnd(__pn_));
1388 }
1389 
1390 string_view_t path::__stem() const {
1391   return parser::separate_filename(__filename()).first;
1392 }
1393 
1394 string_view_t path::__extension() const {
1395   return parser::separate_filename(__filename()).second;
1396 }
1397 
1398 ////////////////////////////////////////////////////////////////////////////
1399 // path.gen
1400 
1401 enum PathPartKind : unsigned char {
1402   PK_None,
1403   PK_RootSep,
1404   PK_Filename,
1405   PK_Dot,
1406   PK_DotDot,
1407   PK_TrailingSep
1408 };
1409 
1410 static PathPartKind ClassifyPathPart(string_view_t Part) {
1411   if (Part.empty())
1412     return PK_TrailingSep;
1413   if (Part == ".")
1414     return PK_Dot;
1415   if (Part == "..")
1416     return PK_DotDot;
1417   if (Part == "/")
1418     return PK_RootSep;
1419   return PK_Filename;
1420 }
1421 
1422 path path::lexically_normal() const {
1423   if (__pn_.empty())
1424     return *this;
1425 
1426   using PartKindPair = pair<string_view_t, PathPartKind>;
1427   vector<PartKindPair> Parts;
1428   // Guess as to how many elements the path has to avoid reallocating.
1429   Parts.reserve(32);
1430 
1431   // Track the total size of the parts as we collect them. This allows the
1432   // resulting path to reserve the correct amount of memory.
1433   size_t NewPathSize = 0;
1434   auto AddPart = [&](PathPartKind K, string_view_t P) {
1435     NewPathSize += P.size();
1436     Parts.emplace_back(P, K);
1437   };
1438   auto LastPartKind = [&]() {
1439     if (Parts.empty())
1440       return PK_None;
1441     return Parts.back().second;
1442   };
1443 
1444   bool MaybeNeedTrailingSep = false;
1445   // Build a stack containing the remaining elements of the path, popping off
1446   // elements which occur before a '..' entry.
1447   for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
1448     auto Part = *PP;
1449     PathPartKind Kind = ClassifyPathPart(Part);
1450     switch (Kind) {
1451     case PK_Filename:
1452     case PK_RootSep: {
1453       // Add all non-dot and non-dot-dot elements to the stack of elements.
1454       AddPart(Kind, Part);
1455       MaybeNeedTrailingSep = false;
1456       break;
1457     }
1458     case PK_DotDot: {
1459       // Only push a ".." element if there are no elements preceding the "..",
1460       // or if the preceding element is itself "..".
1461       auto LastKind = LastPartKind();
1462       if (LastKind == PK_Filename) {
1463         NewPathSize -= Parts.back().first.size();
1464         Parts.pop_back();
1465       } else if (LastKind != PK_RootSep)
1466         AddPart(PK_DotDot, "..");
1467       MaybeNeedTrailingSep = LastKind == PK_Filename;
1468       break;
1469     }
1470     case PK_Dot:
1471     case PK_TrailingSep: {
1472       MaybeNeedTrailingSep = true;
1473       break;
1474     }
1475     case PK_None:
1476       _LIBCPP_UNREACHABLE();
1477     }
1478   }
1479   // [fs.path.generic]p6.8: If the path is empty, add a dot.
1480   if (Parts.empty())
1481     return ".";
1482 
1483   // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
1484   // trailing directory-separator.
1485   bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
1486 
1487   path Result;
1488   Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
1489   for (auto& PK : Parts)
1490     Result /= PK.first;
1491 
1492   if (NeedTrailingSep)
1493     Result /= "";
1494 
1495   return Result;
1496 }
1497 
1498 static int DetermineLexicalElementCount(PathParser PP) {
1499   int Count = 0;
1500   for (; PP; ++PP) {
1501     auto Elem = *PP;
1502     if (Elem == "..")
1503       --Count;
1504     else if (Elem != "." && Elem != "")
1505       ++Count;
1506   }
1507   return Count;
1508 }
1509 
1510 path path::lexically_relative(const path& base) const {
1511   { // perform root-name/root-directory mismatch checks
1512     auto PP = PathParser::CreateBegin(__pn_);
1513     auto PPBase = PathParser::CreateBegin(base.__pn_);
1514     auto CheckIterMismatchAtBase = [&]() {
1515       return PP.State != PPBase.State &&
1516              (PP.inRootPath() || PPBase.inRootPath());
1517     };
1518     if (PP.inRootName() && PPBase.inRootName()) {
1519       if (*PP != *PPBase)
1520         return {};
1521     } else if (CheckIterMismatchAtBase())
1522       return {};
1523 
1524     if (PP.inRootPath())
1525       ++PP;
1526     if (PPBase.inRootPath())
1527       ++PPBase;
1528     if (CheckIterMismatchAtBase())
1529       return {};
1530   }
1531 
1532   // Find the first mismatching element
1533   auto PP = PathParser::CreateBegin(__pn_);
1534   auto PPBase = PathParser::CreateBegin(base.__pn_);
1535   while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
1536     ++PP;
1537     ++PPBase;
1538   }
1539 
1540   // If there is no mismatch, return ".".
1541   if (!PP && !PPBase)
1542     return ".";
1543 
1544   // Otherwise, determine the number of elements, 'n', which are not dot or
1545   // dot-dot minus the number of dot-dot elements.
1546   int ElemCount = DetermineLexicalElementCount(PPBase);
1547   if (ElemCount < 0)
1548     return {};
1549 
1550   // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
1551   if (ElemCount == 0 && (PP.atEnd() || *PP == ""))
1552     return ".";
1553 
1554   // return a path constructed with 'n' dot-dot elements, followed by the the
1555   // elements of '*this' after the mismatch.
1556   path Result;
1557   // FIXME: Reserve enough room in Result that it won't have to re-allocate.
1558   while (ElemCount--)
1559     Result /= "..";
1560   for (; PP; ++PP)
1561     Result /= *PP;
1562   return Result;
1563 }
1564 
1565 ////////////////////////////////////////////////////////////////////////////
1566 // path.comparisons
1567 static int CompareRootName(PathParser *LHS, PathParser *RHS) {
1568   if (!LHS->inRootName() && !RHS->inRootName())
1569     return 0;
1570 
1571   auto GetRootName = [](PathParser *Parser) -> string_view_t {
1572     return Parser->inRootName() ? **Parser : "";
1573   };
1574   int res = GetRootName(LHS).compare(GetRootName(RHS));
1575   ConsumeRootName(LHS);
1576   ConsumeRootName(RHS);
1577   return res;
1578 }
1579 
1580 static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
1581   if (!LHS->inRootDir() && RHS->inRootDir())
1582     return -1;
1583   else if (LHS->inRootDir() && !RHS->inRootDir())
1584     return 1;
1585   else {
1586     ConsumeRootDir(LHS);
1587     ConsumeRootDir(RHS);
1588     return 0;
1589   }
1590 }
1591 
1592 static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
1593   auto &LHS = *LHSPtr;
1594   auto &RHS = *RHSPtr;
1595 
1596   int res;
1597   while (LHS && RHS) {
1598     if ((res = (*LHS).compare(*RHS)) != 0)
1599       return res;
1600     ++LHS;
1601     ++RHS;
1602   }
1603   return 0;
1604 }
1605 
1606 static int CompareEndState(PathParser *LHS, PathParser *RHS) {
1607   if (LHS->atEnd() && !RHS->atEnd())
1608     return -1;
1609   else if (!LHS->atEnd() && RHS->atEnd())
1610     return 1;
1611   return 0;
1612 }
1613 
1614 int path::__compare(string_view_t __s) const {
1615   auto LHS = PathParser::CreateBegin(__pn_);
1616   auto RHS = PathParser::CreateBegin(__s);
1617   int res;
1618 
1619   if ((res = CompareRootName(&LHS, &RHS)) != 0)
1620     return res;
1621 
1622   if ((res = CompareRootDir(&LHS, &RHS)) != 0)
1623     return res;
1624 
1625   if ((res = CompareRelative(&LHS, &RHS)) != 0)
1626     return res;
1627 
1628   return CompareEndState(&LHS, &RHS);
1629 }
1630 
1631 ////////////////////////////////////////////////////////////////////////////
1632 // path.nonmembers
1633 size_t hash_value(const path& __p) noexcept {
1634   auto PP = PathParser::CreateBegin(__p.native());
1635   size_t hash_value = 0;
1636   hash<string_view_t> hasher;
1637   while (PP) {
1638     hash_value = __hash_combine(hash_value, hasher(*PP));
1639     ++PP;
1640   }
1641   return hash_value;
1642 }
1643 
1644 ////////////////////////////////////////////////////////////////////////////
1645 // path.itr
1646 path::iterator path::begin() const {
1647   auto PP = PathParser::CreateBegin(__pn_);
1648   iterator it;
1649   it.__path_ptr_ = this;
1650   it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
1651   it.__entry_ = PP.RawEntry;
1652   it.__stashed_elem_.__assign_view(*PP);
1653   return it;
1654 }
1655 
1656 path::iterator path::end() const {
1657   iterator it{};
1658   it.__state_ = path::iterator::_AtEnd;
1659   it.__path_ptr_ = this;
1660   return it;
1661 }
1662 
1663 path::iterator& path::iterator::__increment() {
1664   PathParser PP(__path_ptr_->native(), __entry_, __state_);
1665   ++PP;
1666   __state_ = static_cast<_ParserState>(PP.State);
1667   __entry_ = PP.RawEntry;
1668   __stashed_elem_.__assign_view(*PP);
1669   return *this;
1670 }
1671 
1672 path::iterator& path::iterator::__decrement() {
1673   PathParser PP(__path_ptr_->native(), __entry_, __state_);
1674   --PP;
1675   __state_ = static_cast<_ParserState>(PP.State);
1676   __entry_ = PP.RawEntry;
1677   __stashed_elem_.__assign_view(*PP);
1678   return *this;
1679 }
1680 
1681 ///////////////////////////////////////////////////////////////////////////////
1682 //                           directory entry definitions
1683 ///////////////////////////////////////////////////////////////////////////////
1684 
1685 #ifndef _LIBCPP_WIN32API
1686 error_code directory_entry::__do_refresh() noexcept {
1687   __data_.__reset();
1688   error_code failure_ec;
1689 
1690   StatT full_st;
1691   file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
1692   if (!status_known(st)) {
1693     __data_.__reset();
1694     return failure_ec;
1695   }
1696 
1697   if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1698     __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1699     __data_.__type_ = st.type();
1700     __data_.__non_sym_perms_ = st.permissions();
1701   } else { // we have a symlink
1702     __data_.__sym_perms_ = st.permissions();
1703     // Get the information about the linked entity.
1704     // Ignore errors from stat, since we don't want errors regarding symlink
1705     // resolution to be reported to the user.
1706     error_code ignored_ec;
1707     st = detail::posix_stat(__p_, full_st, &ignored_ec);
1708 
1709     __data_.__type_ = st.type();
1710     __data_.__non_sym_perms_ = st.permissions();
1711 
1712     // If we failed to resolve the link, then only partially populate the
1713     // cache.
1714     if (!status_known(st)) {
1715       __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1716       return error_code{};
1717     }
1718     // Otherwise, we resolved the link, potentially as not existing.
1719     // That's OK.
1720     __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1721   }
1722 
1723   if (_VSTD_FS::is_regular_file(st))
1724     __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
1725 
1726   if (_VSTD_FS::exists(st)) {
1727     __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
1728 
1729     // Attempt to extract the mtime, and fail if it's not representable using
1730     // file_time_type. For now we ignore the error, as we'll report it when
1731     // the value is actually used.
1732     error_code ignored_ec;
1733     __data_.__write_time_ =
1734         __extract_last_write_time(__p_, full_st, &ignored_ec);
1735   }
1736 
1737   return failure_ec;
1738 }
1739 #else
1740 error_code directory_entry::__do_refresh() noexcept {
1741   __data_.__reset();
1742   error_code failure_ec;
1743 
1744   file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
1745   if (!status_known(st)) {
1746     __data_.__reset();
1747     return failure_ec;
1748   }
1749 
1750   if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1751     __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1752     __data_.__type_ = st.type();
1753     __data_.__non_sym_perms_ = st.permissions();
1754   } else { // we have a symlink
1755     __data_.__sym_perms_ = st.permissions();
1756     // Get the information about the linked entity.
1757     // Ignore errors from stat, since we don't want errors regarding symlink
1758     // resolution to be reported to the user.
1759     error_code ignored_ec;
1760     st = _VSTD_FS::status(__p_, ignored_ec);
1761 
1762     __data_.__type_ = st.type();
1763     __data_.__non_sym_perms_ = st.permissions();
1764 
1765     // If we failed to resolve the link, then only partially populate the
1766     // cache.
1767     if (!status_known(st)) {
1768       __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1769       return error_code{};
1770     }
1771     __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1772   }
1773 
1774   // FIXME: This is currently broken, and the implementation only a placeholder.
1775   // We need to cache last_write_time, file_size, and hard_link_count here before
1776   // the implementation actually works.
1777 
1778   return failure_ec;
1779 }
1780 #endif
1781 
1782 _LIBCPP_END_NAMESPACE_FILESYSTEM
1783