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