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