• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__anonf6b8ccd30111::parser::PathParser79   PathParser(string_view_t P, ParserState State) noexcept : Path(P),
80                                                             State(State) {}
81 
82 public:
PathParser__anonf6b8ccd30111::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__anonf6b8ccd30111::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__anonf6b8ccd30111::parser::PathParser94   static PathParser CreateEnd(string_view_t P) noexcept {
95     PathParser PP(P, PS_AtEnd);
96     return PP;
97   }
98 
peek__anonf6b8ccd30111::parser::PathParser99   PosPtr peek() const noexcept {
100     auto TkEnd = getNextTokenStartPos();
101     auto End = getAfterBack();
102     return TkEnd == End ? nullptr : TkEnd;
103   }
104 
increment__anonf6b8ccd30111::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__anonf6b8ccd30111::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 *__anonf6b8ccd30111::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__anonf6b8ccd30111::parser::PathParser195   explicit operator bool() const noexcept {
196     return State != PS_BeforeBegin && State != PS_AtEnd;
197   }
198 
operator ++__anonf6b8ccd30111::parser::PathParser199   PathParser& operator++() noexcept {
200     increment();
201     return *this;
202   }
203 
operator --__anonf6b8ccd30111::parser::PathParser204   PathParser& operator--() noexcept {
205     decrement();
206     return *this;
207   }
208 
atEnd__anonf6b8ccd30111::parser::PathParser209   bool atEnd() const noexcept {
210     return State == PS_AtEnd;
211   }
212 
inRootDir__anonf6b8ccd30111::parser::PathParser213   bool inRootDir() const noexcept {
214     return State == PS_InRootDir;
215   }
216 
inRootName__anonf6b8ccd30111::parser::PathParser217   bool inRootName() const noexcept {
218     return State == PS_InRootName;
219   }
220 
inRootPath__anonf6b8ccd30111::parser::PathParser221   bool inRootPath() const noexcept {
222     return inRootName() || inRootDir();
223   }
224 
225 private:
makeState__anonf6b8ccd30111::parser::PathParser226   void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
227     State = NewState;
228     RawEntry = string_view_t(Start, End - Start);
229   }
makeState__anonf6b8ccd30111::parser::PathParser230   void makeState(ParserState NewState) noexcept {
231     State = NewState;
232     RawEntry = {};
233   }
234 
getAfterBack__anonf6b8ccd30111::parser::PathParser235   PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
236 
getBeforeFront__anonf6b8ccd30111::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__anonf6b8ccd30111::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__anonf6b8ccd30111::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__anonf6b8ccd30111::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__anonf6b8ccd30111::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::__anonf6b8ccd30211::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::__anonf6b8ccd30211::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::__anonf6b8ccd30211::FileDescriptor345   file_status get_status() const { return m_status; }
get_statdetail::__anonf6b8ccd30211::FileDescriptor346   StatT const& get_stat() const { return m_stat; }
347 
status_knowndetail::__anonf6b8ccd30211::FileDescriptor348   bool status_known() const { return _VSTD_FS::status_known(m_status); }
349 
350   file_status refresh_status(error_code& ec);
351 
closedetail::__anonf6b8ccd30211::FileDescriptor352   void close() noexcept {
353     if (fd != -1)
354       ::close(fd);
355     fd = -1;
356   }
357 
FileDescriptordetail::__anonf6b8ccd30211::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::__anonf6b8ccd30211::FileDescriptor365   ~FileDescriptor() { close(); }
366 
367   FileDescriptor(FileDescriptor const&) = delete;
368   FileDescriptor& operator=(FileDescriptor const&) = delete;
369 
370 private:
FileDescriptordetail::__anonf6b8ccd30211::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 
posix_ftruncate(const FileDescriptor & fd,size_t to_size,error_code & ec)442 bool posix_ftruncate(const FileDescriptor& fd, size_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 
posix_fchmod(const FileDescriptor & fd,const StatT & st,error_code & ec)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 
stat_equivalent(const StatT & st1,const StatT & st2)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 
refresh_status(error_code & ec)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 
now()487 _FilesystemClock::time_point _FilesystemClock::now() noexcept {
488   typedef chrono::duration<rep> __secs;
489 #if defined(_LIBCPP_USE_CLOCK_GETTIME) && 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 // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
502 }
503 
~filesystem_error()504 filesystem_error::~filesystem_error() {}
505 
__create_what(int __num_paths)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 
__do_absolute(const path & p,path * cwd,error_code * ec)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 
__absolute(const path & p,error_code * ec)535 path __absolute(const path& p, error_code* ec) {
536   path cwd;
537   return __do_absolute(p, &cwd, ec);
538 }
539 
__canonical(path const & orig_p,error_code * ec)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   char buff[PATH_MAX + 1];
546   char* ret;
547   if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
548     return err.report(capture_errno());
549   return {ret};
550 }
551 
__copy(const path & from,const path & to,copy_options options,error_code * ec)552 void __copy(const path& from, const path& to, copy_options options,
553             error_code* ec) {
554   ErrorHandler<void> err("copy", ec, &from, &to);
555 
556   const bool sym_status = bool(
557       options & (copy_options::create_symlinks | copy_options::skip_symlinks));
558 
559   const bool sym_status2 = bool(options & copy_options::copy_symlinks);
560 
561   error_code m_ec1;
562   StatT f_st = {};
563   const file_status f = sym_status || sym_status2
564                             ? detail::posix_lstat(from, f_st, &m_ec1)
565                             : detail::posix_stat(from, f_st, &m_ec1);
566   if (m_ec1)
567     return err.report(m_ec1);
568 
569   StatT t_st = {};
570   const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
571                                    : detail::posix_stat(to, t_st, &m_ec1);
572 
573   if (not status_known(t))
574     return err.report(m_ec1);
575 
576   if (!exists(f) || is_other(f) || is_other(t) ||
577       (is_directory(f) && is_regular_file(t)) ||
578       detail::stat_equivalent(f_st, t_st)) {
579     return err.report(errc::function_not_supported);
580   }
581 
582   if (ec)
583     ec->clear();
584 
585   if (is_symlink(f)) {
586     if (bool(copy_options::skip_symlinks & options)) {
587       // do nothing
588     } else if (not exists(t)) {
589       __copy_symlink(from, to, ec);
590     } else {
591       return err.report(errc::file_exists);
592     }
593     return;
594   } else if (is_regular_file(f)) {
595     if (bool(copy_options::directories_only & options)) {
596       // do nothing
597     } else if (bool(copy_options::create_symlinks & options)) {
598       __create_symlink(from, to, ec);
599     } else if (bool(copy_options::create_hard_links & options)) {
600       __create_hard_link(from, to, ec);
601     } else if (is_directory(t)) {
602       __copy_file(from, to / from.filename(), options, ec);
603     } else {
604       __copy_file(from, to, options, ec);
605     }
606     return;
607   } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
608     return err.report(errc::is_a_directory);
609   } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
610                                  copy_options::none == options)) {
611 
612     if (!exists(t)) {
613       // create directory to with attributes from 'from'.
614       __create_directory(to, from, ec);
615       if (ec && *ec) {
616         return;
617       }
618     }
619     directory_iterator it =
620         ec ? directory_iterator(from, *ec) : directory_iterator(from);
621     if (ec && *ec) {
622       return;
623     }
624     error_code m_ec2;
625     for (; it != directory_iterator(); it.increment(m_ec2)) {
626       if (m_ec2) {
627         return err.report(m_ec2);
628       }
629       __copy(it->path(), to / it->path().filename(),
630              options | copy_options::__in_recursive_copy, ec);
631       if (ec && *ec) {
632         return;
633       }
634     }
635   }
636 }
637 
638 namespace detail {
639 namespace {
640 
641 #ifdef _LIBCPP_USE_SENDFILE
copy_file_impl_sendfile(FileDescriptor & read_fd,FileDescriptor & write_fd,error_code & ec)642 bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
643                              error_code& ec) {
644 
645   size_t count = read_fd.get_stat().st_size;
646   do {
647     ssize_t res;
648     if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
649       ec = capture_errno();
650       return false;
651     }
652     count -= res;
653   } while (count > 0);
654 
655   ec.clear();
656 
657   return true;
658 }
659 #elif defined(_LIBCPP_USE_COPYFILE)
660 bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
661                              error_code& ec) {
662   struct CopyFileState {
663     copyfile_state_t state;
664     CopyFileState() { state = copyfile_state_alloc(); }
665     ~CopyFileState() { copyfile_state_free(state); }
666 
667   private:
668     CopyFileState(CopyFileState const&) = delete;
669     CopyFileState& operator=(CopyFileState const&) = delete;
670   };
671 
672   CopyFileState cfs;
673   if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
674     ec = capture_errno();
675     return false;
676   }
677 
678   ec.clear();
679   return true;
680 }
681 #endif
682 
683 // Note: This function isn't guarded by ifdef's even though it may be unused
684 // in order to assure it still compiles.
copy_file_impl_default(FileDescriptor & read_fd,FileDescriptor & write_fd,error_code & ec)685 __attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd,
686                                                     FileDescriptor& write_fd,
687                                                     error_code& ec) {
688   ifstream in;
689   in.__open(read_fd.fd, ios::binary);
690   if (!in.is_open()) {
691     // This assumes that __open didn't reset the error code.
692     ec = capture_errno();
693     return false;
694   }
695   ofstream out;
696   out.__open(write_fd.fd, ios::binary);
697   if (!out.is_open()) {
698     ec = capture_errno();
699     return false;
700   }
701 
702   if (in.good() && out.good()) {
703     using InIt = istreambuf_iterator<char>;
704     using OutIt = ostreambuf_iterator<char>;
705     InIt bin(in);
706     InIt ein;
707     OutIt bout(out);
708     copy(bin, ein, bout);
709   }
710   if (out.fail() || in.fail()) {
711     ec = make_error_code(errc::io_error);
712     return false;
713   }
714 
715   ec.clear();
716   return true;
717 }
718 
copy_file_impl(FileDescriptor & from,FileDescriptor & to,error_code & ec)719 bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) {
720 #if defined(_LIBCPP_USE_SENDFILE)
721   return copy_file_impl_sendfile(from, to, ec);
722 #elif defined(_LIBCPP_USE_COPYFILE)
723   return copy_file_impl_copyfile(from, to, ec);
724 #else
725   return copy_file_impl_default(from, to, ec);
726 #endif
727 }
728 
729 } // namespace
730 } // namespace detail
731 
__copy_file(const path & from,const path & to,copy_options options,error_code * ec)732 bool __copy_file(const path& from, const path& to, copy_options options,
733                  error_code* ec) {
734   using detail::FileDescriptor;
735   ErrorHandler<bool> err("copy_file", ec, &to, &from);
736 
737   error_code m_ec;
738   FileDescriptor from_fd =
739       FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
740   if (m_ec)
741     return err.report(m_ec);
742 
743   auto from_st = from_fd.get_status();
744   StatT const& from_stat = from_fd.get_stat();
745   if (!is_regular_file(from_st)) {
746     if (not m_ec)
747       m_ec = make_error_code(errc::not_supported);
748     return err.report(m_ec);
749   }
750 
751   const bool skip_existing = bool(copy_options::skip_existing & options);
752   const bool update_existing = bool(copy_options::update_existing & options);
753   const bool overwrite_existing =
754       bool(copy_options::overwrite_existing & options);
755 
756   StatT to_stat_path;
757   file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
758   if (!status_known(to_st))
759     return err.report(m_ec);
760 
761   const bool to_exists = exists(to_st);
762   if (to_exists && !is_regular_file(to_st))
763     return err.report(errc::not_supported);
764 
765   if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
766     return err.report(errc::file_exists);
767 
768   if (to_exists && skip_existing)
769     return false;
770 
771   bool ShouldCopy = [&]() {
772     if (to_exists && update_existing) {
773       auto from_time = detail::extract_mtime(from_stat);
774       auto to_time = detail::extract_mtime(to_stat_path);
775       if (from_time.tv_sec < to_time.tv_sec)
776         return false;
777       if (from_time.tv_sec == to_time.tv_sec &&
778           from_time.tv_nsec <= to_time.tv_nsec)
779         return false;
780       return true;
781     }
782     if (!to_exists || overwrite_existing)
783       return true;
784     return err.report(errc::file_exists);
785   }();
786   if (!ShouldCopy)
787     return false;
788 
789   // Don't truncate right away. We may not be opening the file we originally
790   // looked at; we'll check this later.
791   int to_open_flags = O_WRONLY;
792   if (!to_exists)
793     to_open_flags |= O_CREAT;
794   FileDescriptor to_fd = FileDescriptor::create_with_status(
795       &to, m_ec, to_open_flags, from_stat.st_mode);
796   if (m_ec)
797     return err.report(m_ec);
798 
799   if (to_exists) {
800     // Check that the file we initially stat'ed is equivalent to the one
801     // we opened.
802     // FIXME: report this better.
803     if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
804       return err.report(errc::bad_file_descriptor);
805 
806     // Set the permissions and truncate the file we opened.
807     if (detail::posix_fchmod(to_fd, from_stat, m_ec))
808       return err.report(m_ec);
809     if (detail::posix_ftruncate(to_fd, 0, m_ec))
810       return err.report(m_ec);
811   }
812 
813   if (!copy_file_impl(from_fd, to_fd, m_ec)) {
814     // FIXME: Remove the dest file if we failed, and it didn't exist previously.
815     return err.report(m_ec);
816   }
817 
818   return true;
819 }
820 
__copy_symlink(const path & existing_symlink,const path & new_symlink,error_code * ec)821 void __copy_symlink(const path& existing_symlink, const path& new_symlink,
822                     error_code* ec) {
823   const path real_path(__read_symlink(existing_symlink, ec));
824   if (ec && *ec) {
825     return;
826   }
827   // NOTE: proposal says you should detect if you should call
828   // create_symlink or create_directory_symlink. I don't think this
829   // is needed with POSIX
830   __create_symlink(real_path, new_symlink, ec);
831 }
832 
__create_directories(const path & p,error_code * ec)833 bool __create_directories(const path& p, error_code* ec) {
834   ErrorHandler<bool> err("create_directories", ec, &p);
835 
836   error_code m_ec;
837   auto const st = detail::posix_stat(p, &m_ec);
838   if (!status_known(st))
839     return err.report(m_ec);
840   else if (is_directory(st))
841     return false;
842   else if (exists(st))
843     return err.report(errc::file_exists);
844 
845   const path parent = p.parent_path();
846   if (!parent.empty()) {
847     const file_status parent_st = status(parent, m_ec);
848     if (not status_known(parent_st))
849       return err.report(m_ec);
850     if (not exists(parent_st)) {
851       __create_directories(parent, ec);
852       if (ec && *ec) {
853         return false;
854       }
855     }
856   }
857   return __create_directory(p, ec);
858 }
859 
__create_directory(const path & p,error_code * ec)860 bool __create_directory(const path& p, error_code* ec) {
861   ErrorHandler<bool> err("create_directory", ec, &p);
862 
863   if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
864     return true;
865   if (errno != EEXIST)
866     err.report(capture_errno());
867   return false;
868 }
869 
__create_directory(path const & p,path const & attributes,error_code * ec)870 bool __create_directory(path const& p, path const& attributes, error_code* ec) {
871   ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
872 
873   StatT attr_stat;
874   error_code mec;
875   auto st = detail::posix_stat(attributes, attr_stat, &mec);
876   if (!status_known(st))
877     return err.report(mec);
878   if (!is_directory(st))
879     return err.report(errc::not_a_directory,
880                       "the specified attribute path is invalid");
881 
882   if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
883     return true;
884   if (errno != EEXIST)
885     err.report(capture_errno());
886   return false;
887 }
888 
__create_directory_symlink(path const & from,path const & to,error_code * ec)889 void __create_directory_symlink(path const& from, path const& to,
890                                 error_code* ec) {
891   ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
892   if (::symlink(from.c_str(), to.c_str()) != 0)
893     return err.report(capture_errno());
894 }
895 
__create_hard_link(const path & from,const path & to,error_code * ec)896 void __create_hard_link(const path& from, const path& to, error_code* ec) {
897   ErrorHandler<void> err("create_hard_link", ec, &from, &to);
898   if (::link(from.c_str(), to.c_str()) == -1)
899     return err.report(capture_errno());
900 }
901 
__create_symlink(path const & from,path const & to,error_code * ec)902 void __create_symlink(path const& from, path const& to, error_code* ec) {
903   ErrorHandler<void> err("create_symlink", ec, &from, &to);
904   if (::symlink(from.c_str(), to.c_str()) == -1)
905     return err.report(capture_errno());
906 }
907 
__current_path(error_code * ec)908 path __current_path(error_code* ec) {
909   ErrorHandler<path> err("current_path", ec);
910 
911   auto size = ::pathconf(".", _PC_PATH_MAX);
912   _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
913 
914   auto buff = unique_ptr<char[]>(new char[size + 1]);
915   char* ret;
916   if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
917     return err.report(capture_errno(), "call to getcwd failed");
918 
919   return {buff.get()};
920 }
921 
__current_path(const path & p,error_code * ec)922 void __current_path(const path& p, error_code* ec) {
923   ErrorHandler<void> err("current_path", ec, &p);
924   if (::chdir(p.c_str()) == -1)
925     err.report(capture_errno());
926 }
927 
__equivalent(const path & p1,const path & p2,error_code * ec)928 bool __equivalent(const path& p1, const path& p2, error_code* ec) {
929   ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
930 
931   error_code ec1, ec2;
932   StatT st1 = {}, st2 = {};
933   auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
934   if (!exists(s1))
935     return err.report(errc::not_supported);
936   auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
937   if (!exists(s2))
938     return err.report(errc::not_supported);
939 
940   return detail::stat_equivalent(st1, st2);
941 }
942 
__file_size(const path & p,error_code * ec)943 uintmax_t __file_size(const path& p, error_code* ec) {
944   ErrorHandler<uintmax_t> err("file_size", ec, &p);
945 
946   error_code m_ec;
947   StatT st;
948   file_status fst = detail::posix_stat(p, st, &m_ec);
949   if (!exists(fst) || !is_regular_file(fst)) {
950     errc error_kind =
951         is_directory(fst) ? errc::is_a_directory : errc::not_supported;
952     if (!m_ec)
953       m_ec = make_error_code(error_kind);
954     return err.report(m_ec);
955   }
956   // is_regular_file(p) == true
957   return static_cast<uintmax_t>(st.st_size);
958 }
959 
__hard_link_count(const path & p,error_code * ec)960 uintmax_t __hard_link_count(const path& p, error_code* ec) {
961   ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
962 
963   error_code m_ec;
964   StatT st;
965   detail::posix_stat(p, st, &m_ec);
966   if (m_ec)
967     return err.report(m_ec);
968   return static_cast<uintmax_t>(st.st_nlink);
969 }
970 
__fs_is_empty(const path & p,error_code * ec)971 bool __fs_is_empty(const path& p, error_code* ec) {
972   ErrorHandler<bool> err("is_empty", ec, &p);
973 
974   error_code m_ec;
975   StatT pst;
976   auto st = detail::posix_stat(p, pst, &m_ec);
977   if (m_ec)
978     return err.report(m_ec);
979   else if (!is_directory(st) && !is_regular_file(st))
980     return err.report(errc::not_supported);
981   else if (is_directory(st)) {
982     auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
983     if (ec && *ec)
984       return false;
985     return it == directory_iterator{};
986   } else if (is_regular_file(st))
987     return static_cast<uintmax_t>(pst.st_size) == 0;
988 
989   _LIBCPP_UNREACHABLE();
990 }
991 
__extract_last_write_time(const path & p,const StatT & st,error_code * ec)992 static file_time_type __extract_last_write_time(const path& p, const StatT& st,
993                                                 error_code* ec) {
994   using detail::fs_time;
995   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
996 
997   auto ts = detail::extract_mtime(st);
998   if (!fs_time::is_representable(ts))
999     return err.report(errc::value_too_large);
1000 
1001   return fs_time::convert_from_timespec(ts);
1002 }
1003 
__last_write_time(const path & p,error_code * ec)1004 file_time_type __last_write_time(const path& p, error_code* ec) {
1005   using namespace chrono;
1006   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
1007 
1008   error_code m_ec;
1009   StatT st;
1010   detail::posix_stat(p, st, &m_ec);
1011   if (m_ec)
1012     return err.report(m_ec);
1013   return __extract_last_write_time(p, st, ec);
1014 }
1015 
__last_write_time(const path & p,file_time_type new_time,error_code * ec)1016 void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
1017   using detail::fs_time;
1018   ErrorHandler<void> err("last_write_time", ec, &p);
1019 
1020   error_code m_ec;
1021   array<TimeSpec, 2> tbuf;
1022 #if !defined(_LIBCPP_USE_UTIMENSAT)
1023   // This implementation has a race condition between determining the
1024   // last access time and attempting to set it to the same value using
1025   // ::utimes
1026   StatT st;
1027   file_status fst = detail::posix_stat(p, st, &m_ec);
1028   if (m_ec)
1029     return err.report(m_ec);
1030   tbuf[0] = detail::extract_atime(st);
1031 #else
1032   tbuf[0].tv_sec = 0;
1033   tbuf[0].tv_nsec = UTIME_OMIT;
1034 #endif
1035   if (!fs_time::convert_to_timespec(tbuf[1], new_time))
1036     return err.report(errc::value_too_large);
1037 
1038   detail::set_file_times(p, tbuf, m_ec);
1039   if (m_ec)
1040     return err.report(m_ec);
1041 }
1042 
__permissions(const path & p,perms prms,perm_options opts,error_code * ec)1043 void __permissions(const path& p, perms prms, perm_options opts,
1044                    error_code* ec) {
1045   ErrorHandler<void> err("permissions", ec, &p);
1046 
1047   auto has_opt = [&](perm_options o) { return bool(o & opts); };
1048   const bool resolve_symlinks = !has_opt(perm_options::nofollow);
1049   const bool add_perms = has_opt(perm_options::add);
1050   const bool remove_perms = has_opt(perm_options::remove);
1051   _LIBCPP_ASSERT(
1052       (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
1053       "One and only one of the perm_options constants replace, add, or remove "
1054       "is present in opts");
1055 
1056   bool set_sym_perms = false;
1057   prms &= perms::mask;
1058   if (!resolve_symlinks || (add_perms || remove_perms)) {
1059     error_code m_ec;
1060     file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
1061                                       : detail::posix_lstat(p, &m_ec);
1062     set_sym_perms = is_symlink(st);
1063     if (m_ec)
1064       return err.report(m_ec);
1065     _LIBCPP_ASSERT(st.permissions() != perms::unknown,
1066                    "Permissions unexpectedly unknown");
1067     if (add_perms)
1068       prms |= st.permissions();
1069     else if (remove_perms)
1070       prms = st.permissions() & ~prms;
1071   }
1072   const auto real_perms = detail::posix_convert_perms(prms);
1073 
1074 #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
1075   const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
1076   if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
1077     return err.report(capture_errno());
1078   }
1079 #else
1080   if (set_sym_perms)
1081     return err.report(errc::operation_not_supported);
1082   if (::chmod(p.c_str(), real_perms) == -1) {
1083     return err.report(capture_errno());
1084   }
1085 #endif
1086 }
1087 
__read_symlink(const path & p,error_code * ec)1088 path __read_symlink(const path& p, error_code* ec) {
1089   ErrorHandler<path> err("read_symlink", ec, &p);
1090 
1091   char buff[PATH_MAX + 1];
1092   error_code m_ec;
1093   ::ssize_t ret;
1094   if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
1095     return err.report(capture_errno());
1096   }
1097   _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
1098   _LIBCPP_ASSERT(ret > 0, "TODO");
1099   buff[ret] = 0;
1100   return {buff};
1101 }
1102 
__remove(const path & p,error_code * ec)1103 bool __remove(const path& p, error_code* ec) {
1104   ErrorHandler<bool> err("remove", ec, &p);
1105   if (::remove(p.c_str()) == -1) {
1106     if (errno != ENOENT)
1107       err.report(capture_errno());
1108     return false;
1109   }
1110   return true;
1111 }
1112 
1113 namespace {
1114 
remove_all_impl(path const & p,error_code & ec)1115 uintmax_t remove_all_impl(path const& p, error_code& ec) {
1116   const auto npos = static_cast<uintmax_t>(-1);
1117   const file_status st = __symlink_status(p, &ec);
1118   if (ec)
1119     return npos;
1120   uintmax_t count = 1;
1121   if (is_directory(st)) {
1122     for (directory_iterator it(p, ec); !ec && it != directory_iterator();
1123          it.increment(ec)) {
1124       auto other_count = remove_all_impl(it->path(), ec);
1125       if (ec)
1126         return npos;
1127       count += other_count;
1128     }
1129     if (ec)
1130       return npos;
1131   }
1132   if (!__remove(p, &ec))
1133     return npos;
1134   return count;
1135 }
1136 
1137 } // end namespace
1138 
__remove_all(const path & p,error_code * ec)1139 uintmax_t __remove_all(const path& p, error_code* ec) {
1140   ErrorHandler<uintmax_t> err("remove_all", ec, &p);
1141 
1142   error_code mec;
1143   auto count = remove_all_impl(p, mec);
1144   if (mec) {
1145     if (mec == errc::no_such_file_or_directory)
1146       return 0;
1147     return err.report(mec);
1148   }
1149   return count;
1150 }
1151 
__rename(const path & from,const path & to,error_code * ec)1152 void __rename(const path& from, const path& to, error_code* ec) {
1153   ErrorHandler<void> err("rename", ec, &from, &to);
1154   if (::rename(from.c_str(), to.c_str()) == -1)
1155     err.report(capture_errno());
1156 }
1157 
__resize_file(const path & p,uintmax_t size,error_code * ec)1158 void __resize_file(const path& p, uintmax_t size, error_code* ec) {
1159   ErrorHandler<void> err("resize_file", ec, &p);
1160   if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
1161     return err.report(capture_errno());
1162 }
1163 
__space(const path & p,error_code * ec)1164 space_info __space(const path& p, error_code* ec) {
1165   ErrorHandler<void> err("space", ec, &p);
1166   space_info si;
1167   struct statvfs m_svfs = {};
1168   if (::statvfs(p.c_str(), &m_svfs) == -1) {
1169     err.report(capture_errno());
1170     si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
1171     return si;
1172   }
1173   // Multiply with overflow checking.
1174   auto do_mult = [&](uintmax_t& out, uintmax_t other) {
1175     out = other * m_svfs.f_frsize;
1176     if (other == 0 || out / other != m_svfs.f_frsize)
1177       out = static_cast<uintmax_t>(-1);
1178   };
1179   do_mult(si.capacity, m_svfs.f_blocks);
1180   do_mult(si.free, m_svfs.f_bfree);
1181   do_mult(si.available, m_svfs.f_bavail);
1182   return si;
1183 }
1184 
__status(const path & p,error_code * ec)1185 file_status __status(const path& p, error_code* ec) {
1186   return detail::posix_stat(p, ec);
1187 }
1188 
__symlink_status(const path & p,error_code * ec)1189 file_status __symlink_status(const path& p, error_code* ec) {
1190   return detail::posix_lstat(p, ec);
1191 }
1192 
__temp_directory_path(error_code * ec)1193 path __temp_directory_path(error_code* ec) {
1194   ErrorHandler<path> err("temp_directory_path", ec);
1195 
1196   const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
1197   const char* ret = nullptr;
1198 
1199   for (auto& ep : env_paths)
1200     if ((ret = getenv(ep)))
1201       break;
1202   if (ret == nullptr)
1203     ret = "/tmp";
1204 
1205   path p(ret);
1206   error_code m_ec;
1207   file_status st = detail::posix_stat(p, &m_ec);
1208   if (!status_known(st))
1209     return err.report(m_ec, "cannot access path \"%s\"", p);
1210 
1211   if (!exists(st) || !is_directory(st))
1212     return err.report(errc::not_a_directory, "path \"%s\" is not a directory",
1213                       p);
1214 
1215   return p;
1216 }
1217 
__weakly_canonical(const path & p,error_code * ec)1218 path __weakly_canonical(const path& p, error_code* ec) {
1219   ErrorHandler<path> err("weakly_canonical", ec, &p);
1220 
1221   if (p.empty())
1222     return __canonical("", ec);
1223 
1224   path result;
1225   path tmp;
1226   tmp.__reserve(p.native().size());
1227   auto PP = PathParser::CreateEnd(p.native());
1228   --PP;
1229   vector<string_view_t> DNEParts;
1230 
1231   while (PP.State != PathParser::PS_BeforeBegin) {
1232     tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
1233     error_code m_ec;
1234     file_status st = __status(tmp, &m_ec);
1235     if (!status_known(st)) {
1236       return err.report(m_ec);
1237     } else if (exists(st)) {
1238       result = __canonical(tmp, ec);
1239       break;
1240     }
1241     DNEParts.push_back(*PP);
1242     --PP;
1243   }
1244   if (PP.State == PathParser::PS_BeforeBegin)
1245     result = __canonical("", ec);
1246   if (ec)
1247     ec->clear();
1248   if (DNEParts.empty())
1249     return result;
1250   for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
1251     result /= *It;
1252   return result.lexically_normal();
1253 }
1254 
1255 ///////////////////////////////////////////////////////////////////////////////
1256 //                            path definitions
1257 ///////////////////////////////////////////////////////////////////////////////
1258 
1259 constexpr path::value_type path::preferred_separator;
1260 
replace_extension(path const & replacement)1261 path& path::replace_extension(path const& replacement) {
1262   path p = extension();
1263   if (not p.empty()) {
1264     __pn_.erase(__pn_.size() - p.native().size());
1265   }
1266   if (!replacement.empty()) {
1267     if (replacement.native()[0] != '.') {
1268       __pn_ += ".";
1269     }
1270     __pn_.append(replacement.__pn_);
1271   }
1272   return *this;
1273 }
1274 
1275 ///////////////////////////////////////////////////////////////////////////////
1276 // path.decompose
1277 
__root_name() const1278 string_view_t path::__root_name() const {
1279   auto PP = PathParser::CreateBegin(__pn_);
1280   if (PP.State == PathParser::PS_InRootName)
1281     return *PP;
1282   return {};
1283 }
1284 
__root_directory() const1285 string_view_t path::__root_directory() const {
1286   auto PP = PathParser::CreateBegin(__pn_);
1287   if (PP.State == PathParser::PS_InRootName)
1288     ++PP;
1289   if (PP.State == PathParser::PS_InRootDir)
1290     return *PP;
1291   return {};
1292 }
1293 
__root_path_raw() const1294 string_view_t path::__root_path_raw() const {
1295   auto PP = PathParser::CreateBegin(__pn_);
1296   if (PP.State == PathParser::PS_InRootName) {
1297     auto NextCh = PP.peek();
1298     if (NextCh && *NextCh == '/') {
1299       ++PP;
1300       return createView(__pn_.data(), &PP.RawEntry.back());
1301     }
1302     return PP.RawEntry;
1303   }
1304   if (PP.State == PathParser::PS_InRootDir)
1305     return *PP;
1306   return {};
1307 }
1308 
ConsumeRootName(PathParser * PP)1309 static bool ConsumeRootName(PathParser *PP) {
1310   static_assert(PathParser::PS_BeforeBegin == 1 &&
1311       PathParser::PS_InRootName == 2,
1312       "Values for enums are incorrect");
1313   while (PP->State <= PathParser::PS_InRootName)
1314     ++(*PP);
1315   return PP->State == PathParser::PS_AtEnd;
1316 }
1317 
ConsumeRootDir(PathParser * PP)1318 static bool ConsumeRootDir(PathParser* PP) {
1319   static_assert(PathParser::PS_BeforeBegin == 1 &&
1320                 PathParser::PS_InRootName == 2 &&
1321                 PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
1322   while (PP->State <= PathParser::PS_InRootDir)
1323     ++(*PP);
1324   return PP->State == PathParser::PS_AtEnd;
1325 }
1326 
__relative_path() const1327 string_view_t path::__relative_path() const {
1328   auto PP = PathParser::CreateBegin(__pn_);
1329   if (ConsumeRootDir(&PP))
1330     return {};
1331   return createView(PP.RawEntry.data(), &__pn_.back());
1332 }
1333 
__parent_path() const1334 string_view_t path::__parent_path() const {
1335   if (empty())
1336     return {};
1337   // Determine if we have a root path but not a relative path. In that case
1338   // return *this.
1339   {
1340     auto PP = PathParser::CreateBegin(__pn_);
1341     if (ConsumeRootDir(&PP))
1342       return __pn_;
1343   }
1344   // Otherwise remove a single element from the end of the path, and return
1345   // a string representing that path
1346   {
1347     auto PP = PathParser::CreateEnd(__pn_);
1348     --PP;
1349     if (PP.RawEntry.data() == __pn_.data())
1350       return {};
1351     --PP;
1352     return createView(__pn_.data(), &PP.RawEntry.back());
1353   }
1354 }
1355 
__filename() const1356 string_view_t path::__filename() const {
1357   if (empty())
1358     return {};
1359   {
1360     PathParser PP = PathParser::CreateBegin(__pn_);
1361     if (ConsumeRootDir(&PP))
1362       return {};
1363   }
1364   return *(--PathParser::CreateEnd(__pn_));
1365 }
1366 
__stem() const1367 string_view_t path::__stem() const {
1368   return parser::separate_filename(__filename()).first;
1369 }
1370 
__extension() const1371 string_view_t path::__extension() const {
1372   return parser::separate_filename(__filename()).second;
1373 }
1374 
1375 ////////////////////////////////////////////////////////////////////////////
1376 // path.gen
1377 
1378 enum PathPartKind : unsigned char {
1379   PK_None,
1380   PK_RootSep,
1381   PK_Filename,
1382   PK_Dot,
1383   PK_DotDot,
1384   PK_TrailingSep
1385 };
1386 
ClassifyPathPart(string_view_t Part)1387 static PathPartKind ClassifyPathPart(string_view_t Part) {
1388   if (Part.empty())
1389     return PK_TrailingSep;
1390   if (Part == ".")
1391     return PK_Dot;
1392   if (Part == "..")
1393     return PK_DotDot;
1394   if (Part == "/")
1395     return PK_RootSep;
1396   return PK_Filename;
1397 }
1398 
lexically_normal() const1399 path path::lexically_normal() const {
1400   if (__pn_.empty())
1401     return *this;
1402 
1403   using PartKindPair = pair<string_view_t, PathPartKind>;
1404   vector<PartKindPair> Parts;
1405   // Guess as to how many elements the path has to avoid reallocating.
1406   Parts.reserve(32);
1407 
1408   // Track the total size of the parts as we collect them. This allows the
1409   // resulting path to reserve the correct amount of memory.
1410   size_t NewPathSize = 0;
1411   auto AddPart = [&](PathPartKind K, string_view_t P) {
1412     NewPathSize += P.size();
1413     Parts.emplace_back(P, K);
1414   };
1415   auto LastPartKind = [&]() {
1416     if (Parts.empty())
1417       return PK_None;
1418     return Parts.back().second;
1419   };
1420 
1421   bool MaybeNeedTrailingSep = false;
1422   // Build a stack containing the remaining elements of the path, popping off
1423   // elements which occur before a '..' entry.
1424   for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
1425     auto Part = *PP;
1426     PathPartKind Kind = ClassifyPathPart(Part);
1427     switch (Kind) {
1428     case PK_Filename:
1429     case PK_RootSep: {
1430       // Add all non-dot and non-dot-dot elements to the stack of elements.
1431       AddPart(Kind, Part);
1432       MaybeNeedTrailingSep = false;
1433       break;
1434     }
1435     case PK_DotDot: {
1436       // Only push a ".." element if there are no elements preceding the "..",
1437       // or if the preceding element is itself "..".
1438       auto LastKind = LastPartKind();
1439       if (LastKind == PK_Filename) {
1440         NewPathSize -= Parts.back().first.size();
1441         Parts.pop_back();
1442       } else if (LastKind != PK_RootSep)
1443         AddPart(PK_DotDot, "..");
1444       MaybeNeedTrailingSep = LastKind == PK_Filename;
1445       break;
1446     }
1447     case PK_Dot:
1448     case PK_TrailingSep: {
1449       MaybeNeedTrailingSep = true;
1450       break;
1451     }
1452     case PK_None:
1453       _LIBCPP_UNREACHABLE();
1454     }
1455   }
1456   // [fs.path.generic]p6.8: If the path is empty, add a dot.
1457   if (Parts.empty())
1458     return ".";
1459 
1460   // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
1461   // trailing directory-separator.
1462   bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
1463 
1464   path Result;
1465   Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
1466   for (auto& PK : Parts)
1467     Result /= PK.first;
1468 
1469   if (NeedTrailingSep)
1470     Result /= "";
1471 
1472   return Result;
1473 }
1474 
DetermineLexicalElementCount(PathParser PP)1475 static int DetermineLexicalElementCount(PathParser PP) {
1476   int Count = 0;
1477   for (; PP; ++PP) {
1478     auto Elem = *PP;
1479     if (Elem == "..")
1480       --Count;
1481     else if (Elem != "." && Elem != "")
1482       ++Count;
1483   }
1484   return Count;
1485 }
1486 
lexically_relative(const path & base) const1487 path path::lexically_relative(const path& base) const {
1488   { // perform root-name/root-directory mismatch checks
1489     auto PP = PathParser::CreateBegin(__pn_);
1490     auto PPBase = PathParser::CreateBegin(base.__pn_);
1491     auto CheckIterMismatchAtBase = [&]() {
1492       return PP.State != PPBase.State &&
1493              (PP.inRootPath() || PPBase.inRootPath());
1494     };
1495     if (PP.inRootName() && PPBase.inRootName()) {
1496       if (*PP != *PPBase)
1497         return {};
1498     } else if (CheckIterMismatchAtBase())
1499       return {};
1500 
1501     if (PP.inRootPath())
1502       ++PP;
1503     if (PPBase.inRootPath())
1504       ++PPBase;
1505     if (CheckIterMismatchAtBase())
1506       return {};
1507   }
1508 
1509   // Find the first mismatching element
1510   auto PP = PathParser::CreateBegin(__pn_);
1511   auto PPBase = PathParser::CreateBegin(base.__pn_);
1512   while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
1513     ++PP;
1514     ++PPBase;
1515   }
1516 
1517   // If there is no mismatch, return ".".
1518   if (!PP && !PPBase)
1519     return ".";
1520 
1521   // Otherwise, determine the number of elements, 'n', which are not dot or
1522   // dot-dot minus the number of dot-dot elements.
1523   int ElemCount = DetermineLexicalElementCount(PPBase);
1524   if (ElemCount < 0)
1525     return {};
1526 
1527   // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
1528   if (ElemCount == 0 && (PP.atEnd() || *PP == ""))
1529     return ".";
1530 
1531   // return a path constructed with 'n' dot-dot elements, followed by the the
1532   // elements of '*this' after the mismatch.
1533   path Result;
1534   // FIXME: Reserve enough room in Result that it won't have to re-allocate.
1535   while (ElemCount--)
1536     Result /= "..";
1537   for (; PP; ++PP)
1538     Result /= *PP;
1539   return Result;
1540 }
1541 
1542 ////////////////////////////////////////////////////////////////////////////
1543 // path.comparisons
CompareRootName(PathParser * LHS,PathParser * RHS)1544 static int CompareRootName(PathParser *LHS, PathParser *RHS) {
1545   if (!LHS->inRootName() && !RHS->inRootName())
1546     return 0;
1547 
1548   auto GetRootName = [](PathParser *Parser) -> string_view_t {
1549     return Parser->inRootName() ? **Parser : "";
1550   };
1551   int res = GetRootName(LHS).compare(GetRootName(RHS));
1552   ConsumeRootName(LHS);
1553   ConsumeRootName(RHS);
1554   return res;
1555 }
1556 
CompareRootDir(PathParser * LHS,PathParser * RHS)1557 static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
1558   if (!LHS->inRootDir() && RHS->inRootDir())
1559     return -1;
1560   else if (LHS->inRootDir() && !RHS->inRootDir())
1561     return 1;
1562   else {
1563     ConsumeRootDir(LHS);
1564     ConsumeRootDir(RHS);
1565     return 0;
1566   }
1567 }
1568 
CompareRelative(PathParser * LHSPtr,PathParser * RHSPtr)1569 static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
1570   auto &LHS = *LHSPtr;
1571   auto &RHS = *RHSPtr;
1572 
1573   int res;
1574   while (LHS && RHS) {
1575     if ((res = (*LHS).compare(*RHS)) != 0)
1576       return res;
1577     ++LHS;
1578     ++RHS;
1579   }
1580   return 0;
1581 }
1582 
CompareEndState(PathParser * LHS,PathParser * RHS)1583 static int CompareEndState(PathParser *LHS, PathParser *RHS) {
1584   if (LHS->atEnd() && !RHS->atEnd())
1585     return -1;
1586   else if (!LHS->atEnd() && RHS->atEnd())
1587     return 1;
1588   return 0;
1589 }
1590 
__compare(string_view_t __s) const1591 int path::__compare(string_view_t __s) const {
1592   auto LHS = PathParser::CreateBegin(__pn_);
1593   auto RHS = PathParser::CreateBegin(__s);
1594   int res;
1595 
1596   if ((res = CompareRootName(&LHS, &RHS)) != 0)
1597     return res;
1598 
1599   if ((res = CompareRootDir(&LHS, &RHS)) != 0)
1600     return res;
1601 
1602   if ((res = CompareRelative(&LHS, &RHS)) != 0)
1603     return res;
1604 
1605   return CompareEndState(&LHS, &RHS);
1606 }
1607 
1608 ////////////////////////////////////////////////////////////////////////////
1609 // path.nonmembers
hash_value(const path & __p)1610 size_t hash_value(const path& __p) noexcept {
1611   auto PP = PathParser::CreateBegin(__p.native());
1612   size_t hash_value = 0;
1613   hash<string_view_t> hasher;
1614   while (PP) {
1615     hash_value = __hash_combine(hash_value, hasher(*PP));
1616     ++PP;
1617   }
1618   return hash_value;
1619 }
1620 
1621 ////////////////////////////////////////////////////////////////////////////
1622 // path.itr
begin() const1623 path::iterator path::begin() const {
1624   auto PP = PathParser::CreateBegin(__pn_);
1625   iterator it;
1626   it.__path_ptr_ = this;
1627   it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
1628   it.__entry_ = PP.RawEntry;
1629   it.__stashed_elem_.__assign_view(*PP);
1630   return it;
1631 }
1632 
end() const1633 path::iterator path::end() const {
1634   iterator it{};
1635   it.__state_ = path::iterator::_AtEnd;
1636   it.__path_ptr_ = this;
1637   return it;
1638 }
1639 
__increment()1640 path::iterator& path::iterator::__increment() {
1641   PathParser PP(__path_ptr_->native(), __entry_, __state_);
1642   ++PP;
1643   __state_ = static_cast<_ParserState>(PP.State);
1644   __entry_ = PP.RawEntry;
1645   __stashed_elem_.__assign_view(*PP);
1646   return *this;
1647 }
1648 
__decrement()1649 path::iterator& path::iterator::__decrement() {
1650   PathParser PP(__path_ptr_->native(), __entry_, __state_);
1651   --PP;
1652   __state_ = static_cast<_ParserState>(PP.State);
1653   __entry_ = PP.RawEntry;
1654   __stashed_elem_.__assign_view(*PP);
1655   return *this;
1656 }
1657 
1658 ///////////////////////////////////////////////////////////////////////////////
1659 //                           directory entry definitions
1660 ///////////////////////////////////////////////////////////////////////////////
1661 
1662 #ifndef _LIBCPP_WIN32API
__do_refresh()1663 error_code directory_entry::__do_refresh() noexcept {
1664   __data_.__reset();
1665   error_code failure_ec;
1666 
1667   StatT full_st;
1668   file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
1669   if (!status_known(st)) {
1670     __data_.__reset();
1671     return failure_ec;
1672   }
1673 
1674   if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1675     __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1676     __data_.__type_ = st.type();
1677     __data_.__non_sym_perms_ = st.permissions();
1678   } else { // we have a symlink
1679     __data_.__sym_perms_ = st.permissions();
1680     // Get the information about the linked entity.
1681     // Ignore errors from stat, since we don't want errors regarding symlink
1682     // resolution to be reported to the user.
1683     error_code ignored_ec;
1684     st = detail::posix_stat(__p_, full_st, &ignored_ec);
1685 
1686     __data_.__type_ = st.type();
1687     __data_.__non_sym_perms_ = st.permissions();
1688 
1689     // If we failed to resolve the link, then only partially populate the
1690     // cache.
1691     if (!status_known(st)) {
1692       __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1693       return error_code{};
1694     }
1695     // Otherwise, we resolved the link, potentially as not existing.
1696     // That's OK.
1697     __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1698   }
1699 
1700   if (_VSTD_FS::is_regular_file(st))
1701     __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
1702 
1703   if (_VSTD_FS::exists(st)) {
1704     __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
1705 
1706     // Attempt to extract the mtime, and fail if it's not representable using
1707     // file_time_type. For now we ignore the error, as we'll report it when
1708     // the value is actually used.
1709     error_code ignored_ec;
1710     __data_.__write_time_ =
1711         __extract_last_write_time(__p_, full_st, &ignored_ec);
1712   }
1713 
1714   return failure_ec;
1715 }
1716 #else
__do_refresh()1717 error_code directory_entry::__do_refresh() noexcept {
1718   __data_.__reset();
1719   error_code failure_ec;
1720 
1721   file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
1722   if (!status_known(st)) {
1723     __data_.__reset();
1724     return failure_ec;
1725   }
1726 
1727   if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1728     __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1729     __data_.__type_ = st.type();
1730     __data_.__non_sym_perms_ = st.permissions();
1731   } else { // we have a symlink
1732     __data_.__sym_perms_ = st.permissions();
1733     // Get the information about the linked entity.
1734     // Ignore errors from stat, since we don't want errors regarding symlink
1735     // resolution to be reported to the user.
1736     error_code ignored_ec;
1737     st = _VSTD_FS::status(__p_, ignored_ec);
1738 
1739     __data_.__type_ = st.type();
1740     __data_.__non_sym_perms_ = st.permissions();
1741 
1742     // If we failed to resolve the link, then only partially populate the
1743     // cache.
1744     if (!status_known(st)) {
1745       __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1746       return error_code{};
1747     }
1748     __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1749   }
1750 
1751   // FIXME: This is currently broken, and the implementation only a placeholder.
1752   // We need to cache last_write_time, file_size, and hard_link_count here before
1753   // the implementation actually works.
1754 
1755   return failure_ec;
1756 }
1757 #endif
1758 
1759 _LIBCPP_END_NAMESPACE_FILESYSTEM
1760