1*4bdff4beSrobert //===----------------------------------------------------------------------===//
246035553Spatrick //
346035553Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
446035553Spatrick // See https://llvm.org/LICENSE.txt for license information.
546035553Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
646035553Spatrick //
746035553Spatrick //===----------------------------------------------------------------------===//
846035553Spatrick 
9*4bdff4beSrobert #include <__assert>
10*4bdff4beSrobert #include <__utility/unreachable.h>
11*4bdff4beSrobert #include <array>
12*4bdff4beSrobert #include <climits>
13*4bdff4beSrobert #include <cstdlib>
14*4bdff4beSrobert #include <filesystem>
15*4bdff4beSrobert #include <iterator>
16*4bdff4beSrobert #include <string_view>
17*4bdff4beSrobert #include <type_traits>
18*4bdff4beSrobert #include <vector>
1946035553Spatrick 
2046035553Spatrick #include "filesystem_common.h"
2146035553Spatrick 
2276d0caaeSpatrick #include "posix_compat.h"
2376d0caaeSpatrick 
2476d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
2576d0caaeSpatrick # define WIN32_LEAN_AND_MEAN
2676d0caaeSpatrick # define NOMINMAX
2776d0caaeSpatrick # include <windows.h>
2876d0caaeSpatrick #else
29*4bdff4beSrobert # include <dirent.h>
3046035553Spatrick # include <sys/stat.h>
3146035553Spatrick # include <sys/statvfs.h>
32*4bdff4beSrobert # include <unistd.h>
3376d0caaeSpatrick #endif
3446035553Spatrick #include <time.h>
3546035553Spatrick #include <fcntl.h> /* values for fchmodat */
3646035553Spatrick 
3776d0caaeSpatrick #if __has_include(<sys/sendfile.h>)
3846035553Spatrick # include <sys/sendfile.h>
3976d0caaeSpatrick # define _LIBCPP_FILESYSTEM_USE_SENDFILE
4046035553Spatrick #elif defined(__APPLE__) || __has_include(<copyfile.h>)
4146035553Spatrick # include <copyfile.h>
4276d0caaeSpatrick # define _LIBCPP_FILESYSTEM_USE_COPYFILE
4376d0caaeSpatrick #else
44*4bdff4beSrobert # include <fstream>
4576d0caaeSpatrick # define _LIBCPP_FILESYSTEM_USE_FSTREAM
4646035553Spatrick #endif
4746035553Spatrick 
4876d0caaeSpatrick #if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API)
4946035553Spatrick # include <sys/time.h> // for gettimeofday and timeval
5076d0caaeSpatrick #endif
5146035553Spatrick 
5246035553Spatrick #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
5346035553Spatrick # pragma comment(lib, "rt")
5446035553Spatrick #endif
5546035553Spatrick 
5646035553Spatrick _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
5746035553Spatrick 
5846035553Spatrick namespace {
5976d0caaeSpatrick 
isSeparator(path::value_type C)6076d0caaeSpatrick bool isSeparator(path::value_type C) {
6176d0caaeSpatrick   if (C == '/')
6276d0caaeSpatrick     return true;
6376d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
6476d0caaeSpatrick   if (C == '\\')
6576d0caaeSpatrick     return true;
6676d0caaeSpatrick #endif
6776d0caaeSpatrick   return false;
6876d0caaeSpatrick }
6976d0caaeSpatrick 
isDriveLetter(path::value_type C)7076d0caaeSpatrick bool isDriveLetter(path::value_type C) {
7176d0caaeSpatrick   return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z');
7276d0caaeSpatrick }
7376d0caaeSpatrick 
7446035553Spatrick namespace parser {
7546035553Spatrick 
7646035553Spatrick using string_view_t = path::__string_view;
7746035553Spatrick using string_view_pair = pair<string_view_t, string_view_t>;
7846035553Spatrick using PosPtr = path::value_type const*;
7946035553Spatrick 
8046035553Spatrick struct PathParser {
8146035553Spatrick   enum ParserState : unsigned char {
8246035553Spatrick     // Zero is a special sentinel value used by default constructed iterators.
8346035553Spatrick     PS_BeforeBegin = path::iterator::_BeforeBegin,
8446035553Spatrick     PS_InRootName = path::iterator::_InRootName,
8546035553Spatrick     PS_InRootDir = path::iterator::_InRootDir,
8646035553Spatrick     PS_InFilenames = path::iterator::_InFilenames,
8746035553Spatrick     PS_InTrailingSep = path::iterator::_InTrailingSep,
8846035553Spatrick     PS_AtEnd = path::iterator::_AtEnd
8946035553Spatrick   };
9046035553Spatrick 
9146035553Spatrick   const string_view_t Path;
9246035553Spatrick   string_view_t RawEntry;
9346035553Spatrick   ParserState State;
9446035553Spatrick 
9546035553Spatrick private:
PathParser__anonc9795eb50111::parser::PathParser9646035553Spatrick   PathParser(string_view_t P, ParserState State) noexcept : Path(P),
9746035553Spatrick                                                             State(State) {}
9846035553Spatrick 
9946035553Spatrick public:
PathParser__anonc9795eb50111::parser::PathParser10046035553Spatrick   PathParser(string_view_t P, string_view_t E, unsigned char S)
10146035553Spatrick       : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
10246035553Spatrick     // S cannot be '0' or PS_BeforeBegin.
10346035553Spatrick   }
10446035553Spatrick 
CreateBegin__anonc9795eb50111::parser::PathParser10546035553Spatrick   static PathParser CreateBegin(string_view_t P) noexcept {
10646035553Spatrick     PathParser PP(P, PS_BeforeBegin);
10746035553Spatrick     PP.increment();
10846035553Spatrick     return PP;
10946035553Spatrick   }
11046035553Spatrick 
CreateEnd__anonc9795eb50111::parser::PathParser11146035553Spatrick   static PathParser CreateEnd(string_view_t P) noexcept {
11246035553Spatrick     PathParser PP(P, PS_AtEnd);
11346035553Spatrick     return PP;
11446035553Spatrick   }
11546035553Spatrick 
peek__anonc9795eb50111::parser::PathParser11646035553Spatrick   PosPtr peek() const noexcept {
11746035553Spatrick     auto TkEnd = getNextTokenStartPos();
11846035553Spatrick     auto End = getAfterBack();
11946035553Spatrick     return TkEnd == End ? nullptr : TkEnd;
12046035553Spatrick   }
12146035553Spatrick 
increment__anonc9795eb50111::parser::PathParser12246035553Spatrick   void increment() noexcept {
12346035553Spatrick     const PosPtr End = getAfterBack();
12446035553Spatrick     const PosPtr Start = getNextTokenStartPos();
12546035553Spatrick     if (Start == End)
12646035553Spatrick       return makeState(PS_AtEnd);
12746035553Spatrick 
12846035553Spatrick     switch (State) {
12946035553Spatrick     case PS_BeforeBegin: {
13076d0caaeSpatrick       PosPtr TkEnd = consumeRootName(Start, End);
13176d0caaeSpatrick       if (TkEnd)
13276d0caaeSpatrick         return makeState(PS_InRootName, Start, TkEnd);
13376d0caaeSpatrick     }
13476d0caaeSpatrick       _LIBCPP_FALLTHROUGH();
13576d0caaeSpatrick     case PS_InRootName: {
13676d0caaeSpatrick       PosPtr TkEnd = consumeAllSeparators(Start, End);
13746035553Spatrick       if (TkEnd)
13846035553Spatrick         return makeState(PS_InRootDir, Start, TkEnd);
13946035553Spatrick       else
14046035553Spatrick         return makeState(PS_InFilenames, Start, consumeName(Start, End));
14146035553Spatrick     }
14246035553Spatrick     case PS_InRootDir:
14346035553Spatrick       return makeState(PS_InFilenames, Start, consumeName(Start, End));
14446035553Spatrick 
14546035553Spatrick     case PS_InFilenames: {
14676d0caaeSpatrick       PosPtr SepEnd = consumeAllSeparators(Start, End);
14746035553Spatrick       if (SepEnd != End) {
14846035553Spatrick         PosPtr TkEnd = consumeName(SepEnd, End);
14946035553Spatrick         if (TkEnd)
15046035553Spatrick           return makeState(PS_InFilenames, SepEnd, TkEnd);
15146035553Spatrick       }
15246035553Spatrick       return makeState(PS_InTrailingSep, Start, SepEnd);
15346035553Spatrick     }
15446035553Spatrick 
15546035553Spatrick     case PS_InTrailingSep:
15646035553Spatrick       return makeState(PS_AtEnd);
15746035553Spatrick 
15846035553Spatrick     case PS_AtEnd:
159*4bdff4beSrobert       __libcpp_unreachable();
16046035553Spatrick     }
16146035553Spatrick   }
16246035553Spatrick 
decrement__anonc9795eb50111::parser::PathParser16346035553Spatrick   void decrement() noexcept {
16446035553Spatrick     const PosPtr REnd = getBeforeFront();
16546035553Spatrick     const PosPtr RStart = getCurrentTokenStartPos() - 1;
16646035553Spatrick     if (RStart == REnd) // we're decrementing the begin
16746035553Spatrick       return makeState(PS_BeforeBegin);
16846035553Spatrick 
16946035553Spatrick     switch (State) {
17046035553Spatrick     case PS_AtEnd: {
17146035553Spatrick       // Try to consume a trailing separator or root directory first.
17276d0caaeSpatrick       if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) {
17346035553Spatrick         if (SepEnd == REnd)
17446035553Spatrick           return makeState(PS_InRootDir, Path.data(), RStart + 1);
17576d0caaeSpatrick         PosPtr TkStart = consumeRootName(SepEnd, REnd);
17676d0caaeSpatrick         if (TkStart == REnd)
17776d0caaeSpatrick           return makeState(PS_InRootDir, RStart, RStart + 1);
17846035553Spatrick         return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
17946035553Spatrick       } else {
18076d0caaeSpatrick         PosPtr TkStart = consumeRootName(RStart, REnd);
18176d0caaeSpatrick         if (TkStart == REnd)
18276d0caaeSpatrick           return makeState(PS_InRootName, TkStart + 1, RStart + 1);
18376d0caaeSpatrick         TkStart = consumeName(RStart, REnd);
18446035553Spatrick         return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
18546035553Spatrick       }
18646035553Spatrick     }
18746035553Spatrick     case PS_InTrailingSep:
18846035553Spatrick       return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
18946035553Spatrick                        RStart + 1);
19046035553Spatrick     case PS_InFilenames: {
19176d0caaeSpatrick       PosPtr SepEnd = consumeAllSeparators(RStart, REnd);
19246035553Spatrick       if (SepEnd == REnd)
19346035553Spatrick         return makeState(PS_InRootDir, Path.data(), RStart + 1);
19476d0caaeSpatrick       PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd);
19576d0caaeSpatrick       if (TkStart == REnd) {
19676d0caaeSpatrick         if (SepEnd)
19776d0caaeSpatrick           return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);
19876d0caaeSpatrick         return makeState(PS_InRootName, TkStart + 1, RStart + 1);
19976d0caaeSpatrick       }
20076d0caaeSpatrick       TkStart = consumeName(SepEnd, REnd);
20176d0caaeSpatrick       return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1);
20246035553Spatrick     }
20346035553Spatrick     case PS_InRootDir:
20476d0caaeSpatrick       return makeState(PS_InRootName, Path.data(), RStart + 1);
20546035553Spatrick     case PS_InRootName:
20646035553Spatrick     case PS_BeforeBegin:
207*4bdff4beSrobert       __libcpp_unreachable();
20846035553Spatrick     }
20946035553Spatrick   }
21046035553Spatrick 
21146035553Spatrick   /// \brief Return a view with the "preferred representation" of the current
21246035553Spatrick   ///   element. For example trailing separators are represented as a '.'
operator *__anonc9795eb50111::parser::PathParser21346035553Spatrick   string_view_t operator*() const noexcept {
21446035553Spatrick     switch (State) {
21546035553Spatrick     case PS_BeforeBegin:
21646035553Spatrick     case PS_AtEnd:
217*4bdff4beSrobert       return PATHSTR("");
21846035553Spatrick     case PS_InRootDir:
21976d0caaeSpatrick       if (RawEntry[0] == '\\')
220*4bdff4beSrobert         return PATHSTR("\\");
22176d0caaeSpatrick       else
222*4bdff4beSrobert         return PATHSTR("/");
22346035553Spatrick     case PS_InTrailingSep:
224*4bdff4beSrobert       return PATHSTR("");
22546035553Spatrick     case PS_InRootName:
22646035553Spatrick     case PS_InFilenames:
22746035553Spatrick       return RawEntry;
22846035553Spatrick     }
229*4bdff4beSrobert     __libcpp_unreachable();
23046035553Spatrick   }
23146035553Spatrick 
operator bool__anonc9795eb50111::parser::PathParser23246035553Spatrick   explicit operator bool() const noexcept {
23346035553Spatrick     return State != PS_BeforeBegin && State != PS_AtEnd;
23446035553Spatrick   }
23546035553Spatrick 
operator ++__anonc9795eb50111::parser::PathParser23646035553Spatrick   PathParser& operator++() noexcept {
23746035553Spatrick     increment();
23846035553Spatrick     return *this;
23946035553Spatrick   }
24046035553Spatrick 
operator --__anonc9795eb50111::parser::PathParser24146035553Spatrick   PathParser& operator--() noexcept {
24246035553Spatrick     decrement();
24346035553Spatrick     return *this;
24446035553Spatrick   }
24546035553Spatrick 
atEnd__anonc9795eb50111::parser::PathParser24646035553Spatrick   bool atEnd() const noexcept {
24746035553Spatrick     return State == PS_AtEnd;
24846035553Spatrick   }
24946035553Spatrick 
inRootDir__anonc9795eb50111::parser::PathParser25046035553Spatrick   bool inRootDir() const noexcept {
25146035553Spatrick     return State == PS_InRootDir;
25246035553Spatrick   }
25346035553Spatrick 
inRootName__anonc9795eb50111::parser::PathParser25446035553Spatrick   bool inRootName() const noexcept {
25546035553Spatrick     return State == PS_InRootName;
25646035553Spatrick   }
25746035553Spatrick 
inRootPath__anonc9795eb50111::parser::PathParser25846035553Spatrick   bool inRootPath() const noexcept {
25946035553Spatrick     return inRootName() || inRootDir();
26046035553Spatrick   }
26146035553Spatrick 
26246035553Spatrick private:
makeState__anonc9795eb50111::parser::PathParser26346035553Spatrick   void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
26446035553Spatrick     State = NewState;
26546035553Spatrick     RawEntry = string_view_t(Start, End - Start);
26646035553Spatrick   }
makeState__anonc9795eb50111::parser::PathParser26746035553Spatrick   void makeState(ParserState NewState) noexcept {
26846035553Spatrick     State = NewState;
26946035553Spatrick     RawEntry = {};
27046035553Spatrick   }
27146035553Spatrick 
getAfterBack__anonc9795eb50111::parser::PathParser27246035553Spatrick   PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
27346035553Spatrick 
getBeforeFront__anonc9795eb50111::parser::PathParser27446035553Spatrick   PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
27546035553Spatrick 
27646035553Spatrick   /// \brief Return a pointer to the first character after the currently
27746035553Spatrick   ///   lexed element.
getNextTokenStartPos__anonc9795eb50111::parser::PathParser27846035553Spatrick   PosPtr getNextTokenStartPos() const noexcept {
27946035553Spatrick     switch (State) {
28046035553Spatrick     case PS_BeforeBegin:
28146035553Spatrick       return Path.data();
28246035553Spatrick     case PS_InRootName:
28346035553Spatrick     case PS_InRootDir:
28446035553Spatrick     case PS_InFilenames:
28546035553Spatrick       return &RawEntry.back() + 1;
28646035553Spatrick     case PS_InTrailingSep:
28746035553Spatrick     case PS_AtEnd:
28846035553Spatrick       return getAfterBack();
28946035553Spatrick     }
290*4bdff4beSrobert     __libcpp_unreachable();
29146035553Spatrick   }
29246035553Spatrick 
29346035553Spatrick   /// \brief Return a pointer to the first character in the currently lexed
29446035553Spatrick   ///   element.
getCurrentTokenStartPos__anonc9795eb50111::parser::PathParser29546035553Spatrick   PosPtr getCurrentTokenStartPos() const noexcept {
29646035553Spatrick     switch (State) {
29746035553Spatrick     case PS_BeforeBegin:
29846035553Spatrick     case PS_InRootName:
29946035553Spatrick       return &Path.front();
30046035553Spatrick     case PS_InRootDir:
30146035553Spatrick     case PS_InFilenames:
30246035553Spatrick     case PS_InTrailingSep:
30346035553Spatrick       return &RawEntry.front();
30446035553Spatrick     case PS_AtEnd:
30546035553Spatrick       return &Path.back() + 1;
30646035553Spatrick     }
307*4bdff4beSrobert     __libcpp_unreachable();
30846035553Spatrick   }
30946035553Spatrick 
31076d0caaeSpatrick   // Consume all consecutive separators.
consumeAllSeparators__anonc9795eb50111::parser::PathParser31176d0caaeSpatrick   PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept {
31276d0caaeSpatrick     if (P == nullptr || P == End || !isSeparator(*P))
31346035553Spatrick       return nullptr;
31446035553Spatrick     const int Inc = P < End ? 1 : -1;
31546035553Spatrick     P += Inc;
31676d0caaeSpatrick     while (P != End && isSeparator(*P))
31746035553Spatrick       P += Inc;
31846035553Spatrick     return P;
31946035553Spatrick   }
32046035553Spatrick 
32176d0caaeSpatrick   // Consume exactly N separators, or return nullptr.
consumeNSeparators__anonc9795eb50111::parser::PathParser32276d0caaeSpatrick   PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept {
32376d0caaeSpatrick     PosPtr Ret = consumeAllSeparators(P, End);
32476d0caaeSpatrick     if (Ret == nullptr)
32576d0caaeSpatrick       return nullptr;
32676d0caaeSpatrick     if (P < End) {
32776d0caaeSpatrick       if (Ret == P + N)
32876d0caaeSpatrick         return Ret;
32976d0caaeSpatrick     } else {
33076d0caaeSpatrick       if (Ret == P - N)
33176d0caaeSpatrick         return Ret;
33276d0caaeSpatrick     }
33376d0caaeSpatrick     return nullptr;
33476d0caaeSpatrick   }
33576d0caaeSpatrick 
consumeName__anonc9795eb50111::parser::PathParser33646035553Spatrick   PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
33776d0caaeSpatrick     PosPtr Start = P;
33876d0caaeSpatrick     if (P == nullptr || P == End || isSeparator(*P))
33946035553Spatrick       return nullptr;
34046035553Spatrick     const int Inc = P < End ? 1 : -1;
34146035553Spatrick     P += Inc;
34276d0caaeSpatrick     while (P != End && !isSeparator(*P))
34346035553Spatrick       P += Inc;
34476d0caaeSpatrick     if (P == End && Inc < 0) {
34576d0caaeSpatrick       // Iterating backwards and consumed all the rest of the input.
34676d0caaeSpatrick       // Check if the start of the string would have been considered
34776d0caaeSpatrick       // a root name.
34876d0caaeSpatrick       PosPtr RootEnd = consumeRootName(End + 1, Start);
34976d0caaeSpatrick       if (RootEnd)
35076d0caaeSpatrick         return RootEnd - 1;
35176d0caaeSpatrick     }
35246035553Spatrick     return P;
35346035553Spatrick   }
35476d0caaeSpatrick 
consumeDriveLetter__anonc9795eb50111::parser::PathParser35576d0caaeSpatrick   PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept {
35676d0caaeSpatrick     if (P == End)
35776d0caaeSpatrick       return nullptr;
35876d0caaeSpatrick     if (P < End) {
35976d0caaeSpatrick       if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':')
36076d0caaeSpatrick         return nullptr;
36176d0caaeSpatrick       return P + 2;
36276d0caaeSpatrick     } else {
36376d0caaeSpatrick       if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':')
36476d0caaeSpatrick         return nullptr;
36576d0caaeSpatrick       return P - 2;
36676d0caaeSpatrick     }
36776d0caaeSpatrick   }
36876d0caaeSpatrick 
consumeNetworkRoot__anonc9795eb50111::parser::PathParser36976d0caaeSpatrick   PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept {
37076d0caaeSpatrick     if (P == End)
37176d0caaeSpatrick       return nullptr;
37276d0caaeSpatrick     if (P < End)
37376d0caaeSpatrick       return consumeName(consumeNSeparators(P, End, 2), End);
37476d0caaeSpatrick     else
37576d0caaeSpatrick       return consumeNSeparators(consumeName(P, End), End, 2);
37676d0caaeSpatrick   }
37776d0caaeSpatrick 
consumeRootName__anonc9795eb50111::parser::PathParser37876d0caaeSpatrick   PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept {
37976d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
38076d0caaeSpatrick     if (PosPtr Ret = consumeDriveLetter(P, End))
38176d0caaeSpatrick       return Ret;
38276d0caaeSpatrick     if (PosPtr Ret = consumeNetworkRoot(P, End))
38376d0caaeSpatrick       return Ret;
38476d0caaeSpatrick #endif
38576d0caaeSpatrick     return nullptr;
38676d0caaeSpatrick   }
38746035553Spatrick };
38846035553Spatrick 
separate_filename(string_view_t const & s)38946035553Spatrick string_view_pair separate_filename(string_view_t const& s) {
390*4bdff4beSrobert   if (s == PATHSTR(".") || s == PATHSTR("..") || s.empty())
391*4bdff4beSrobert     return string_view_pair{s, PATHSTR("")};
39246035553Spatrick   auto pos = s.find_last_of('.');
39346035553Spatrick   if (pos == string_view_t::npos || pos == 0)
39446035553Spatrick     return string_view_pair{s, string_view_t{}};
39546035553Spatrick   return string_view_pair{s.substr(0, pos), s.substr(pos)};
39646035553Spatrick }
39746035553Spatrick 
createView(PosPtr S,PosPtr E)39846035553Spatrick string_view_t createView(PosPtr S, PosPtr E) noexcept {
39946035553Spatrick   return {S, static_cast<size_t>(E - S) + 1};
40046035553Spatrick }
40146035553Spatrick 
40246035553Spatrick } // namespace parser
40346035553Spatrick } // namespace
40446035553Spatrick 
40546035553Spatrick //                       POSIX HELPERS
40646035553Spatrick 
40776d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
40876d0caaeSpatrick namespace detail {
40976d0caaeSpatrick 
__win_err_to_errc(int err)41076d0caaeSpatrick errc __win_err_to_errc(int err) {
41176d0caaeSpatrick   constexpr struct {
41276d0caaeSpatrick     DWORD win;
41376d0caaeSpatrick     errc errc;
41476d0caaeSpatrick   } win_error_mapping[] = {
41576d0caaeSpatrick       {ERROR_ACCESS_DENIED, errc::permission_denied},
41676d0caaeSpatrick       {ERROR_ALREADY_EXISTS, errc::file_exists},
41776d0caaeSpatrick       {ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
41876d0caaeSpatrick       {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
41976d0caaeSpatrick       {ERROR_BAD_UNIT, errc::no_such_device},
42076d0caaeSpatrick       {ERROR_BROKEN_PIPE, errc::broken_pipe},
42176d0caaeSpatrick       {ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
42276d0caaeSpatrick       {ERROR_BUSY, errc::device_or_resource_busy},
42376d0caaeSpatrick       {ERROR_BUSY_DRIVE, errc::device_or_resource_busy},
42476d0caaeSpatrick       {ERROR_CANNOT_MAKE, errc::permission_denied},
42576d0caaeSpatrick       {ERROR_CANTOPEN, errc::io_error},
42676d0caaeSpatrick       {ERROR_CANTREAD, errc::io_error},
42776d0caaeSpatrick       {ERROR_CANTWRITE, errc::io_error},
42876d0caaeSpatrick       {ERROR_CURRENT_DIRECTORY, errc::permission_denied},
42976d0caaeSpatrick       {ERROR_DEV_NOT_EXIST, errc::no_such_device},
43076d0caaeSpatrick       {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy},
43176d0caaeSpatrick       {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty},
43276d0caaeSpatrick       {ERROR_DIRECTORY, errc::invalid_argument},
43376d0caaeSpatrick       {ERROR_DISK_FULL, errc::no_space_on_device},
43476d0caaeSpatrick       {ERROR_FILE_EXISTS, errc::file_exists},
43576d0caaeSpatrick       {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory},
43676d0caaeSpatrick       {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device},
43776d0caaeSpatrick       {ERROR_INVALID_ACCESS, errc::permission_denied},
43876d0caaeSpatrick       {ERROR_INVALID_DRIVE, errc::no_such_device},
43976d0caaeSpatrick       {ERROR_INVALID_FUNCTION, errc::function_not_supported},
44076d0caaeSpatrick       {ERROR_INVALID_HANDLE, errc::invalid_argument},
44176d0caaeSpatrick       {ERROR_INVALID_NAME, errc::no_such_file_or_directory},
44276d0caaeSpatrick       {ERROR_INVALID_PARAMETER, errc::invalid_argument},
44376d0caaeSpatrick       {ERROR_LOCK_VIOLATION, errc::no_lock_available},
44476d0caaeSpatrick       {ERROR_LOCKED, errc::no_lock_available},
44576d0caaeSpatrick       {ERROR_NEGATIVE_SEEK, errc::invalid_argument},
44676d0caaeSpatrick       {ERROR_NOACCESS, errc::permission_denied},
44776d0caaeSpatrick       {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory},
44876d0caaeSpatrick       {ERROR_NOT_READY, errc::resource_unavailable_try_again},
44976d0caaeSpatrick       {ERROR_NOT_SAME_DEVICE, errc::cross_device_link},
45076d0caaeSpatrick       {ERROR_NOT_SUPPORTED, errc::not_supported},
45176d0caaeSpatrick       {ERROR_OPEN_FAILED, errc::io_error},
45276d0caaeSpatrick       {ERROR_OPEN_FILES, errc::device_or_resource_busy},
45376d0caaeSpatrick       {ERROR_OPERATION_ABORTED, errc::operation_canceled},
45476d0caaeSpatrick       {ERROR_OUTOFMEMORY, errc::not_enough_memory},
45576d0caaeSpatrick       {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory},
45676d0caaeSpatrick       {ERROR_READ_FAULT, errc::io_error},
45776d0caaeSpatrick       {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument},
45876d0caaeSpatrick       {ERROR_RETRY, errc::resource_unavailable_try_again},
45976d0caaeSpatrick       {ERROR_SEEK, errc::io_error},
46076d0caaeSpatrick       {ERROR_SHARING_VIOLATION, errc::permission_denied},
46176d0caaeSpatrick       {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open},
46276d0caaeSpatrick       {ERROR_WRITE_FAULT, errc::io_error},
46376d0caaeSpatrick       {ERROR_WRITE_PROTECT, errc::permission_denied},
46476d0caaeSpatrick   };
46576d0caaeSpatrick 
46676d0caaeSpatrick   for (const auto &pair : win_error_mapping)
46776d0caaeSpatrick     if (pair.win == static_cast<DWORD>(err))
46876d0caaeSpatrick       return pair.errc;
46976d0caaeSpatrick   return errc::invalid_argument;
47076d0caaeSpatrick }
47176d0caaeSpatrick 
47276d0caaeSpatrick } // namespace detail
47376d0caaeSpatrick #endif
47476d0caaeSpatrick 
47546035553Spatrick namespace detail {
47646035553Spatrick namespace {
47746035553Spatrick 
47846035553Spatrick using value_type = path::value_type;
47946035553Spatrick using string_type = path::string_type;
48046035553Spatrick 
48146035553Spatrick struct FileDescriptor {
48246035553Spatrick   const path& name;
48346035553Spatrick   int fd = -1;
48446035553Spatrick   StatT m_stat;
48546035553Spatrick   file_status m_status;
48646035553Spatrick 
48746035553Spatrick   template <class... Args>
createdetail::__anonc9795eb50311::FileDescriptor48846035553Spatrick   static FileDescriptor create(const path* p, error_code& ec, Args... args) {
48946035553Spatrick     ec.clear();
49046035553Spatrick     int fd;
49176d0caaeSpatrick     if ((fd = detail::open(p->c_str(), args...)) == -1) {
49246035553Spatrick       ec = capture_errno();
49346035553Spatrick       return FileDescriptor{p};
49446035553Spatrick     }
49546035553Spatrick     return FileDescriptor(p, fd);
49646035553Spatrick   }
49746035553Spatrick 
49846035553Spatrick   template <class... Args>
create_with_statusdetail::__anonc9795eb50311::FileDescriptor49946035553Spatrick   static FileDescriptor create_with_status(const path* p, error_code& ec,
50046035553Spatrick                                            Args... args) {
50146035553Spatrick     FileDescriptor fd = create(p, ec, args...);
50246035553Spatrick     if (!ec)
50346035553Spatrick       fd.refresh_status(ec);
50446035553Spatrick 
50546035553Spatrick     return fd;
50646035553Spatrick   }
50746035553Spatrick 
get_statusdetail::__anonc9795eb50311::FileDescriptor50846035553Spatrick   file_status get_status() const { return m_status; }
get_statdetail::__anonc9795eb50311::FileDescriptor50946035553Spatrick   StatT const& get_stat() const { return m_stat; }
51046035553Spatrick 
status_knowndetail::__anonc9795eb50311::FileDescriptor51146035553Spatrick   bool status_known() const { return _VSTD_FS::status_known(m_status); }
51246035553Spatrick 
51346035553Spatrick   file_status refresh_status(error_code& ec);
51446035553Spatrick 
closedetail::__anonc9795eb50311::FileDescriptor51546035553Spatrick   void close() noexcept {
51646035553Spatrick     if (fd != -1)
51776d0caaeSpatrick       detail::close(fd);
51846035553Spatrick     fd = -1;
51946035553Spatrick   }
52046035553Spatrick 
FileDescriptordetail::__anonc9795eb50311::FileDescriptor52146035553Spatrick   FileDescriptor(FileDescriptor&& other)
52246035553Spatrick       : name(other.name), fd(other.fd), m_stat(other.m_stat),
52346035553Spatrick         m_status(other.m_status) {
52446035553Spatrick     other.fd = -1;
52546035553Spatrick     other.m_status = file_status{};
52646035553Spatrick   }
52746035553Spatrick 
~FileDescriptordetail::__anonc9795eb50311::FileDescriptor52846035553Spatrick   ~FileDescriptor() { close(); }
52946035553Spatrick 
53046035553Spatrick   FileDescriptor(FileDescriptor const&) = delete;
53146035553Spatrick   FileDescriptor& operator=(FileDescriptor const&) = delete;
53246035553Spatrick 
53346035553Spatrick private:
FileDescriptordetail::__anonc9795eb50311::FileDescriptor53446035553Spatrick   explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {}
53546035553Spatrick };
53646035553Spatrick 
posix_get_perms(const StatT & st)53746035553Spatrick perms posix_get_perms(const StatT& st) noexcept {
53846035553Spatrick   return static_cast<perms>(st.st_mode) & perms::mask;
53946035553Spatrick }
54046035553Spatrick 
create_file_status(error_code & m_ec,path const & p,const StatT & path_stat,error_code * ec)54146035553Spatrick file_status create_file_status(error_code& m_ec, path const& p,
54246035553Spatrick                                const StatT& path_stat, error_code* ec) {
54346035553Spatrick   if (ec)
54446035553Spatrick     *ec = m_ec;
54546035553Spatrick   if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
54646035553Spatrick     return file_status(file_type::not_found);
54746035553Spatrick   } else if (m_ec) {
54846035553Spatrick     ErrorHandler<void> err("posix_stat", ec, &p);
54946035553Spatrick     err.report(m_ec, "failed to determine attributes for the specified path");
55046035553Spatrick     return file_status(file_type::none);
55146035553Spatrick   }
55246035553Spatrick   // else
55346035553Spatrick 
55446035553Spatrick   file_status fs_tmp;
55546035553Spatrick   auto const mode = path_stat.st_mode;
55646035553Spatrick   if (S_ISLNK(mode))
55746035553Spatrick     fs_tmp.type(file_type::symlink);
55846035553Spatrick   else if (S_ISREG(mode))
55946035553Spatrick     fs_tmp.type(file_type::regular);
56046035553Spatrick   else if (S_ISDIR(mode))
56146035553Spatrick     fs_tmp.type(file_type::directory);
56246035553Spatrick   else if (S_ISBLK(mode))
56346035553Spatrick     fs_tmp.type(file_type::block);
56446035553Spatrick   else if (S_ISCHR(mode))
56546035553Spatrick     fs_tmp.type(file_type::character);
56646035553Spatrick   else if (S_ISFIFO(mode))
56746035553Spatrick     fs_tmp.type(file_type::fifo);
56846035553Spatrick   else if (S_ISSOCK(mode))
56946035553Spatrick     fs_tmp.type(file_type::socket);
57046035553Spatrick   else
57146035553Spatrick     fs_tmp.type(file_type::unknown);
57246035553Spatrick 
57346035553Spatrick   fs_tmp.permissions(detail::posix_get_perms(path_stat));
57446035553Spatrick   return fs_tmp;
57546035553Spatrick }
57646035553Spatrick 
posix_stat(path const & p,StatT & path_stat,error_code * ec)57746035553Spatrick file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
57846035553Spatrick   error_code m_ec;
57976d0caaeSpatrick   if (detail::stat(p.c_str(), &path_stat) == -1)
58046035553Spatrick     m_ec = detail::capture_errno();
58146035553Spatrick   return create_file_status(m_ec, p, path_stat, ec);
58246035553Spatrick }
58346035553Spatrick 
posix_stat(path const & p,error_code * ec)58446035553Spatrick file_status posix_stat(path const& p, error_code* ec) {
58546035553Spatrick   StatT path_stat;
58646035553Spatrick   return posix_stat(p, path_stat, ec);
58746035553Spatrick }
58846035553Spatrick 
posix_lstat(path const & p,StatT & path_stat,error_code * ec)58946035553Spatrick file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
59046035553Spatrick   error_code m_ec;
59176d0caaeSpatrick   if (detail::lstat(p.c_str(), &path_stat) == -1)
59246035553Spatrick     m_ec = detail::capture_errno();
59346035553Spatrick   return create_file_status(m_ec, p, path_stat, ec);
59446035553Spatrick }
59546035553Spatrick 
posix_lstat(path const & p,error_code * ec)59646035553Spatrick file_status posix_lstat(path const& p, error_code* ec) {
59746035553Spatrick   StatT path_stat;
59846035553Spatrick   return posix_lstat(p, path_stat, ec);
59946035553Spatrick }
60046035553Spatrick 
60146035553Spatrick // http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
posix_ftruncate(const FileDescriptor & fd,off_t to_size,error_code & ec)60246035553Spatrick bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
60376d0caaeSpatrick   if (detail::ftruncate(fd.fd, to_size) == -1) {
60446035553Spatrick     ec = capture_errno();
60546035553Spatrick     return true;
60646035553Spatrick   }
60746035553Spatrick   ec.clear();
60846035553Spatrick   return false;
60946035553Spatrick }
61046035553Spatrick 
posix_fchmod(const FileDescriptor & fd,const StatT & st,error_code & ec)61146035553Spatrick bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
61276d0caaeSpatrick   if (detail::fchmod(fd.fd, st.st_mode) == -1) {
61346035553Spatrick     ec = capture_errno();
61446035553Spatrick     return true;
61546035553Spatrick   }
61646035553Spatrick   ec.clear();
61746035553Spatrick   return false;
61846035553Spatrick }
61946035553Spatrick 
stat_equivalent(const StatT & st1,const StatT & st2)62046035553Spatrick bool stat_equivalent(const StatT& st1, const StatT& st2) {
62146035553Spatrick   return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
62246035553Spatrick }
62346035553Spatrick 
refresh_status(error_code & ec)62446035553Spatrick file_status FileDescriptor::refresh_status(error_code& ec) {
62546035553Spatrick   // FD must be open and good.
62646035553Spatrick   m_status = file_status{};
62746035553Spatrick   m_stat = {};
62846035553Spatrick   error_code m_ec;
62976d0caaeSpatrick   if (detail::fstat(fd, &m_stat) == -1)
63046035553Spatrick     m_ec = capture_errno();
63146035553Spatrick   m_status = create_file_status(m_ec, name, m_stat, &ec);
63246035553Spatrick   return m_status;
63346035553Spatrick }
63446035553Spatrick } // namespace
63546035553Spatrick } // end namespace detail
63646035553Spatrick 
63746035553Spatrick using detail::capture_errno;
63846035553Spatrick using detail::ErrorHandler;
63946035553Spatrick using detail::StatT;
64046035553Spatrick using detail::TimeSpec;
64146035553Spatrick using parser::createView;
64246035553Spatrick using parser::PathParser;
64346035553Spatrick using parser::string_view_t;
64446035553Spatrick 
64546035553Spatrick const bool _FilesystemClock::is_steady;
64646035553Spatrick 
now()64746035553Spatrick _FilesystemClock::time_point _FilesystemClock::now() noexcept {
64846035553Spatrick   typedef chrono::duration<rep> __secs;
64976d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
65076d0caaeSpatrick   typedef chrono::duration<rep, nano> __nsecs;
65176d0caaeSpatrick   FILETIME time;
65276d0caaeSpatrick   GetSystemTimeAsFileTime(&time);
65376d0caaeSpatrick   TimeSpec tp = detail::filetime_to_timespec(time);
65476d0caaeSpatrick   return time_point(__secs(tp.tv_sec) +
65576d0caaeSpatrick                     chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
65676d0caaeSpatrick #elif defined(CLOCK_REALTIME)
65746035553Spatrick   typedef chrono::duration<rep, nano> __nsecs;
65846035553Spatrick   struct timespec tp;
65946035553Spatrick   if (0 != clock_gettime(CLOCK_REALTIME, &tp))
66046035553Spatrick     __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
66146035553Spatrick   return time_point(__secs(tp.tv_sec) +
66246035553Spatrick                     chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
66346035553Spatrick #else
66446035553Spatrick   typedef chrono::duration<rep, micro> __microsecs;
66546035553Spatrick   timeval tv;
66646035553Spatrick   gettimeofday(&tv, 0);
66746035553Spatrick   return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
668037e7968Spatrick #endif // CLOCK_REALTIME
66946035553Spatrick }
67046035553Spatrick 
~filesystem_error()67146035553Spatrick filesystem_error::~filesystem_error() {}
67246035553Spatrick 
__create_what(int __num_paths)67346035553Spatrick void filesystem_error::__create_what(int __num_paths) {
67446035553Spatrick   const char* derived_what = system_error::what();
67546035553Spatrick   __storage_->__what_ = [&]() -> string {
67646035553Spatrick     switch (__num_paths) {
67776d0caaeSpatrick     case 0:
67846035553Spatrick       return detail::format_string("filesystem error: %s", derived_what);
67946035553Spatrick     case 1:
68076d0caaeSpatrick       return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "]",
68176d0caaeSpatrick                                    derived_what, path1().c_str());
68246035553Spatrick     case 2:
68376d0caaeSpatrick       return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "] [" PATH_CSTR_FMT "]",
68476d0caaeSpatrick                                    derived_what, path1().c_str(), path2().c_str());
68546035553Spatrick     }
686*4bdff4beSrobert     __libcpp_unreachable();
68746035553Spatrick   }();
68846035553Spatrick }
68946035553Spatrick 
__do_absolute(const path & p,path * cwd,error_code * ec)69046035553Spatrick static path __do_absolute(const path& p, path* cwd, error_code* ec) {
69146035553Spatrick   if (ec)
69246035553Spatrick     ec->clear();
69346035553Spatrick   if (p.is_absolute())
69446035553Spatrick     return p;
69546035553Spatrick   *cwd = __current_path(ec);
69646035553Spatrick   if (ec && *ec)
69746035553Spatrick     return {};
69846035553Spatrick   return (*cwd) / p;
69946035553Spatrick }
70046035553Spatrick 
__absolute(const path & p,error_code * ec)70146035553Spatrick path __absolute(const path& p, error_code* ec) {
70246035553Spatrick   path cwd;
70346035553Spatrick   return __do_absolute(p, &cwd, ec);
70446035553Spatrick }
70546035553Spatrick 
__canonical(path const & orig_p,error_code * ec)70646035553Spatrick path __canonical(path const& orig_p, error_code* ec) {
70746035553Spatrick   path cwd;
70846035553Spatrick   ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
70946035553Spatrick 
71046035553Spatrick   path p = __do_absolute(orig_p, &cwd, ec);
71176d0caaeSpatrick #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
71276d0caaeSpatrick   std::unique_ptr<path::value_type, decltype(&::free)>
71376d0caaeSpatrick     hold(detail::realpath(p.c_str(), nullptr), &::free);
71446035553Spatrick   if (hold.get() == nullptr)
71546035553Spatrick     return err.report(capture_errno());
71646035553Spatrick   return {hold.get()};
71746035553Spatrick #else
71876d0caaeSpatrick   #if defined(__MVS__) && !defined(PATH_MAX)
71976d0caaeSpatrick     path::value_type buff[ _XOPEN_PATH_MAX + 1 ];
72076d0caaeSpatrick   #else
72176d0caaeSpatrick     path::value_type buff[PATH_MAX + 1];
72276d0caaeSpatrick   #endif
72376d0caaeSpatrick   path::value_type* ret;
72476d0caaeSpatrick   if ((ret = detail::realpath(p.c_str(), buff)) == nullptr)
72546035553Spatrick     return err.report(capture_errno());
72646035553Spatrick   return {ret};
72746035553Spatrick #endif
72846035553Spatrick }
72946035553Spatrick 
__copy(const path & from,const path & to,copy_options options,error_code * ec)73046035553Spatrick void __copy(const path& from, const path& to, copy_options options,
73146035553Spatrick             error_code* ec) {
73246035553Spatrick   ErrorHandler<void> err("copy", ec, &from, &to);
73346035553Spatrick 
73446035553Spatrick   const bool sym_status = bool(
73546035553Spatrick       options & (copy_options::create_symlinks | copy_options::skip_symlinks));
73646035553Spatrick 
73746035553Spatrick   const bool sym_status2 = bool(options & copy_options::copy_symlinks);
73846035553Spatrick 
73946035553Spatrick   error_code m_ec1;
74046035553Spatrick   StatT f_st = {};
74146035553Spatrick   const file_status f = sym_status || sym_status2
74246035553Spatrick                             ? detail::posix_lstat(from, f_st, &m_ec1)
74346035553Spatrick                             : detail::posix_stat(from, f_st, &m_ec1);
74446035553Spatrick   if (m_ec1)
74546035553Spatrick     return err.report(m_ec1);
74646035553Spatrick 
74746035553Spatrick   StatT t_st = {};
74846035553Spatrick   const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
74946035553Spatrick                                    : detail::posix_stat(to, t_st, &m_ec1);
75046035553Spatrick 
75146035553Spatrick   if (not status_known(t))
75246035553Spatrick     return err.report(m_ec1);
75346035553Spatrick 
75446035553Spatrick   if (!exists(f) || is_other(f) || is_other(t) ||
75546035553Spatrick       (is_directory(f) && is_regular_file(t)) ||
75646035553Spatrick       detail::stat_equivalent(f_st, t_st)) {
75746035553Spatrick     return err.report(errc::function_not_supported);
75846035553Spatrick   }
75946035553Spatrick 
76046035553Spatrick   if (ec)
76146035553Spatrick     ec->clear();
76246035553Spatrick 
76346035553Spatrick   if (is_symlink(f)) {
76446035553Spatrick     if (bool(copy_options::skip_symlinks & options)) {
76546035553Spatrick       // do nothing
76646035553Spatrick     } else if (not exists(t)) {
76746035553Spatrick       __copy_symlink(from, to, ec);
76846035553Spatrick     } else {
76946035553Spatrick       return err.report(errc::file_exists);
77046035553Spatrick     }
77146035553Spatrick     return;
77246035553Spatrick   } else if (is_regular_file(f)) {
77346035553Spatrick     if (bool(copy_options::directories_only & options)) {
77446035553Spatrick       // do nothing
77546035553Spatrick     } else if (bool(copy_options::create_symlinks & options)) {
77646035553Spatrick       __create_symlink(from, to, ec);
77746035553Spatrick     } else if (bool(copy_options::create_hard_links & options)) {
77846035553Spatrick       __create_hard_link(from, to, ec);
77946035553Spatrick     } else if (is_directory(t)) {
78046035553Spatrick       __copy_file(from, to / from.filename(), options, ec);
78146035553Spatrick     } else {
78246035553Spatrick       __copy_file(from, to, options, ec);
78346035553Spatrick     }
78446035553Spatrick     return;
78546035553Spatrick   } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
78646035553Spatrick     return err.report(errc::is_a_directory);
78746035553Spatrick   } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
78846035553Spatrick                                  copy_options::none == options)) {
78946035553Spatrick 
79046035553Spatrick     if (!exists(t)) {
79146035553Spatrick       // create directory to with attributes from 'from'.
79246035553Spatrick       __create_directory(to, from, ec);
79346035553Spatrick       if (ec && *ec) {
79446035553Spatrick         return;
79546035553Spatrick       }
79646035553Spatrick     }
79746035553Spatrick     directory_iterator it =
79846035553Spatrick         ec ? directory_iterator(from, *ec) : directory_iterator(from);
79946035553Spatrick     if (ec && *ec) {
80046035553Spatrick       return;
80146035553Spatrick     }
80246035553Spatrick     error_code m_ec2;
80346035553Spatrick     for (; it != directory_iterator(); it.increment(m_ec2)) {
80446035553Spatrick       if (m_ec2) {
80546035553Spatrick         return err.report(m_ec2);
80646035553Spatrick       }
80746035553Spatrick       __copy(it->path(), to / it->path().filename(),
80846035553Spatrick              options | copy_options::__in_recursive_copy, ec);
80946035553Spatrick       if (ec && *ec) {
81046035553Spatrick         return;
81146035553Spatrick       }
81246035553Spatrick     }
81346035553Spatrick   }
81446035553Spatrick }
81546035553Spatrick 
81646035553Spatrick namespace detail {
81746035553Spatrick namespace {
81846035553Spatrick 
81976d0caaeSpatrick #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
copy_file_impl(FileDescriptor & read_fd,FileDescriptor & write_fd,error_code & ec)82076d0caaeSpatrick   bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
82146035553Spatrick     size_t count = read_fd.get_stat().st_size;
82246035553Spatrick     do {
82346035553Spatrick       ssize_t res;
82446035553Spatrick       if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
82546035553Spatrick         ec = capture_errno();
82646035553Spatrick         return false;
82746035553Spatrick       }
82846035553Spatrick       count -= res;
82946035553Spatrick     } while (count > 0);
83046035553Spatrick 
83146035553Spatrick     ec.clear();
83246035553Spatrick 
83346035553Spatrick     return true;
83446035553Spatrick   }
83576d0caaeSpatrick #elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
83676d0caaeSpatrick   bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
83746035553Spatrick     struct CopyFileState {
83846035553Spatrick       copyfile_state_t state;
83946035553Spatrick       CopyFileState() { state = copyfile_state_alloc(); }
84046035553Spatrick       ~CopyFileState() { copyfile_state_free(state); }
84146035553Spatrick 
84246035553Spatrick     private:
84346035553Spatrick       CopyFileState(CopyFileState const&) = delete;
84446035553Spatrick       CopyFileState& operator=(CopyFileState const&) = delete;
84546035553Spatrick     };
84646035553Spatrick 
84746035553Spatrick     CopyFileState cfs;
84846035553Spatrick     if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
84946035553Spatrick       ec = capture_errno();
85046035553Spatrick       return false;
85146035553Spatrick     }
85246035553Spatrick 
85346035553Spatrick     ec.clear();
85446035553Spatrick     return true;
85546035553Spatrick   }
85676d0caaeSpatrick #elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
85776d0caaeSpatrick   bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
85846035553Spatrick     ifstream in;
85946035553Spatrick     in.__open(read_fd.fd, ios::binary);
86046035553Spatrick     if (!in.is_open()) {
86146035553Spatrick       // This assumes that __open didn't reset the error code.
86246035553Spatrick       ec = capture_errno();
86346035553Spatrick       return false;
86446035553Spatrick     }
86576d0caaeSpatrick     read_fd.fd = -1;
86646035553Spatrick     ofstream out;
86746035553Spatrick     out.__open(write_fd.fd, ios::binary);
86846035553Spatrick     if (!out.is_open()) {
86946035553Spatrick       ec = capture_errno();
87046035553Spatrick       return false;
87146035553Spatrick     }
87276d0caaeSpatrick     write_fd.fd = -1;
87346035553Spatrick 
87446035553Spatrick     if (in.good() && out.good()) {
87546035553Spatrick       using InIt = istreambuf_iterator<char>;
87646035553Spatrick       using OutIt = ostreambuf_iterator<char>;
87746035553Spatrick       InIt bin(in);
87846035553Spatrick       InIt ein;
87946035553Spatrick       OutIt bout(out);
88046035553Spatrick       copy(bin, ein, bout);
88146035553Spatrick     }
88246035553Spatrick     if (out.fail() || in.fail()) {
88346035553Spatrick       ec = make_error_code(errc::io_error);
88446035553Spatrick       return false;
88546035553Spatrick     }
88646035553Spatrick 
88746035553Spatrick     ec.clear();
88846035553Spatrick     return true;
88946035553Spatrick   }
89046035553Spatrick #else
89176d0caaeSpatrick # error "Unknown implementation for copy_file_impl"
89276d0caaeSpatrick #endif // copy_file_impl implementation
89346035553Spatrick 
89476d0caaeSpatrick } // end anonymous namespace
89576d0caaeSpatrick } // end namespace detail
89646035553Spatrick 
__copy_file(const path & from,const path & to,copy_options options,error_code * ec)89746035553Spatrick bool __copy_file(const path& from, const path& to, copy_options options,
89846035553Spatrick                  error_code* ec) {
89946035553Spatrick   using detail::FileDescriptor;
90046035553Spatrick   ErrorHandler<bool> err("copy_file", ec, &to, &from);
90146035553Spatrick 
90246035553Spatrick   error_code m_ec;
90376d0caaeSpatrick   FileDescriptor from_fd = FileDescriptor::create_with_status(
90476d0caaeSpatrick       &from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY);
90546035553Spatrick   if (m_ec)
90646035553Spatrick     return err.report(m_ec);
90746035553Spatrick 
90846035553Spatrick   auto from_st = from_fd.get_status();
90946035553Spatrick   StatT const& from_stat = from_fd.get_stat();
91046035553Spatrick   if (!is_regular_file(from_st)) {
91146035553Spatrick     if (not m_ec)
91246035553Spatrick       m_ec = make_error_code(errc::not_supported);
91346035553Spatrick     return err.report(m_ec);
91446035553Spatrick   }
91546035553Spatrick 
91646035553Spatrick   const bool skip_existing = bool(copy_options::skip_existing & options);
91746035553Spatrick   const bool update_existing = bool(copy_options::update_existing & options);
91846035553Spatrick   const bool overwrite_existing =
91946035553Spatrick       bool(copy_options::overwrite_existing & options);
92046035553Spatrick 
92146035553Spatrick   StatT to_stat_path;
92246035553Spatrick   file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
92346035553Spatrick   if (!status_known(to_st))
92446035553Spatrick     return err.report(m_ec);
92546035553Spatrick 
92646035553Spatrick   const bool to_exists = exists(to_st);
92746035553Spatrick   if (to_exists && !is_regular_file(to_st))
92846035553Spatrick     return err.report(errc::not_supported);
92946035553Spatrick 
93046035553Spatrick   if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
93146035553Spatrick     return err.report(errc::file_exists);
93246035553Spatrick 
93346035553Spatrick   if (to_exists && skip_existing)
93446035553Spatrick     return false;
93546035553Spatrick 
93646035553Spatrick   bool ShouldCopy = [&]() {
93746035553Spatrick     if (to_exists && update_existing) {
93846035553Spatrick       auto from_time = detail::extract_mtime(from_stat);
93946035553Spatrick       auto to_time = detail::extract_mtime(to_stat_path);
94046035553Spatrick       if (from_time.tv_sec < to_time.tv_sec)
94146035553Spatrick         return false;
94246035553Spatrick       if (from_time.tv_sec == to_time.tv_sec &&
94346035553Spatrick           from_time.tv_nsec <= to_time.tv_nsec)
94446035553Spatrick         return false;
94546035553Spatrick       return true;
94646035553Spatrick     }
94746035553Spatrick     if (!to_exists || overwrite_existing)
94846035553Spatrick       return true;
94946035553Spatrick     return err.report(errc::file_exists);
95046035553Spatrick   }();
95146035553Spatrick   if (!ShouldCopy)
95246035553Spatrick     return false;
95346035553Spatrick 
95446035553Spatrick   // Don't truncate right away. We may not be opening the file we originally
95546035553Spatrick   // looked at; we'll check this later.
95676d0caaeSpatrick   int to_open_flags = O_WRONLY | O_BINARY;
95746035553Spatrick   if (!to_exists)
95846035553Spatrick     to_open_flags |= O_CREAT;
95946035553Spatrick   FileDescriptor to_fd = FileDescriptor::create_with_status(
96046035553Spatrick       &to, m_ec, to_open_flags, from_stat.st_mode);
96146035553Spatrick   if (m_ec)
96246035553Spatrick     return err.report(m_ec);
96346035553Spatrick 
96446035553Spatrick   if (to_exists) {
96546035553Spatrick     // Check that the file we initially stat'ed is equivalent to the one
96646035553Spatrick     // we opened.
96746035553Spatrick     // FIXME: report this better.
96846035553Spatrick     if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
96946035553Spatrick       return err.report(errc::bad_file_descriptor);
97046035553Spatrick 
97146035553Spatrick     // Set the permissions and truncate the file we opened.
97246035553Spatrick     if (detail::posix_fchmod(to_fd, from_stat, m_ec))
97346035553Spatrick       return err.report(m_ec);
97446035553Spatrick     if (detail::posix_ftruncate(to_fd, 0, m_ec))
97546035553Spatrick       return err.report(m_ec);
97646035553Spatrick   }
97746035553Spatrick 
97846035553Spatrick   if (!copy_file_impl(from_fd, to_fd, m_ec)) {
97946035553Spatrick     // FIXME: Remove the dest file if we failed, and it didn't exist previously.
98046035553Spatrick     return err.report(m_ec);
98146035553Spatrick   }
98246035553Spatrick 
98346035553Spatrick   return true;
98446035553Spatrick }
98546035553Spatrick 
__copy_symlink(const path & existing_symlink,const path & new_symlink,error_code * ec)98646035553Spatrick void __copy_symlink(const path& existing_symlink, const path& new_symlink,
98746035553Spatrick                     error_code* ec) {
98846035553Spatrick   const path real_path(__read_symlink(existing_symlink, ec));
98946035553Spatrick   if (ec && *ec) {
99046035553Spatrick     return;
99146035553Spatrick   }
99276d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
99376d0caaeSpatrick   error_code local_ec;
99476d0caaeSpatrick   if (is_directory(real_path, local_ec))
99576d0caaeSpatrick     __create_directory_symlink(real_path, new_symlink, ec);
99676d0caaeSpatrick   else
99776d0caaeSpatrick #endif
99846035553Spatrick     __create_symlink(real_path, new_symlink, ec);
99946035553Spatrick }
100046035553Spatrick 
__create_directories(const path & p,error_code * ec)100146035553Spatrick bool __create_directories(const path& p, error_code* ec) {
100246035553Spatrick   ErrorHandler<bool> err("create_directories", ec, &p);
100346035553Spatrick 
100446035553Spatrick   error_code m_ec;
100546035553Spatrick   auto const st = detail::posix_stat(p, &m_ec);
100646035553Spatrick   if (!status_known(st))
100746035553Spatrick     return err.report(m_ec);
100846035553Spatrick   else if (is_directory(st))
100946035553Spatrick     return false;
101046035553Spatrick   else if (exists(st))
101146035553Spatrick     return err.report(errc::file_exists);
101246035553Spatrick 
101346035553Spatrick   const path parent = p.parent_path();
101446035553Spatrick   if (!parent.empty()) {
101546035553Spatrick     const file_status parent_st = status(parent, m_ec);
101646035553Spatrick     if (not status_known(parent_st))
101746035553Spatrick       return err.report(m_ec);
101846035553Spatrick     if (not exists(parent_st)) {
101976d0caaeSpatrick       if (parent == p)
102076d0caaeSpatrick         return err.report(errc::invalid_argument);
102146035553Spatrick       __create_directories(parent, ec);
102246035553Spatrick       if (ec && *ec) {
102346035553Spatrick         return false;
102446035553Spatrick       }
102576d0caaeSpatrick     } else if (not is_directory(parent_st))
102676d0caaeSpatrick       return err.report(errc::not_a_directory);
102746035553Spatrick   }
102876d0caaeSpatrick   bool ret = __create_directory(p, &m_ec);
102976d0caaeSpatrick   if (m_ec)
103076d0caaeSpatrick     return err.report(m_ec);
103176d0caaeSpatrick   return ret;
103246035553Spatrick }
103346035553Spatrick 
__create_directory(const path & p,error_code * ec)103446035553Spatrick bool __create_directory(const path& p, error_code* ec) {
103546035553Spatrick   ErrorHandler<bool> err("create_directory", ec, &p);
103646035553Spatrick 
103776d0caaeSpatrick   if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
103846035553Spatrick     return true;
103976d0caaeSpatrick 
104046035553Spatrick   if (errno != EEXIST)
104176d0caaeSpatrick     return err.report(capture_errno());
104276d0caaeSpatrick   error_code mec = capture_errno();
104376d0caaeSpatrick   error_code ignored_ec;
104476d0caaeSpatrick   const file_status st = status(p, ignored_ec);
104576d0caaeSpatrick   if (!is_directory(st))
104676d0caaeSpatrick     return err.report(mec);
104746035553Spatrick   return false;
104846035553Spatrick }
104946035553Spatrick 
__create_directory(path const & p,path const & attributes,error_code * ec)105046035553Spatrick bool __create_directory(path const& p, path const& attributes, error_code* ec) {
105146035553Spatrick   ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
105246035553Spatrick 
105346035553Spatrick   StatT attr_stat;
105446035553Spatrick   error_code mec;
105576d0caaeSpatrick   file_status st = detail::posix_stat(attributes, attr_stat, &mec);
105646035553Spatrick   if (!status_known(st))
105746035553Spatrick     return err.report(mec);
105846035553Spatrick   if (!is_directory(st))
105946035553Spatrick     return err.report(errc::not_a_directory,
106046035553Spatrick                       "the specified attribute path is invalid");
106146035553Spatrick 
106276d0caaeSpatrick   if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0)
106346035553Spatrick     return true;
106476d0caaeSpatrick 
106546035553Spatrick   if (errno != EEXIST)
106676d0caaeSpatrick     return err.report(capture_errno());
106776d0caaeSpatrick 
106876d0caaeSpatrick   mec = capture_errno();
106976d0caaeSpatrick   error_code ignored_ec;
107076d0caaeSpatrick   st = status(p, ignored_ec);
107176d0caaeSpatrick   if (!is_directory(st))
107276d0caaeSpatrick     return err.report(mec);
107346035553Spatrick   return false;
107446035553Spatrick }
107546035553Spatrick 
__create_directory_symlink(path const & from,path const & to,error_code * ec)107646035553Spatrick void __create_directory_symlink(path const& from, path const& to,
107746035553Spatrick                                 error_code* ec) {
107846035553Spatrick   ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
107976d0caaeSpatrick   if (detail::symlink_dir(from.c_str(), to.c_str()) == -1)
108046035553Spatrick     return err.report(capture_errno());
108146035553Spatrick }
108246035553Spatrick 
__create_hard_link(const path & from,const path & to,error_code * ec)108346035553Spatrick void __create_hard_link(const path& from, const path& to, error_code* ec) {
108446035553Spatrick   ErrorHandler<void> err("create_hard_link", ec, &from, &to);
108576d0caaeSpatrick   if (detail::link(from.c_str(), to.c_str()) == -1)
108646035553Spatrick     return err.report(capture_errno());
108746035553Spatrick }
108846035553Spatrick 
__create_symlink(path const & from,path const & to,error_code * ec)108946035553Spatrick void __create_symlink(path const& from, path const& to, error_code* ec) {
109046035553Spatrick   ErrorHandler<void> err("create_symlink", ec, &from, &to);
109176d0caaeSpatrick   if (detail::symlink_file(from.c_str(), to.c_str()) == -1)
109246035553Spatrick     return err.report(capture_errno());
109346035553Spatrick }
109446035553Spatrick 
__current_path(error_code * ec)109546035553Spatrick path __current_path(error_code* ec) {
109646035553Spatrick   ErrorHandler<path> err("current_path", ec);
109746035553Spatrick 
109876d0caaeSpatrick #if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__)
109976d0caaeSpatrick   // Common extension outside of POSIX getcwd() spec, without needing to
110076d0caaeSpatrick   // preallocate a buffer. Also supported by a number of other POSIX libcs.
110176d0caaeSpatrick   int size = 0;
110276d0caaeSpatrick   path::value_type* ptr = nullptr;
110376d0caaeSpatrick   typedef decltype(&::free) Deleter;
110476d0caaeSpatrick   Deleter deleter = &::free;
110576d0caaeSpatrick #else
110646035553Spatrick   auto size = ::pathconf(".", _PC_PATH_MAX);
110746035553Spatrick   _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
110846035553Spatrick 
110976d0caaeSpatrick   auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]);
111076d0caaeSpatrick   path::value_type* ptr = buff.get();
111176d0caaeSpatrick 
111276d0caaeSpatrick   // Preallocated buffer, don't free the buffer in the second unique_ptr
111376d0caaeSpatrick   // below.
111476d0caaeSpatrick   struct Deleter { void operator()(void*) const {} };
111576d0caaeSpatrick   Deleter deleter;
111676d0caaeSpatrick #endif
111776d0caaeSpatrick 
111876d0caaeSpatrick   unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size),
111976d0caaeSpatrick                                              deleter);
112076d0caaeSpatrick   if (hold.get() == nullptr)
112146035553Spatrick     return err.report(capture_errno(), "call to getcwd failed");
112246035553Spatrick 
112376d0caaeSpatrick   return {hold.get()};
112446035553Spatrick }
112546035553Spatrick 
__current_path(const path & p,error_code * ec)112646035553Spatrick void __current_path(const path& p, error_code* ec) {
112746035553Spatrick   ErrorHandler<void> err("current_path", ec, &p);
112876d0caaeSpatrick   if (detail::chdir(p.c_str()) == -1)
112946035553Spatrick     err.report(capture_errno());
113046035553Spatrick }
113146035553Spatrick 
__equivalent(const path & p1,const path & p2,error_code * ec)113246035553Spatrick bool __equivalent(const path& p1, const path& p2, error_code* ec) {
113346035553Spatrick   ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
113446035553Spatrick 
113546035553Spatrick   error_code ec1, ec2;
113646035553Spatrick   StatT st1 = {}, st2 = {};
113746035553Spatrick   auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
113846035553Spatrick   if (!exists(s1))
113946035553Spatrick     return err.report(errc::not_supported);
114046035553Spatrick   auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
114146035553Spatrick   if (!exists(s2))
114246035553Spatrick     return err.report(errc::not_supported);
114346035553Spatrick 
114446035553Spatrick   return detail::stat_equivalent(st1, st2);
114546035553Spatrick }
114646035553Spatrick 
__file_size(const path & p,error_code * ec)114746035553Spatrick uintmax_t __file_size(const path& p, error_code* ec) {
114846035553Spatrick   ErrorHandler<uintmax_t> err("file_size", ec, &p);
114946035553Spatrick 
115046035553Spatrick   error_code m_ec;
115146035553Spatrick   StatT st;
115246035553Spatrick   file_status fst = detail::posix_stat(p, st, &m_ec);
115346035553Spatrick   if (!exists(fst) || !is_regular_file(fst)) {
115446035553Spatrick     errc error_kind =
115546035553Spatrick         is_directory(fst) ? errc::is_a_directory : errc::not_supported;
115646035553Spatrick     if (!m_ec)
115746035553Spatrick       m_ec = make_error_code(error_kind);
115846035553Spatrick     return err.report(m_ec);
115946035553Spatrick   }
116046035553Spatrick   // is_regular_file(p) == true
116146035553Spatrick   return static_cast<uintmax_t>(st.st_size);
116246035553Spatrick }
116346035553Spatrick 
__hard_link_count(const path & p,error_code * ec)116446035553Spatrick uintmax_t __hard_link_count(const path& p, error_code* ec) {
116546035553Spatrick   ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
116646035553Spatrick 
116746035553Spatrick   error_code m_ec;
116846035553Spatrick   StatT st;
116946035553Spatrick   detail::posix_stat(p, st, &m_ec);
117046035553Spatrick   if (m_ec)
117146035553Spatrick     return err.report(m_ec);
117246035553Spatrick   return static_cast<uintmax_t>(st.st_nlink);
117346035553Spatrick }
117446035553Spatrick 
__fs_is_empty(const path & p,error_code * ec)117546035553Spatrick bool __fs_is_empty(const path& p, error_code* ec) {
117646035553Spatrick   ErrorHandler<bool> err("is_empty", ec, &p);
117746035553Spatrick 
117846035553Spatrick   error_code m_ec;
117946035553Spatrick   StatT pst;
118046035553Spatrick   auto st = detail::posix_stat(p, pst, &m_ec);
118146035553Spatrick   if (m_ec)
118246035553Spatrick     return err.report(m_ec);
118346035553Spatrick   else if (!is_directory(st) && !is_regular_file(st))
118446035553Spatrick     return err.report(errc::not_supported);
118546035553Spatrick   else if (is_directory(st)) {
118646035553Spatrick     auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
118746035553Spatrick     if (ec && *ec)
118846035553Spatrick       return false;
118946035553Spatrick     return it == directory_iterator{};
119046035553Spatrick   } else if (is_regular_file(st))
119146035553Spatrick     return static_cast<uintmax_t>(pst.st_size) == 0;
119246035553Spatrick 
1193*4bdff4beSrobert   __libcpp_unreachable();
119446035553Spatrick }
119546035553Spatrick 
__extract_last_write_time(const path & p,const StatT & st,error_code * ec)119646035553Spatrick static file_time_type __extract_last_write_time(const path& p, const StatT& st,
119746035553Spatrick                                                 error_code* ec) {
119846035553Spatrick   using detail::fs_time;
119946035553Spatrick   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
120046035553Spatrick 
120146035553Spatrick   auto ts = detail::extract_mtime(st);
120246035553Spatrick   if (!fs_time::is_representable(ts))
120346035553Spatrick     return err.report(errc::value_too_large);
120446035553Spatrick 
120546035553Spatrick   return fs_time::convert_from_timespec(ts);
120646035553Spatrick }
120746035553Spatrick 
__last_write_time(const path & p,error_code * ec)120846035553Spatrick file_time_type __last_write_time(const path& p, error_code* ec) {
120946035553Spatrick   using namespace chrono;
121046035553Spatrick   ErrorHandler<file_time_type> err("last_write_time", ec, &p);
121146035553Spatrick 
121246035553Spatrick   error_code m_ec;
121346035553Spatrick   StatT st;
121446035553Spatrick   detail::posix_stat(p, st, &m_ec);
121546035553Spatrick   if (m_ec)
121646035553Spatrick     return err.report(m_ec);
121746035553Spatrick   return __extract_last_write_time(p, st, ec);
121846035553Spatrick }
121946035553Spatrick 
__last_write_time(const path & p,file_time_type new_time,error_code * ec)122046035553Spatrick void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
122146035553Spatrick   using detail::fs_time;
122246035553Spatrick   ErrorHandler<void> err("last_write_time", ec, &p);
122346035553Spatrick 
122476d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
122576d0caaeSpatrick   TimeSpec ts;
122676d0caaeSpatrick   if (!fs_time::convert_to_timespec(ts, new_time))
122776d0caaeSpatrick     return err.report(errc::value_too_large);
122876d0caaeSpatrick   detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0);
122976d0caaeSpatrick   if (!h)
123076d0caaeSpatrick     return err.report(detail::make_windows_error(GetLastError()));
123176d0caaeSpatrick   FILETIME last_write = timespec_to_filetime(ts);
123276d0caaeSpatrick   if (!SetFileTime(h, nullptr, nullptr, &last_write))
123376d0caaeSpatrick     return err.report(detail::make_windows_error(GetLastError()));
123476d0caaeSpatrick #else
123546035553Spatrick   error_code m_ec;
123646035553Spatrick   array<TimeSpec, 2> tbuf;
123746035553Spatrick #if !defined(_LIBCPP_USE_UTIMENSAT)
123846035553Spatrick   // This implementation has a race condition between determining the
123946035553Spatrick   // last access time and attempting to set it to the same value using
124046035553Spatrick   // ::utimes
124146035553Spatrick   StatT st;
124246035553Spatrick   file_status fst = detail::posix_stat(p, st, &m_ec);
124346035553Spatrick   if (m_ec)
124446035553Spatrick     return err.report(m_ec);
124546035553Spatrick   tbuf[0] = detail::extract_atime(st);
124646035553Spatrick #else
124746035553Spatrick   tbuf[0].tv_sec = 0;
124846035553Spatrick   tbuf[0].tv_nsec = UTIME_OMIT;
124946035553Spatrick #endif
125046035553Spatrick   if (!fs_time::convert_to_timespec(tbuf[1], new_time))
125146035553Spatrick     return err.report(errc::value_too_large);
125246035553Spatrick 
125346035553Spatrick   detail::set_file_times(p, tbuf, m_ec);
125446035553Spatrick   if (m_ec)
125546035553Spatrick     return err.report(m_ec);
125676d0caaeSpatrick #endif
125746035553Spatrick }
125846035553Spatrick 
__permissions(const path & p,perms prms,perm_options opts,error_code * ec)125946035553Spatrick void __permissions(const path& p, perms prms, perm_options opts,
126046035553Spatrick                    error_code* ec) {
126146035553Spatrick   ErrorHandler<void> err("permissions", ec, &p);
126246035553Spatrick 
126346035553Spatrick   auto has_opt = [&](perm_options o) { return bool(o & opts); };
126446035553Spatrick   const bool resolve_symlinks = !has_opt(perm_options::nofollow);
126546035553Spatrick   const bool add_perms = has_opt(perm_options::add);
126646035553Spatrick   const bool remove_perms = has_opt(perm_options::remove);
126746035553Spatrick   _LIBCPP_ASSERT(
126846035553Spatrick       (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
126946035553Spatrick       "One and only one of the perm_options constants replace, add, or remove "
127046035553Spatrick       "is present in opts");
127146035553Spatrick 
127246035553Spatrick   bool set_sym_perms = false;
127346035553Spatrick   prms &= perms::mask;
127446035553Spatrick   if (!resolve_symlinks || (add_perms || remove_perms)) {
127546035553Spatrick     error_code m_ec;
127646035553Spatrick     file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
127746035553Spatrick                                       : detail::posix_lstat(p, &m_ec);
127846035553Spatrick     set_sym_perms = is_symlink(st);
127946035553Spatrick     if (m_ec)
128046035553Spatrick       return err.report(m_ec);
128146035553Spatrick     _LIBCPP_ASSERT(st.permissions() != perms::unknown,
128246035553Spatrick                    "Permissions unexpectedly unknown");
128346035553Spatrick     if (add_perms)
128446035553Spatrick       prms |= st.permissions();
128546035553Spatrick     else if (remove_perms)
128646035553Spatrick       prms = st.permissions() & ~prms;
128746035553Spatrick   }
128876d0caaeSpatrick   const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask);
128946035553Spatrick 
129046035553Spatrick #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
129146035553Spatrick   const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
129276d0caaeSpatrick   if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
129346035553Spatrick     return err.report(capture_errno());
129446035553Spatrick   }
129546035553Spatrick #else
129646035553Spatrick   if (set_sym_perms)
129746035553Spatrick     return err.report(errc::operation_not_supported);
129846035553Spatrick   if (::chmod(p.c_str(), real_perms) == -1) {
129946035553Spatrick     return err.report(capture_errno());
130046035553Spatrick   }
130146035553Spatrick #endif
130246035553Spatrick }
130346035553Spatrick 
__read_symlink(const path & p,error_code * ec)130446035553Spatrick path __read_symlink(const path& p, error_code* ec) {
130546035553Spatrick   ErrorHandler<path> err("read_symlink", ec, &p);
130646035553Spatrick 
130776d0caaeSpatrick #if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE)
130846035553Spatrick   struct NullDeleter { void operator()(void*) const {} };
130976d0caaeSpatrick #ifdef MAX_SYMLINK_SIZE
131076d0caaeSpatrick   const size_t size = MAX_SYMLINK_SIZE + 1;
131176d0caaeSpatrick #else
131246035553Spatrick   const size_t size = PATH_MAX + 1;
131376d0caaeSpatrick #endif
131476d0caaeSpatrick   path::value_type stack_buff[size];
131576d0caaeSpatrick   auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff);
131646035553Spatrick #else
131746035553Spatrick   StatT sb;
131876d0caaeSpatrick   if (detail::lstat(p.c_str(), &sb) == -1) {
131946035553Spatrick     return err.report(capture_errno());
132046035553Spatrick   }
132146035553Spatrick   const size_t size = sb.st_size + 1;
132276d0caaeSpatrick   auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]);
132346035553Spatrick #endif
132476d0caaeSpatrick   detail::SSizeT ret;
132576d0caaeSpatrick   if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1)
132646035553Spatrick     return err.report(capture_errno());
132746035553Spatrick   _LIBCPP_ASSERT(ret > 0, "TODO");
132846035553Spatrick   if (static_cast<size_t>(ret) >= size)
132946035553Spatrick     return err.report(errc::value_too_large);
133046035553Spatrick   buff[ret] = 0;
133146035553Spatrick   return {buff.get()};
133246035553Spatrick }
133346035553Spatrick 
__remove(const path & p,error_code * ec)133446035553Spatrick bool __remove(const path& p, error_code* ec) {
133546035553Spatrick   ErrorHandler<bool> err("remove", ec, &p);
133676d0caaeSpatrick   if (detail::remove(p.c_str()) == -1) {
133746035553Spatrick     if (errno != ENOENT)
133846035553Spatrick       err.report(capture_errno());
133946035553Spatrick     return false;
134046035553Spatrick   }
134146035553Spatrick   return true;
134246035553Spatrick }
134346035553Spatrick 
1344*4bdff4beSrobert // We currently have two implementations of `__remove_all`. The first one is general and
1345*4bdff4beSrobert // used on platforms where we don't have access to the `openat()` family of POSIX functions.
1346*4bdff4beSrobert // That implementation uses `directory_iterator`, however it is vulnerable to some race
1347*4bdff4beSrobert // conditions, see https://reviews.llvm.org/D118134 for details.
1348*4bdff4beSrobert //
1349*4bdff4beSrobert // The second implementation is used on platforms where `openat()` & friends are available,
1350*4bdff4beSrobert // and it threads file descriptors through recursive calls to avoid such race conditions.
1351*4bdff4beSrobert #if defined(_LIBCPP_WIN32API) || defined (__MVS__)
1352*4bdff4beSrobert # define REMOVE_ALL_USE_DIRECTORY_ITERATOR
1353*4bdff4beSrobert #endif
1354*4bdff4beSrobert 
1355*4bdff4beSrobert #if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR)
1356*4bdff4beSrobert 
135746035553Spatrick namespace {
135846035553Spatrick 
remove_all_impl(path const & p,error_code & ec)135946035553Spatrick uintmax_t remove_all_impl(path const& p, error_code& ec) {
136046035553Spatrick   const auto npos = static_cast<uintmax_t>(-1);
136146035553Spatrick   const file_status st = __symlink_status(p, &ec);
136246035553Spatrick   if (ec)
136346035553Spatrick     return npos;
136446035553Spatrick   uintmax_t count = 1;
136546035553Spatrick   if (is_directory(st)) {
136646035553Spatrick     for (directory_iterator it(p, ec); !ec && it != directory_iterator();
136746035553Spatrick          it.increment(ec)) {
136846035553Spatrick       auto other_count = remove_all_impl(it->path(), ec);
136946035553Spatrick       if (ec)
137046035553Spatrick         return npos;
137146035553Spatrick       count += other_count;
137246035553Spatrick     }
137346035553Spatrick     if (ec)
137446035553Spatrick       return npos;
137546035553Spatrick   }
137646035553Spatrick   if (!__remove(p, &ec))
137746035553Spatrick     return npos;
137846035553Spatrick   return count;
137946035553Spatrick }
138046035553Spatrick 
138146035553Spatrick } // end namespace
138246035553Spatrick 
__remove_all(const path & p,error_code * ec)138346035553Spatrick uintmax_t __remove_all(const path& p, error_code* ec) {
138446035553Spatrick   ErrorHandler<uintmax_t> err("remove_all", ec, &p);
138546035553Spatrick 
138646035553Spatrick   error_code mec;
138746035553Spatrick   auto count = remove_all_impl(p, mec);
138846035553Spatrick   if (mec) {
138946035553Spatrick     if (mec == errc::no_such_file_or_directory)
139046035553Spatrick       return 0;
139146035553Spatrick     return err.report(mec);
139246035553Spatrick   }
139346035553Spatrick   return count;
139446035553Spatrick }
139546035553Spatrick 
1396*4bdff4beSrobert #else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR
1397*4bdff4beSrobert 
1398*4bdff4beSrobert namespace {
1399*4bdff4beSrobert 
1400*4bdff4beSrobert template <class Cleanup>
1401*4bdff4beSrobert struct scope_exit {
scope_exit__anonc9795eb50911::scope_exit1402*4bdff4beSrobert   explicit scope_exit(Cleanup const& cleanup)
1403*4bdff4beSrobert     : cleanup_(cleanup)
1404*4bdff4beSrobert   { }
1405*4bdff4beSrobert 
~scope_exit__anonc9795eb50911::scope_exit1406*4bdff4beSrobert   ~scope_exit() { cleanup_(); }
1407*4bdff4beSrobert 
1408*4bdff4beSrobert private:
1409*4bdff4beSrobert   Cleanup cleanup_;
1410*4bdff4beSrobert };
1411*4bdff4beSrobert _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scope_exit);
1412*4bdff4beSrobert 
remove_all_impl(int parent_directory,const path & p,error_code & ec)1413*4bdff4beSrobert uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) {
1414*4bdff4beSrobert   // First, try to open the path as a directory.
1415*4bdff4beSrobert   const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW;
1416*4bdff4beSrobert   int fd = ::openat(parent_directory, p.c_str(), options);
1417*4bdff4beSrobert   if (fd != -1) {
1418*4bdff4beSrobert     // If that worked, iterate over the contents of the directory and
1419*4bdff4beSrobert     // remove everything in it, recursively.
1420*4bdff4beSrobert     DIR* stream = ::fdopendir(fd);
1421*4bdff4beSrobert     if (stream == nullptr) {
1422*4bdff4beSrobert       ::close(fd);
1423*4bdff4beSrobert       ec = detail::capture_errno();
1424*4bdff4beSrobert       return 0;
1425*4bdff4beSrobert     }
1426*4bdff4beSrobert     // Note: `::closedir` will also close the associated file descriptor, so
1427*4bdff4beSrobert     // there should be no call to `close(fd)`.
1428*4bdff4beSrobert     scope_exit close_stream([=] { ::closedir(stream); });
1429*4bdff4beSrobert 
1430*4bdff4beSrobert     uintmax_t count = 0;
1431*4bdff4beSrobert     while (true) {
1432*4bdff4beSrobert       auto [str, type] = detail::posix_readdir(stream, ec);
1433*4bdff4beSrobert       static_assert(std::is_same_v<decltype(str), std::string_view>);
1434*4bdff4beSrobert       if (str == "." || str == "..") {
1435*4bdff4beSrobert         continue;
1436*4bdff4beSrobert       } else if (ec || str.empty()) {
1437*4bdff4beSrobert         break; // we're done iterating through the directory
1438*4bdff4beSrobert       } else {
1439*4bdff4beSrobert         count += remove_all_impl(fd, str, ec);
1440*4bdff4beSrobert       }
1441*4bdff4beSrobert     }
1442*4bdff4beSrobert 
1443*4bdff4beSrobert     // Then, remove the now-empty directory itself.
1444*4bdff4beSrobert     if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) {
1445*4bdff4beSrobert       ec = detail::capture_errno();
1446*4bdff4beSrobert       return count;
1447*4bdff4beSrobert     }
1448*4bdff4beSrobert 
1449*4bdff4beSrobert     return count + 1; // the contents of the directory + the directory itself
1450*4bdff4beSrobert   }
1451*4bdff4beSrobert 
1452*4bdff4beSrobert   ec = detail::capture_errno();
1453*4bdff4beSrobert 
1454*4bdff4beSrobert   // If we failed to open `p` because it didn't exist, it's not an
1455*4bdff4beSrobert   // error -- it might have moved or have been deleted already.
1456*4bdff4beSrobert   if (ec == errc::no_such_file_or_directory) {
1457*4bdff4beSrobert     ec.clear();
1458*4bdff4beSrobert     return 0;
1459*4bdff4beSrobert   }
1460*4bdff4beSrobert 
1461*4bdff4beSrobert   // If opening `p` failed because it wasn't a directory, remove it as
1462*4bdff4beSrobert   // a normal file instead. Note that `openat()` can return either ENOTDIR
1463*4bdff4beSrobert   // or ELOOP depending on the exact reason of the failure.
1464*4bdff4beSrobert   if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels) {
1465*4bdff4beSrobert     ec.clear();
1466*4bdff4beSrobert     if (::unlinkat(parent_directory, p.c_str(), /* flags = */0) == -1) {
1467*4bdff4beSrobert       ec = detail::capture_errno();
1468*4bdff4beSrobert       return 0;
1469*4bdff4beSrobert     }
1470*4bdff4beSrobert     return 1;
1471*4bdff4beSrobert   }
1472*4bdff4beSrobert 
1473*4bdff4beSrobert   // Otherwise, it's a real error -- we don't remove anything.
1474*4bdff4beSrobert   return 0;
1475*4bdff4beSrobert }
1476*4bdff4beSrobert 
1477*4bdff4beSrobert } // end namespace
1478*4bdff4beSrobert 
__remove_all(const path & p,error_code * ec)1479*4bdff4beSrobert uintmax_t __remove_all(const path& p, error_code* ec) {
1480*4bdff4beSrobert   ErrorHandler<uintmax_t> err("remove_all", ec, &p);
1481*4bdff4beSrobert   error_code mec;
1482*4bdff4beSrobert   uintmax_t count = remove_all_impl(AT_FDCWD, p, mec);
1483*4bdff4beSrobert   if (mec)
1484*4bdff4beSrobert     return err.report(mec);
1485*4bdff4beSrobert   return count;
1486*4bdff4beSrobert }
1487*4bdff4beSrobert 
1488*4bdff4beSrobert #endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR
1489*4bdff4beSrobert 
__rename(const path & from,const path & to,error_code * ec)149046035553Spatrick void __rename(const path& from, const path& to, error_code* ec) {
149146035553Spatrick   ErrorHandler<void> err("rename", ec, &from, &to);
149276d0caaeSpatrick   if (detail::rename(from.c_str(), to.c_str()) == -1)
149346035553Spatrick     err.report(capture_errno());
149446035553Spatrick }
149546035553Spatrick 
__resize_file(const path & p,uintmax_t size,error_code * ec)149646035553Spatrick void __resize_file(const path& p, uintmax_t size, error_code* ec) {
149746035553Spatrick   ErrorHandler<void> err("resize_file", ec, &p);
149876d0caaeSpatrick   if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
149946035553Spatrick     return err.report(capture_errno());
150046035553Spatrick }
150146035553Spatrick 
__space(const path & p,error_code * ec)150246035553Spatrick space_info __space(const path& p, error_code* ec) {
150346035553Spatrick   ErrorHandler<void> err("space", ec, &p);
150446035553Spatrick   space_info si;
150576d0caaeSpatrick   detail::StatVFS m_svfs = {};
150676d0caaeSpatrick   if (detail::statvfs(p.c_str(), &m_svfs) == -1) {
150746035553Spatrick     err.report(capture_errno());
150846035553Spatrick     si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
150946035553Spatrick     return si;
151046035553Spatrick   }
151146035553Spatrick   // Multiply with overflow checking.
151246035553Spatrick   auto do_mult = [&](uintmax_t& out, uintmax_t other) {
151346035553Spatrick     out = other * m_svfs.f_frsize;
151446035553Spatrick     if (other == 0 || out / other != m_svfs.f_frsize)
151546035553Spatrick       out = static_cast<uintmax_t>(-1);
151646035553Spatrick   };
151746035553Spatrick   do_mult(si.capacity, m_svfs.f_blocks);
151846035553Spatrick   do_mult(si.free, m_svfs.f_bfree);
151946035553Spatrick   do_mult(si.available, m_svfs.f_bavail);
152046035553Spatrick   return si;
152146035553Spatrick }
152246035553Spatrick 
__status(const path & p,error_code * ec)152346035553Spatrick file_status __status(const path& p, error_code* ec) {
152446035553Spatrick   return detail::posix_stat(p, ec);
152546035553Spatrick }
152646035553Spatrick 
__symlink_status(const path & p,error_code * ec)152746035553Spatrick file_status __symlink_status(const path& p, error_code* ec) {
152846035553Spatrick   return detail::posix_lstat(p, ec);
152946035553Spatrick }
153046035553Spatrick 
__temp_directory_path(error_code * ec)153146035553Spatrick path __temp_directory_path(error_code* ec) {
153246035553Spatrick   ErrorHandler<path> err("temp_directory_path", ec);
153346035553Spatrick 
153476d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
153576d0caaeSpatrick   wchar_t buf[MAX_PATH];
153676d0caaeSpatrick   DWORD retval = GetTempPathW(MAX_PATH, buf);
153776d0caaeSpatrick   if (!retval)
153876d0caaeSpatrick     return err.report(detail::make_windows_error(GetLastError()));
153976d0caaeSpatrick   if (retval > MAX_PATH)
154076d0caaeSpatrick     return err.report(errc::filename_too_long);
154176d0caaeSpatrick   // GetTempPathW returns a path with a trailing slash, which we
154276d0caaeSpatrick   // shouldn't include for consistency.
154376d0caaeSpatrick   if (buf[retval-1] == L'\\')
154476d0caaeSpatrick     buf[retval-1] = L'\0';
154576d0caaeSpatrick   path p(buf);
154676d0caaeSpatrick #else
154746035553Spatrick   const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
154846035553Spatrick   const char* ret = nullptr;
154946035553Spatrick 
155046035553Spatrick   for (auto& ep : env_paths)
155146035553Spatrick     if ((ret = getenv(ep)))
155246035553Spatrick       break;
155346035553Spatrick   if (ret == nullptr)
155446035553Spatrick     ret = "/tmp";
155546035553Spatrick 
155646035553Spatrick   path p(ret);
155776d0caaeSpatrick #endif
155846035553Spatrick   error_code m_ec;
155946035553Spatrick   file_status st = detail::posix_stat(p, &m_ec);
156046035553Spatrick   if (!status_known(st))
156176d0caaeSpatrick     return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str());
156246035553Spatrick 
156346035553Spatrick   if (!exists(st) || !is_directory(st))
156476d0caaeSpatrick     return err.report(errc::not_a_directory,
156576d0caaeSpatrick                       "path " PATH_CSTR_FMT " is not a directory", p.c_str());
156646035553Spatrick 
156746035553Spatrick   return p;
156846035553Spatrick }
156946035553Spatrick 
__weakly_canonical(const path & p,error_code * ec)157046035553Spatrick path __weakly_canonical(const path& p, error_code* ec) {
157146035553Spatrick   ErrorHandler<path> err("weakly_canonical", ec, &p);
157246035553Spatrick 
157346035553Spatrick   if (p.empty())
157446035553Spatrick     return __canonical("", ec);
157546035553Spatrick 
157646035553Spatrick   path result;
157746035553Spatrick   path tmp;
157846035553Spatrick   tmp.__reserve(p.native().size());
157946035553Spatrick   auto PP = PathParser::CreateEnd(p.native());
158046035553Spatrick   --PP;
158146035553Spatrick   vector<string_view_t> DNEParts;
158246035553Spatrick 
158346035553Spatrick   while (PP.State != PathParser::PS_BeforeBegin) {
158446035553Spatrick     tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
158546035553Spatrick     error_code m_ec;
158646035553Spatrick     file_status st = __status(tmp, &m_ec);
158746035553Spatrick     if (!status_known(st)) {
158846035553Spatrick       return err.report(m_ec);
158946035553Spatrick     } else if (exists(st)) {
159046035553Spatrick       result = __canonical(tmp, ec);
159146035553Spatrick       break;
159246035553Spatrick     }
159346035553Spatrick     DNEParts.push_back(*PP);
159446035553Spatrick     --PP;
159546035553Spatrick   }
159646035553Spatrick   if (PP.State == PathParser::PS_BeforeBegin)
159746035553Spatrick     result = __canonical("", ec);
159846035553Spatrick   if (ec)
159946035553Spatrick     ec->clear();
160046035553Spatrick   if (DNEParts.empty())
160146035553Spatrick     return result;
160246035553Spatrick   for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
160346035553Spatrick     result /= *It;
160446035553Spatrick   return result.lexically_normal();
160546035553Spatrick }
160646035553Spatrick 
160746035553Spatrick ///////////////////////////////////////////////////////////////////////////////
160846035553Spatrick //                            path definitions
160946035553Spatrick ///////////////////////////////////////////////////////////////////////////////
161046035553Spatrick 
161146035553Spatrick constexpr path::value_type path::preferred_separator;
161246035553Spatrick 
replace_extension(path const & replacement)161346035553Spatrick path& path::replace_extension(path const& replacement) {
161446035553Spatrick   path p = extension();
161546035553Spatrick   if (not p.empty()) {
161646035553Spatrick     __pn_.erase(__pn_.size() - p.native().size());
161746035553Spatrick   }
161846035553Spatrick   if (!replacement.empty()) {
161946035553Spatrick     if (replacement.native()[0] != '.') {
1620*4bdff4beSrobert       __pn_ += PATHSTR(".");
162146035553Spatrick     }
162246035553Spatrick     __pn_.append(replacement.__pn_);
162346035553Spatrick   }
162446035553Spatrick   return *this;
162546035553Spatrick }
162646035553Spatrick 
162746035553Spatrick ///////////////////////////////////////////////////////////////////////////////
162846035553Spatrick // path.decompose
162946035553Spatrick 
__root_name() const163046035553Spatrick string_view_t path::__root_name() const {
163146035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
163246035553Spatrick   if (PP.State == PathParser::PS_InRootName)
163346035553Spatrick     return *PP;
163446035553Spatrick   return {};
163546035553Spatrick }
163646035553Spatrick 
__root_directory() const163746035553Spatrick string_view_t path::__root_directory() const {
163846035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
163946035553Spatrick   if (PP.State == PathParser::PS_InRootName)
164046035553Spatrick     ++PP;
164146035553Spatrick   if (PP.State == PathParser::PS_InRootDir)
164246035553Spatrick     return *PP;
164346035553Spatrick   return {};
164446035553Spatrick }
164546035553Spatrick 
__root_path_raw() const164646035553Spatrick string_view_t path::__root_path_raw() const {
164746035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
164846035553Spatrick   if (PP.State == PathParser::PS_InRootName) {
164946035553Spatrick     auto NextCh = PP.peek();
165076d0caaeSpatrick     if (NextCh && isSeparator(*NextCh)) {
165146035553Spatrick       ++PP;
165246035553Spatrick       return createView(__pn_.data(), &PP.RawEntry.back());
165346035553Spatrick     }
165446035553Spatrick     return PP.RawEntry;
165546035553Spatrick   }
165646035553Spatrick   if (PP.State == PathParser::PS_InRootDir)
165746035553Spatrick     return *PP;
165846035553Spatrick   return {};
165946035553Spatrick }
166046035553Spatrick 
ConsumeRootName(PathParser * PP)166146035553Spatrick static bool ConsumeRootName(PathParser *PP) {
166246035553Spatrick   static_assert(PathParser::PS_BeforeBegin == 1 &&
166346035553Spatrick       PathParser::PS_InRootName == 2,
166446035553Spatrick       "Values for enums are incorrect");
166546035553Spatrick   while (PP->State <= PathParser::PS_InRootName)
166646035553Spatrick     ++(*PP);
166746035553Spatrick   return PP->State == PathParser::PS_AtEnd;
166846035553Spatrick }
166946035553Spatrick 
ConsumeRootDir(PathParser * PP)167046035553Spatrick static bool ConsumeRootDir(PathParser* PP) {
167146035553Spatrick   static_assert(PathParser::PS_BeforeBegin == 1 &&
167246035553Spatrick                 PathParser::PS_InRootName == 2 &&
167346035553Spatrick                 PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
167446035553Spatrick   while (PP->State <= PathParser::PS_InRootDir)
167546035553Spatrick     ++(*PP);
167646035553Spatrick   return PP->State == PathParser::PS_AtEnd;
167746035553Spatrick }
167846035553Spatrick 
__relative_path() const167946035553Spatrick string_view_t path::__relative_path() const {
168046035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
168146035553Spatrick   if (ConsumeRootDir(&PP))
168246035553Spatrick     return {};
168346035553Spatrick   return createView(PP.RawEntry.data(), &__pn_.back());
168446035553Spatrick }
168546035553Spatrick 
__parent_path() const168646035553Spatrick string_view_t path::__parent_path() const {
168746035553Spatrick   if (empty())
168846035553Spatrick     return {};
168946035553Spatrick   // Determine if we have a root path but not a relative path. In that case
169046035553Spatrick   // return *this.
169146035553Spatrick   {
169246035553Spatrick     auto PP = PathParser::CreateBegin(__pn_);
169346035553Spatrick     if (ConsumeRootDir(&PP))
169446035553Spatrick       return __pn_;
169546035553Spatrick   }
169646035553Spatrick   // Otherwise remove a single element from the end of the path, and return
169746035553Spatrick   // a string representing that path
169846035553Spatrick   {
169946035553Spatrick     auto PP = PathParser::CreateEnd(__pn_);
170046035553Spatrick     --PP;
170146035553Spatrick     if (PP.RawEntry.data() == __pn_.data())
170246035553Spatrick       return {};
170346035553Spatrick     --PP;
170446035553Spatrick     return createView(__pn_.data(), &PP.RawEntry.back());
170546035553Spatrick   }
170646035553Spatrick }
170746035553Spatrick 
__filename() const170846035553Spatrick string_view_t path::__filename() const {
170946035553Spatrick   if (empty())
171046035553Spatrick     return {};
171146035553Spatrick   {
171246035553Spatrick     PathParser PP = PathParser::CreateBegin(__pn_);
171346035553Spatrick     if (ConsumeRootDir(&PP))
171446035553Spatrick       return {};
171546035553Spatrick   }
171646035553Spatrick   return *(--PathParser::CreateEnd(__pn_));
171746035553Spatrick }
171846035553Spatrick 
__stem() const171946035553Spatrick string_view_t path::__stem() const {
172046035553Spatrick   return parser::separate_filename(__filename()).first;
172146035553Spatrick }
172246035553Spatrick 
__extension() const172346035553Spatrick string_view_t path::__extension() const {
172446035553Spatrick   return parser::separate_filename(__filename()).second;
172546035553Spatrick }
172646035553Spatrick 
172746035553Spatrick ////////////////////////////////////////////////////////////////////////////
172846035553Spatrick // path.gen
172946035553Spatrick 
173046035553Spatrick enum PathPartKind : unsigned char {
173146035553Spatrick   PK_None,
173246035553Spatrick   PK_RootSep,
173346035553Spatrick   PK_Filename,
173446035553Spatrick   PK_Dot,
173546035553Spatrick   PK_DotDot,
173646035553Spatrick   PK_TrailingSep
173746035553Spatrick };
173846035553Spatrick 
ClassifyPathPart(string_view_t Part)173946035553Spatrick static PathPartKind ClassifyPathPart(string_view_t Part) {
174046035553Spatrick   if (Part.empty())
174146035553Spatrick     return PK_TrailingSep;
1742*4bdff4beSrobert   if (Part == PATHSTR("."))
174346035553Spatrick     return PK_Dot;
1744*4bdff4beSrobert   if (Part == PATHSTR(".."))
174546035553Spatrick     return PK_DotDot;
1746*4bdff4beSrobert   if (Part == PATHSTR("/"))
174746035553Spatrick     return PK_RootSep;
174876d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
1749*4bdff4beSrobert   if (Part == PATHSTR("\\"))
175076d0caaeSpatrick     return PK_RootSep;
175176d0caaeSpatrick #endif
175246035553Spatrick   return PK_Filename;
175346035553Spatrick }
175446035553Spatrick 
lexically_normal() const175546035553Spatrick path path::lexically_normal() const {
175646035553Spatrick   if (__pn_.empty())
175746035553Spatrick     return *this;
175846035553Spatrick 
175946035553Spatrick   using PartKindPair = pair<string_view_t, PathPartKind>;
176046035553Spatrick   vector<PartKindPair> Parts;
176146035553Spatrick   // Guess as to how many elements the path has to avoid reallocating.
176246035553Spatrick   Parts.reserve(32);
176346035553Spatrick 
176446035553Spatrick   // Track the total size of the parts as we collect them. This allows the
176546035553Spatrick   // resulting path to reserve the correct amount of memory.
176646035553Spatrick   size_t NewPathSize = 0;
176746035553Spatrick   auto AddPart = [&](PathPartKind K, string_view_t P) {
176846035553Spatrick     NewPathSize += P.size();
176946035553Spatrick     Parts.emplace_back(P, K);
177046035553Spatrick   };
177146035553Spatrick   auto LastPartKind = [&]() {
177246035553Spatrick     if (Parts.empty())
177346035553Spatrick       return PK_None;
177446035553Spatrick     return Parts.back().second;
177546035553Spatrick   };
177646035553Spatrick 
177746035553Spatrick   bool MaybeNeedTrailingSep = false;
177846035553Spatrick   // Build a stack containing the remaining elements of the path, popping off
177946035553Spatrick   // elements which occur before a '..' entry.
178046035553Spatrick   for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
178146035553Spatrick     auto Part = *PP;
178246035553Spatrick     PathPartKind Kind = ClassifyPathPart(Part);
178346035553Spatrick     switch (Kind) {
178446035553Spatrick     case PK_Filename:
178546035553Spatrick     case PK_RootSep: {
178646035553Spatrick       // Add all non-dot and non-dot-dot elements to the stack of elements.
178746035553Spatrick       AddPart(Kind, Part);
178846035553Spatrick       MaybeNeedTrailingSep = false;
178946035553Spatrick       break;
179046035553Spatrick     }
179146035553Spatrick     case PK_DotDot: {
179246035553Spatrick       // Only push a ".." element if there are no elements preceding the "..",
179346035553Spatrick       // or if the preceding element is itself "..".
179446035553Spatrick       auto LastKind = LastPartKind();
179546035553Spatrick       if (LastKind == PK_Filename) {
179646035553Spatrick         NewPathSize -= Parts.back().first.size();
179746035553Spatrick         Parts.pop_back();
179846035553Spatrick       } else if (LastKind != PK_RootSep)
1799*4bdff4beSrobert         AddPart(PK_DotDot, PATHSTR(".."));
180046035553Spatrick       MaybeNeedTrailingSep = LastKind == PK_Filename;
180146035553Spatrick       break;
180246035553Spatrick     }
180346035553Spatrick     case PK_Dot:
180446035553Spatrick     case PK_TrailingSep: {
180546035553Spatrick       MaybeNeedTrailingSep = true;
180646035553Spatrick       break;
180746035553Spatrick     }
180846035553Spatrick     case PK_None:
1809*4bdff4beSrobert       __libcpp_unreachable();
181046035553Spatrick     }
181146035553Spatrick   }
181246035553Spatrick   // [fs.path.generic]p6.8: If the path is empty, add a dot.
181346035553Spatrick   if (Parts.empty())
1814*4bdff4beSrobert     return PATHSTR(".");
181546035553Spatrick 
181646035553Spatrick   // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
181746035553Spatrick   // trailing directory-separator.
181846035553Spatrick   bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
181946035553Spatrick 
182046035553Spatrick   path Result;
182146035553Spatrick   Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
182246035553Spatrick   for (auto& PK : Parts)
182346035553Spatrick     Result /= PK.first;
182446035553Spatrick 
182546035553Spatrick   if (NeedTrailingSep)
1826*4bdff4beSrobert     Result /= PATHSTR("");
182746035553Spatrick 
182876d0caaeSpatrick   Result.make_preferred();
182946035553Spatrick   return Result;
183046035553Spatrick }
183146035553Spatrick 
DetermineLexicalElementCount(PathParser PP)183246035553Spatrick static int DetermineLexicalElementCount(PathParser PP) {
183346035553Spatrick   int Count = 0;
183446035553Spatrick   for (; PP; ++PP) {
183546035553Spatrick     auto Elem = *PP;
1836*4bdff4beSrobert     if (Elem == PATHSTR(".."))
183746035553Spatrick       --Count;
1838*4bdff4beSrobert     else if (Elem != PATHSTR(".") && Elem != PATHSTR(""))
183946035553Spatrick       ++Count;
184046035553Spatrick   }
184146035553Spatrick   return Count;
184246035553Spatrick }
184346035553Spatrick 
lexically_relative(const path & base) const184446035553Spatrick path path::lexically_relative(const path& base) const {
184546035553Spatrick   { // perform root-name/root-directory mismatch checks
184646035553Spatrick     auto PP = PathParser::CreateBegin(__pn_);
184746035553Spatrick     auto PPBase = PathParser::CreateBegin(base.__pn_);
184846035553Spatrick     auto CheckIterMismatchAtBase = [&]() {
184946035553Spatrick       return PP.State != PPBase.State &&
185046035553Spatrick              (PP.inRootPath() || PPBase.inRootPath());
185146035553Spatrick     };
185246035553Spatrick     if (PP.inRootName() && PPBase.inRootName()) {
185346035553Spatrick       if (*PP != *PPBase)
185446035553Spatrick         return {};
185546035553Spatrick     } else if (CheckIterMismatchAtBase())
185646035553Spatrick       return {};
185746035553Spatrick 
185846035553Spatrick     if (PP.inRootPath())
185946035553Spatrick       ++PP;
186046035553Spatrick     if (PPBase.inRootPath())
186146035553Spatrick       ++PPBase;
186246035553Spatrick     if (CheckIterMismatchAtBase())
186346035553Spatrick       return {};
186446035553Spatrick   }
186546035553Spatrick 
186646035553Spatrick   // Find the first mismatching element
186746035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
186846035553Spatrick   auto PPBase = PathParser::CreateBegin(base.__pn_);
186946035553Spatrick   while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
187046035553Spatrick     ++PP;
187146035553Spatrick     ++PPBase;
187246035553Spatrick   }
187346035553Spatrick 
187446035553Spatrick   // If there is no mismatch, return ".".
187546035553Spatrick   if (!PP && !PPBase)
187646035553Spatrick     return ".";
187746035553Spatrick 
187846035553Spatrick   // Otherwise, determine the number of elements, 'n', which are not dot or
187946035553Spatrick   // dot-dot minus the number of dot-dot elements.
188046035553Spatrick   int ElemCount = DetermineLexicalElementCount(PPBase);
188146035553Spatrick   if (ElemCount < 0)
188246035553Spatrick     return {};
188346035553Spatrick 
188446035553Spatrick   // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
1885*4bdff4beSrobert   if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR("")))
1886*4bdff4beSrobert     return PATHSTR(".");
188746035553Spatrick 
1888*4bdff4beSrobert   // return a path constructed with 'n' dot-dot elements, followed by the
188946035553Spatrick   // elements of '*this' after the mismatch.
189046035553Spatrick   path Result;
189146035553Spatrick   // FIXME: Reserve enough room in Result that it won't have to re-allocate.
189246035553Spatrick   while (ElemCount--)
1893*4bdff4beSrobert     Result /= PATHSTR("..");
189446035553Spatrick   for (; PP; ++PP)
189546035553Spatrick     Result /= *PP;
189646035553Spatrick   return Result;
189746035553Spatrick }
189846035553Spatrick 
189946035553Spatrick ////////////////////////////////////////////////////////////////////////////
190046035553Spatrick // path.comparisons
CompareRootName(PathParser * LHS,PathParser * RHS)190146035553Spatrick static int CompareRootName(PathParser *LHS, PathParser *RHS) {
190246035553Spatrick   if (!LHS->inRootName() && !RHS->inRootName())
190346035553Spatrick     return 0;
190446035553Spatrick 
190546035553Spatrick   auto GetRootName = [](PathParser *Parser) -> string_view_t {
1906*4bdff4beSrobert     return Parser->inRootName() ? **Parser : PATHSTR("");
190746035553Spatrick   };
190846035553Spatrick   int res = GetRootName(LHS).compare(GetRootName(RHS));
190946035553Spatrick   ConsumeRootName(LHS);
191046035553Spatrick   ConsumeRootName(RHS);
191146035553Spatrick   return res;
191246035553Spatrick }
191346035553Spatrick 
CompareRootDir(PathParser * LHS,PathParser * RHS)191446035553Spatrick static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
191546035553Spatrick   if (!LHS->inRootDir() && RHS->inRootDir())
191646035553Spatrick     return -1;
191746035553Spatrick   else if (LHS->inRootDir() && !RHS->inRootDir())
191846035553Spatrick     return 1;
191946035553Spatrick   else {
192046035553Spatrick     ConsumeRootDir(LHS);
192146035553Spatrick     ConsumeRootDir(RHS);
192246035553Spatrick     return 0;
192346035553Spatrick   }
192446035553Spatrick }
192546035553Spatrick 
CompareRelative(PathParser * LHSPtr,PathParser * RHSPtr)192646035553Spatrick static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
192746035553Spatrick   auto &LHS = *LHSPtr;
192846035553Spatrick   auto &RHS = *RHSPtr;
192946035553Spatrick 
193046035553Spatrick   int res;
193146035553Spatrick   while (LHS && RHS) {
193246035553Spatrick     if ((res = (*LHS).compare(*RHS)) != 0)
193346035553Spatrick       return res;
193446035553Spatrick     ++LHS;
193546035553Spatrick     ++RHS;
193646035553Spatrick   }
193746035553Spatrick   return 0;
193846035553Spatrick }
193946035553Spatrick 
CompareEndState(PathParser * LHS,PathParser * RHS)194046035553Spatrick static int CompareEndState(PathParser *LHS, PathParser *RHS) {
194146035553Spatrick   if (LHS->atEnd() && !RHS->atEnd())
194246035553Spatrick     return -1;
194346035553Spatrick   else if (!LHS->atEnd() && RHS->atEnd())
194446035553Spatrick     return 1;
194546035553Spatrick   return 0;
194646035553Spatrick }
194746035553Spatrick 
__compare(string_view_t __s) const194846035553Spatrick int path::__compare(string_view_t __s) const {
194946035553Spatrick   auto LHS = PathParser::CreateBegin(__pn_);
195046035553Spatrick   auto RHS = PathParser::CreateBegin(__s);
195146035553Spatrick   int res;
195246035553Spatrick 
195346035553Spatrick   if ((res = CompareRootName(&LHS, &RHS)) != 0)
195446035553Spatrick     return res;
195546035553Spatrick 
195646035553Spatrick   if ((res = CompareRootDir(&LHS, &RHS)) != 0)
195746035553Spatrick     return res;
195846035553Spatrick 
195946035553Spatrick   if ((res = CompareRelative(&LHS, &RHS)) != 0)
196046035553Spatrick     return res;
196146035553Spatrick 
196246035553Spatrick   return CompareEndState(&LHS, &RHS);
196346035553Spatrick }
196446035553Spatrick 
196546035553Spatrick ////////////////////////////////////////////////////////////////////////////
196646035553Spatrick // path.nonmembers
hash_value(const path & __p)196746035553Spatrick size_t hash_value(const path& __p) noexcept {
196846035553Spatrick   auto PP = PathParser::CreateBegin(__p.native());
196946035553Spatrick   size_t hash_value = 0;
197046035553Spatrick   hash<string_view_t> hasher;
197146035553Spatrick   while (PP) {
197246035553Spatrick     hash_value = __hash_combine(hash_value, hasher(*PP));
197346035553Spatrick     ++PP;
197446035553Spatrick   }
197546035553Spatrick   return hash_value;
197646035553Spatrick }
197746035553Spatrick 
197846035553Spatrick ////////////////////////////////////////////////////////////////////////////
197946035553Spatrick // path.itr
begin() const198046035553Spatrick path::iterator path::begin() const {
198146035553Spatrick   auto PP = PathParser::CreateBegin(__pn_);
198246035553Spatrick   iterator it;
198346035553Spatrick   it.__path_ptr_ = this;
198446035553Spatrick   it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
198546035553Spatrick   it.__entry_ = PP.RawEntry;
198646035553Spatrick   it.__stashed_elem_.__assign_view(*PP);
198746035553Spatrick   return it;
198846035553Spatrick }
198946035553Spatrick 
end() const199046035553Spatrick path::iterator path::end() const {
199146035553Spatrick   iterator it{};
199246035553Spatrick   it.__state_ = path::iterator::_AtEnd;
199346035553Spatrick   it.__path_ptr_ = this;
199446035553Spatrick   return it;
199546035553Spatrick }
199646035553Spatrick 
__increment()199746035553Spatrick path::iterator& path::iterator::__increment() {
199846035553Spatrick   PathParser PP(__path_ptr_->native(), __entry_, __state_);
199946035553Spatrick   ++PP;
200046035553Spatrick   __state_ = static_cast<_ParserState>(PP.State);
200146035553Spatrick   __entry_ = PP.RawEntry;
200246035553Spatrick   __stashed_elem_.__assign_view(*PP);
200346035553Spatrick   return *this;
200446035553Spatrick }
200546035553Spatrick 
__decrement()200646035553Spatrick path::iterator& path::iterator::__decrement() {
200746035553Spatrick   PathParser PP(__path_ptr_->native(), __entry_, __state_);
200846035553Spatrick   --PP;
200946035553Spatrick   __state_ = static_cast<_ParserState>(PP.State);
201046035553Spatrick   __entry_ = PP.RawEntry;
201146035553Spatrick   __stashed_elem_.__assign_view(*PP);
201246035553Spatrick   return *this;
201346035553Spatrick }
201446035553Spatrick 
201576d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
201676d0caaeSpatrick ////////////////////////////////////////////////////////////////////////////
201776d0caaeSpatrick // Windows path conversions
__wide_to_char(const wstring & str,char * out,size_t outlen)201876d0caaeSpatrick size_t __wide_to_char(const wstring &str, char *out, size_t outlen) {
201976d0caaeSpatrick   if (str.empty())
202076d0caaeSpatrick     return 0;
202176d0caaeSpatrick   ErrorHandler<size_t> err("__wide_to_char", nullptr);
202276d0caaeSpatrick   UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
202376d0caaeSpatrick   BOOL used_default = FALSE;
202476d0caaeSpatrick   int ret = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out,
202576d0caaeSpatrick                                 outlen, nullptr, &used_default);
202676d0caaeSpatrick   if (ret <= 0 || used_default)
202776d0caaeSpatrick     return err.report(errc::illegal_byte_sequence);
202876d0caaeSpatrick   return ret;
202976d0caaeSpatrick }
203076d0caaeSpatrick 
__char_to_wide(const string & str,wchar_t * out,size_t outlen)203176d0caaeSpatrick size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) {
203276d0caaeSpatrick   if (str.empty())
203376d0caaeSpatrick     return 0;
203476d0caaeSpatrick   ErrorHandler<size_t> err("__char_to_wide", nullptr);
203576d0caaeSpatrick   UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
203676d0caaeSpatrick   int ret = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(),
203776d0caaeSpatrick                                 str.size(), out, outlen);
203876d0caaeSpatrick   if (ret <= 0)
203976d0caaeSpatrick     return err.report(errc::illegal_byte_sequence);
204076d0caaeSpatrick   return ret;
204176d0caaeSpatrick }
204276d0caaeSpatrick #endif
204376d0caaeSpatrick 
204476d0caaeSpatrick 
204546035553Spatrick ///////////////////////////////////////////////////////////////////////////////
204646035553Spatrick //                           directory entry definitions
204746035553Spatrick ///////////////////////////////////////////////////////////////////////////////
204846035553Spatrick 
__do_refresh()204946035553Spatrick error_code directory_entry::__do_refresh() noexcept {
205046035553Spatrick   __data_.__reset();
205146035553Spatrick   error_code failure_ec;
205246035553Spatrick 
205346035553Spatrick   StatT full_st;
205446035553Spatrick   file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
205546035553Spatrick   if (!status_known(st)) {
205646035553Spatrick     __data_.__reset();
205746035553Spatrick     return failure_ec;
205846035553Spatrick   }
205946035553Spatrick 
206046035553Spatrick   if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
206146035553Spatrick     __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
206246035553Spatrick     __data_.__type_ = st.type();
206346035553Spatrick     __data_.__non_sym_perms_ = st.permissions();
206446035553Spatrick   } else { // we have a symlink
206546035553Spatrick     __data_.__sym_perms_ = st.permissions();
206646035553Spatrick     // Get the information about the linked entity.
206746035553Spatrick     // Ignore errors from stat, since we don't want errors regarding symlink
206846035553Spatrick     // resolution to be reported to the user.
206946035553Spatrick     error_code ignored_ec;
207046035553Spatrick     st = detail::posix_stat(__p_, full_st, &ignored_ec);
207146035553Spatrick 
207246035553Spatrick     __data_.__type_ = st.type();
207346035553Spatrick     __data_.__non_sym_perms_ = st.permissions();
207446035553Spatrick 
207546035553Spatrick     // If we failed to resolve the link, then only partially populate the
207646035553Spatrick     // cache.
207746035553Spatrick     if (!status_known(st)) {
207846035553Spatrick       __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
207946035553Spatrick       return error_code{};
208046035553Spatrick     }
208146035553Spatrick     // Otherwise, we resolved the link, potentially as not existing.
208246035553Spatrick     // That's OK.
208346035553Spatrick     __data_.__cache_type_ = directory_entry::_RefreshSymlink;
208446035553Spatrick   }
208546035553Spatrick 
208646035553Spatrick   if (_VSTD_FS::is_regular_file(st))
208746035553Spatrick     __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
208846035553Spatrick 
208946035553Spatrick   if (_VSTD_FS::exists(st)) {
209046035553Spatrick     __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
209146035553Spatrick 
209246035553Spatrick     // Attempt to extract the mtime, and fail if it's not representable using
209346035553Spatrick     // file_time_type. For now we ignore the error, as we'll report it when
209446035553Spatrick     // the value is actually used.
209546035553Spatrick     error_code ignored_ec;
209646035553Spatrick     __data_.__write_time_ =
209746035553Spatrick         __extract_last_write_time(__p_, full_st, &ignored_ec);
209846035553Spatrick   }
209946035553Spatrick 
210046035553Spatrick   return failure_ec;
210146035553Spatrick }
210246035553Spatrick 
210346035553Spatrick _LIBCPP_END_NAMESPACE_FILESYSTEM
2104