Coverage Report

Created: 2022-05-17 06:19

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