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