146035553Spatrick //===----------------------------------------------------------------------===////
246035553Spatrick //
346035553Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
446035553Spatrick // See https://llvm.org/LICENSE.txt for license information.
546035553Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
646035553Spatrick //
746035553Spatrick //===----------------------------------------------------------------------===////
846035553Spatrick 
946035553Spatrick #ifndef FILESYSTEM_COMMON_H
1046035553Spatrick #define FILESYSTEM_COMMON_H
1146035553Spatrick 
12*4bdff4beSrobert #include <__assert>
13*4bdff4beSrobert #include <__config>
14*4bdff4beSrobert #include <array>
15*4bdff4beSrobert #include <chrono>
16*4bdff4beSrobert #include <climits>
17*4bdff4beSrobert #include <cstdarg>
18*4bdff4beSrobert #include <ctime>
19*4bdff4beSrobert #include <filesystem>
20*4bdff4beSrobert #include <ratio>
21*4bdff4beSrobert #include <system_error>
22*4bdff4beSrobert #include <utility>
2346035553Spatrick 
24*4bdff4beSrobert #if defined(_LIBCPP_WIN32API)
25*4bdff4beSrobert # define WIN32_LEAN_AND_MEAN
26*4bdff4beSrobert # define NOMINMAX
27*4bdff4beSrobert # include <windows.h>
28*4bdff4beSrobert #else
29*4bdff4beSrobert # include <dirent.h>   // for DIR & friends
30*4bdff4beSrobert # include <fcntl.h>    /* values for fchmodat */
3146035553Spatrick # include <sys/stat.h>
3246035553Spatrick # include <sys/statvfs.h>
3346035553Spatrick # include <sys/time.h> // for ::utimes as used in __last_write_time
34*4bdff4beSrobert # include <unistd.h>
35*4bdff4beSrobert #endif // defined(_LIBCPP_WIN32API)
3646035553Spatrick 
3746035553Spatrick #include "../include/apple_availability.h"
3846035553Spatrick 
3946035553Spatrick #if !defined(__APPLE__)
4046035553Spatrick // We can use the presence of UTIME_OMIT to detect platforms that provide
4146035553Spatrick // utimensat.
4246035553Spatrick #if defined(UTIME_OMIT)
4346035553Spatrick #define _LIBCPP_USE_UTIMENSAT
4446035553Spatrick #endif
4546035553Spatrick #endif
4646035553Spatrick 
47*4bdff4beSrobert _LIBCPP_DIAGNOSTIC_PUSH
48*4bdff4beSrobert _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function")
49*4bdff4beSrobert _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function")
5046035553Spatrick 
5176d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
52*4bdff4beSrobert #  define PATHSTR(x) (L##x)
5376d0caaeSpatrick #  define PATH_CSTR_FMT "\"%ls\""
5476d0caaeSpatrick #else
55*4bdff4beSrobert #  define PATHSTR(x) (x)
5676d0caaeSpatrick #  define PATH_CSTR_FMT "\"%s\""
5776d0caaeSpatrick #endif
5876d0caaeSpatrick 
5946035553Spatrick _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
6046035553Spatrick 
6146035553Spatrick namespace detail {
6276d0caaeSpatrick 
6376d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
6476d0caaeSpatrick // Non anonymous, to allow access from two translation units.
6576d0caaeSpatrick errc __win_err_to_errc(int err);
6676d0caaeSpatrick #endif
6776d0caaeSpatrick 
6846035553Spatrick namespace {
6946035553Spatrick 
70*4bdff4beSrobert static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string
format_string_impl(const char * msg,va_list ap)7176d0caaeSpatrick format_string_impl(const char* msg, va_list ap) {
7276d0caaeSpatrick   array<char, 256> buf;
7346035553Spatrick 
7476d0caaeSpatrick   va_list apcopy;
7576d0caaeSpatrick   va_copy(apcopy, ap);
7676d0caaeSpatrick   int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy);
7776d0caaeSpatrick   va_end(apcopy);
7846035553Spatrick 
7976d0caaeSpatrick   string result;
8076d0caaeSpatrick   if (static_cast<size_t>(ret) < buf.size()) {
8176d0caaeSpatrick     result.assign(buf.data(), static_cast<size_t>(ret));
8276d0caaeSpatrick   } else {
8346035553Spatrick     // we did not provide a long enough buffer on our first attempt. The
8446035553Spatrick     // return value is the number of bytes (excluding the null byte) that are
8546035553Spatrick     // needed for formatting.
8676d0caaeSpatrick     size_t size_with_null = static_cast<size_t>(ret) + 1;
8746035553Spatrick     result.__resize_default_init(size_with_null - 1);
8876d0caaeSpatrick     ret = ::vsnprintf(&result[0], size_with_null, msg, ap);
8946035553Spatrick     _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
9076d0caaeSpatrick   }
9146035553Spatrick   return result;
9246035553Spatrick }
9346035553Spatrick 
94*4bdff4beSrobert static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) string
format_string(const char * msg,...)9576d0caaeSpatrick format_string(const char* msg, ...) {
9676d0caaeSpatrick   string ret;
9776d0caaeSpatrick   va_list ap;
9876d0caaeSpatrick   va_start(ap, msg);
9976d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
10076d0caaeSpatrick   try {
10176d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
10276d0caaeSpatrick     ret = format_string_impl(msg, ap);
10376d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
10476d0caaeSpatrick   } catch (...) {
10576d0caaeSpatrick     va_end(ap);
10676d0caaeSpatrick     throw;
10746035553Spatrick   }
10876d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
10976d0caaeSpatrick   va_end(ap);
11076d0caaeSpatrick   return ret;
11146035553Spatrick }
11246035553Spatrick 
capture_errno()11346035553Spatrick error_code capture_errno() {
114*4bdff4beSrobert   _LIBCPP_ASSERT(errno != 0, "Expected errno to be non-zero");
11546035553Spatrick   return error_code(errno, generic_category());
11646035553Spatrick }
11746035553Spatrick 
11876d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
make_windows_error(int err)11976d0caaeSpatrick error_code make_windows_error(int err) {
12076d0caaeSpatrick   return make_error_code(__win_err_to_errc(err));
12176d0caaeSpatrick }
12276d0caaeSpatrick #endif
12376d0caaeSpatrick 
12446035553Spatrick template <class T>
12546035553Spatrick T error_value();
12646035553Spatrick template <>
127*4bdff4beSrobert _LIBCPP_CONSTEXPR_SINCE_CXX14 void error_value<void>() {}
12846035553Spatrick template <>
12946035553Spatrick bool error_value<bool>() {
13046035553Spatrick   return false;
13146035553Spatrick }
13276d0caaeSpatrick #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__
13376d0caaeSpatrick template <>
13476d0caaeSpatrick size_t error_value<size_t>() {
13576d0caaeSpatrick   return size_t(-1);
13676d0caaeSpatrick }
13776d0caaeSpatrick #endif
13846035553Spatrick template <>
13946035553Spatrick uintmax_t error_value<uintmax_t>() {
14046035553Spatrick   return uintmax_t(-1);
14146035553Spatrick }
14246035553Spatrick template <>
143*4bdff4beSrobert _LIBCPP_CONSTEXPR_SINCE_CXX14 file_time_type error_value<file_time_type>() {
14446035553Spatrick   return file_time_type::min();
14546035553Spatrick }
14646035553Spatrick template <>
14746035553Spatrick path error_value<path>() {
14846035553Spatrick   return {};
14946035553Spatrick }
15046035553Spatrick 
15146035553Spatrick template <class T>
15246035553Spatrick struct ErrorHandler {
15376d0caaeSpatrick   const char* func_name_;
15476d0caaeSpatrick   error_code* ec_ = nullptr;
15576d0caaeSpatrick   const path* p1_ = nullptr;
15676d0caaeSpatrick   const path* p2_ = nullptr;
15746035553Spatrick 
15846035553Spatrick   ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
15946035553Spatrick                const path* p2 = nullptr)
func_name_ErrorHandler16076d0caaeSpatrick       : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
16176d0caaeSpatrick     if (ec_)
16276d0caaeSpatrick       ec_->clear();
16346035553Spatrick   }
16446035553Spatrick 
reportErrorHandler16576d0caaeSpatrick   T report(const error_code& ec) const {
16676d0caaeSpatrick     if (ec_) {
16776d0caaeSpatrick       *ec_ = ec;
16846035553Spatrick       return error_value<T>();
16946035553Spatrick     }
17076d0caaeSpatrick     string what = string("in ") + func_name_;
17176d0caaeSpatrick     switch (bool(p1_) + bool(p2_)) {
17246035553Spatrick     case 0:
17376d0caaeSpatrick       __throw_filesystem_error(what, ec);
17446035553Spatrick     case 1:
17576d0caaeSpatrick       __throw_filesystem_error(what, *p1_, ec);
17646035553Spatrick     case 2:
17776d0caaeSpatrick       __throw_filesystem_error(what, *p1_, *p2_, ec);
17846035553Spatrick     }
179*4bdff4beSrobert     __libcpp_unreachable();
18046035553Spatrick   }
18146035553Spatrick 
182*4bdff4beSrobert   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0)
report_implErrorHandler18376d0caaeSpatrick   void report_impl(const error_code& ec, const char* msg, va_list ap) const {
18476d0caaeSpatrick     if (ec_) {
18576d0caaeSpatrick       *ec_ = ec;
18676d0caaeSpatrick       return;
18746035553Spatrick     }
18846035553Spatrick     string what =
18976d0caaeSpatrick         string("in ") + func_name_ + ": " + format_string_impl(msg, ap);
19076d0caaeSpatrick     switch (bool(p1_) + bool(p2_)) {
19146035553Spatrick     case 0:
19276d0caaeSpatrick       __throw_filesystem_error(what, ec);
19346035553Spatrick     case 1:
19476d0caaeSpatrick       __throw_filesystem_error(what, *p1_, ec);
19546035553Spatrick     case 2:
19676d0caaeSpatrick       __throw_filesystem_error(what, *p1_, *p2_, ec);
19746035553Spatrick     }
198*4bdff4beSrobert     __libcpp_unreachable();
19946035553Spatrick   }
20046035553Spatrick 
201*4bdff4beSrobert   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
reportErrorHandler20276d0caaeSpatrick   T report(const error_code& ec, const char* msg, ...) const {
20376d0caaeSpatrick     va_list ap;
20476d0caaeSpatrick     va_start(ap, msg);
20576d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
20676d0caaeSpatrick     try {
20776d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
20876d0caaeSpatrick       report_impl(ec, msg, ap);
20976d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
21076d0caaeSpatrick     } catch (...) {
21176d0caaeSpatrick       va_end(ap);
21276d0caaeSpatrick       throw;
21376d0caaeSpatrick     }
21476d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
21576d0caaeSpatrick     va_end(ap);
21676d0caaeSpatrick     return error_value<T>();
21776d0caaeSpatrick   }
21846035553Spatrick 
reportErrorHandler21976d0caaeSpatrick   T report(errc const& err) const {
22076d0caaeSpatrick     return report(make_error_code(err));
22176d0caaeSpatrick   }
22276d0caaeSpatrick 
223*4bdff4beSrobert   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
reportErrorHandler22476d0caaeSpatrick   T report(errc const& err, const char* msg, ...) const {
22576d0caaeSpatrick     va_list ap;
22676d0caaeSpatrick     va_start(ap, msg);
22776d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
22876d0caaeSpatrick     try {
22976d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
23076d0caaeSpatrick       report_impl(make_error_code(err), msg, ap);
23176d0caaeSpatrick #ifndef _LIBCPP_NO_EXCEPTIONS
23276d0caaeSpatrick     } catch (...) {
23376d0caaeSpatrick       va_end(ap);
23476d0caaeSpatrick       throw;
23576d0caaeSpatrick     }
23676d0caaeSpatrick #endif // _LIBCPP_NO_EXCEPTIONS
23776d0caaeSpatrick     va_end(ap);
23876d0caaeSpatrick     return error_value<T>();
23946035553Spatrick   }
24046035553Spatrick 
24146035553Spatrick private:
24246035553Spatrick   ErrorHandler(ErrorHandler const&) = delete;
24346035553Spatrick   ErrorHandler& operator=(ErrorHandler const&) = delete;
24446035553Spatrick };
24546035553Spatrick 
24646035553Spatrick using chrono::duration;
24746035553Spatrick using chrono::duration_cast;
24846035553Spatrick 
24976d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
25076d0caaeSpatrick // Various C runtime versions (UCRT, or the legacy msvcrt.dll used by
25176d0caaeSpatrick // some mingw toolchains) provide different stat function implementations,
25276d0caaeSpatrick // with a number of limitations with respect to what we want from the
25376d0caaeSpatrick // stat function. Instead provide our own (in the anonymous detail namespace
25476d0caaeSpatrick // in posix_compat.h) which does exactly what we want, along with our own
25576d0caaeSpatrick // stat structure and flag macros.
25676d0caaeSpatrick 
25776d0caaeSpatrick struct TimeSpec {
25876d0caaeSpatrick   int64_t tv_sec;
25976d0caaeSpatrick   int64_t tv_nsec;
26076d0caaeSpatrick };
26176d0caaeSpatrick struct StatT {
26276d0caaeSpatrick   unsigned st_mode;
26376d0caaeSpatrick   TimeSpec st_atim;
26476d0caaeSpatrick   TimeSpec st_mtim;
26576d0caaeSpatrick   uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber
26676d0caaeSpatrick   struct FileIdStruct {
26776d0caaeSpatrick     unsigned char id[16]; // FILE_ID_INFO::FileId
26876d0caaeSpatrick     bool operator==(const FileIdStruct &other) const {
26976d0caaeSpatrick       for (int i = 0; i < 16; i++)
27076d0caaeSpatrick         if (id[i] != other.id[i])
27176d0caaeSpatrick           return false;
27276d0caaeSpatrick       return true;
27376d0caaeSpatrick     }
27476d0caaeSpatrick   } st_ino;
27576d0caaeSpatrick   uint32_t st_nlink;
27676d0caaeSpatrick   uintmax_t st_size;
27776d0caaeSpatrick };
27876d0caaeSpatrick 
27976d0caaeSpatrick #else
28076d0caaeSpatrick using TimeSpec = struct timespec;
28176d0caaeSpatrick using TimeVal = struct timeval;
28276d0caaeSpatrick using StatT = struct stat;
28376d0caaeSpatrick #endif
28446035553Spatrick 
28546035553Spatrick template <class FileTimeT, class TimeT,
28646035553Spatrick           bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
28746035553Spatrick struct time_util_base {
28846035553Spatrick   using rep = typename FileTimeT::rep;
28946035553Spatrick   using fs_duration = typename FileTimeT::duration;
29046035553Spatrick   using fs_seconds = duration<rep>;
29146035553Spatrick   using fs_nanoseconds = duration<rep, nano>;
29246035553Spatrick   using fs_microseconds = duration<rep, micro>;
29346035553Spatrick 
29446035553Spatrick   static constexpr rep max_seconds =
29546035553Spatrick       duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
29646035553Spatrick 
29746035553Spatrick   static constexpr rep max_nsec =
29846035553Spatrick       duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
29946035553Spatrick                                     fs_seconds(max_seconds))
30046035553Spatrick           .count();
30146035553Spatrick 
30246035553Spatrick   static constexpr rep min_seconds =
30346035553Spatrick       duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
30446035553Spatrick 
30546035553Spatrick   static constexpr rep min_nsec_timespec =
30646035553Spatrick       duration_cast<fs_nanoseconds>(
30746035553Spatrick           (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
30846035553Spatrick           fs_seconds(1))
30946035553Spatrick           .count();
31046035553Spatrick 
31146035553Spatrick private:
get_min_nsecstime_util_base312*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 fs_duration get_min_nsecs() {
31346035553Spatrick     return duration_cast<fs_duration>(
31446035553Spatrick         fs_nanoseconds(min_nsec_timespec) -
31546035553Spatrick         duration_cast<fs_nanoseconds>(fs_seconds(1)));
31646035553Spatrick   }
31746035553Spatrick   // Static assert that these values properly round trip.
31846035553Spatrick   static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
31946035553Spatrick                     FileTimeT::duration::min(),
32046035553Spatrick                 "value doesn't roundtrip");
32146035553Spatrick 
check_rangetime_util_base322*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool check_range() {
32346035553Spatrick     // This kinda sucks, but it's what happens when we don't have __int128_t.
32446035553Spatrick     if (sizeof(TimeT) == sizeof(rep)) {
32546035553Spatrick       typedef duration<long long, ratio<3600 * 24 * 365> > Years;
32646035553Spatrick       return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
32746035553Spatrick              duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
32846035553Spatrick     }
32946035553Spatrick     return max_seconds >= numeric_limits<TimeT>::max() &&
33046035553Spatrick            min_seconds <= numeric_limits<TimeT>::min();
33146035553Spatrick   }
33246035553Spatrick   static_assert(check_range(), "the representable range is unacceptable small");
33346035553Spatrick };
33446035553Spatrick 
33546035553Spatrick template <class FileTimeT, class TimeT>
33646035553Spatrick struct time_util_base<FileTimeT, TimeT, true> {
33746035553Spatrick   using rep = typename FileTimeT::rep;
33846035553Spatrick   using fs_duration = typename FileTimeT::duration;
33946035553Spatrick   using fs_seconds = duration<rep>;
34046035553Spatrick   using fs_nanoseconds = duration<rep, nano>;
34146035553Spatrick   using fs_microseconds = duration<rep, micro>;
34246035553Spatrick 
34346035553Spatrick   static const rep max_seconds;
34446035553Spatrick   static const rep max_nsec;
34546035553Spatrick   static const rep min_seconds;
34646035553Spatrick   static const rep min_nsec_timespec;
34746035553Spatrick };
34846035553Spatrick 
34946035553Spatrick template <class FileTimeT, class TimeT>
35046035553Spatrick const typename FileTimeT::rep
35146035553Spatrick     time_util_base<FileTimeT, TimeT, true>::max_seconds =
35246035553Spatrick         duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
35346035553Spatrick 
35446035553Spatrick template <class FileTimeT, class TimeT>
35546035553Spatrick const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
35646035553Spatrick     duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
35746035553Spatrick                                   fs_seconds(max_seconds))
35846035553Spatrick         .count();
35946035553Spatrick 
36046035553Spatrick template <class FileTimeT, class TimeT>
36146035553Spatrick const typename FileTimeT::rep
36246035553Spatrick     time_util_base<FileTimeT, TimeT, true>::min_seconds =
36346035553Spatrick         duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
36446035553Spatrick 
36546035553Spatrick template <class FileTimeT, class TimeT>
36646035553Spatrick const typename FileTimeT::rep
36746035553Spatrick     time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
36846035553Spatrick         duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
36946035553Spatrick                                        fs_seconds(min_seconds)) +
37046035553Spatrick                                       fs_seconds(1))
37146035553Spatrick             .count();
37246035553Spatrick 
37346035553Spatrick template <class FileTimeT, class TimeT, class TimeSpecT>
37446035553Spatrick struct time_util : time_util_base<FileTimeT, TimeT> {
37546035553Spatrick   using Base = time_util_base<FileTimeT, TimeT>;
37646035553Spatrick   using Base::max_nsec;
37746035553Spatrick   using Base::max_seconds;
37846035553Spatrick   using Base::min_nsec_timespec;
37946035553Spatrick   using Base::min_seconds;
38046035553Spatrick 
38146035553Spatrick   using typename Base::fs_duration;
38246035553Spatrick   using typename Base::fs_microseconds;
38346035553Spatrick   using typename Base::fs_nanoseconds;
38446035553Spatrick   using typename Base::fs_seconds;
38546035553Spatrick 
38646035553Spatrick public:
38746035553Spatrick   template <class CType, class ChronoType>
388*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool checked_set(CType* out,
38946035553Spatrick                                                         ChronoType time) {
39046035553Spatrick     using Lim = numeric_limits<CType>;
39146035553Spatrick     if (time > Lim::max() || time < Lim::min())
39246035553Spatrick       return false;
39346035553Spatrick     *out = static_cast<CType>(time);
39446035553Spatrick     return true;
39546035553Spatrick   }
39646035553Spatrick 
397*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool is_representable(TimeSpecT tm) {
39846035553Spatrick     if (tm.tv_sec >= 0) {
39946035553Spatrick       return tm.tv_sec < max_seconds ||
40046035553Spatrick              (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
40146035553Spatrick     } else if (tm.tv_sec == (min_seconds - 1)) {
40246035553Spatrick       return tm.tv_nsec >= min_nsec_timespec;
40346035553Spatrick     } else {
40446035553Spatrick       return tm.tv_sec >= min_seconds;
40546035553Spatrick     }
40646035553Spatrick   }
40746035553Spatrick 
408*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool is_representable(FileTimeT tm) {
40946035553Spatrick     auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
41046035553Spatrick     auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
41146035553Spatrick     if (nsecs.count() < 0) {
41246035553Spatrick       secs = secs + fs_seconds(1);
41346035553Spatrick       nsecs = nsecs + fs_seconds(1);
41446035553Spatrick     }
41546035553Spatrick     using TLim = numeric_limits<TimeT>;
41646035553Spatrick     if (secs.count() >= 0)
41746035553Spatrick       return secs.count() <= TLim::max();
41846035553Spatrick     return secs.count() >= TLim::min();
41946035553Spatrick   }
42046035553Spatrick 
421*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 FileTimeT
42246035553Spatrick   convert_from_timespec(TimeSpecT tm) {
42346035553Spatrick     if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
42446035553Spatrick       return FileTimeT(fs_seconds(tm.tv_sec) +
42546035553Spatrick                        duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
42646035553Spatrick     } else { // tm.tv_sec < 0
42746035553Spatrick       auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
42846035553Spatrick                                                    fs_nanoseconds(tm.tv_nsec));
42946035553Spatrick       auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
43046035553Spatrick       return FileTimeT(Dur);
43146035553Spatrick     }
43246035553Spatrick   }
43346035553Spatrick 
43446035553Spatrick   template <class SubSecT>
435*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
43646035553Spatrick   set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
43746035553Spatrick     auto dur = tp.time_since_epoch();
43846035553Spatrick     auto sec_dur = duration_cast<fs_seconds>(dur);
43946035553Spatrick     auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
44046035553Spatrick     // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
44146035553Spatrick     if (subsec_dur.count() < 0) {
44246035553Spatrick       if (sec_dur.count() > min_seconds) {
44346035553Spatrick         sec_dur = sec_dur - fs_seconds(1);
44446035553Spatrick         subsec_dur = subsec_dur + fs_seconds(1);
44546035553Spatrick       } else {
44646035553Spatrick         subsec_dur = fs_nanoseconds::zero();
44746035553Spatrick       }
44846035553Spatrick     }
44946035553Spatrick     return checked_set(sec_out, sec_dur.count()) &&
45046035553Spatrick            checked_set(subsec_out, subsec_dur.count());
45146035553Spatrick   }
452*4bdff4beSrobert   static _LIBCPP_CONSTEXPR_SINCE_CXX14 bool convert_to_timespec(TimeSpecT& dest,
45346035553Spatrick                                                                 FileTimeT tp) {
45446035553Spatrick     if (!is_representable(tp))
45546035553Spatrick       return false;
45646035553Spatrick     return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
45746035553Spatrick   }
45846035553Spatrick };
45946035553Spatrick 
46076d0caaeSpatrick #if defined(_LIBCPP_WIN32API)
46176d0caaeSpatrick using fs_time = time_util<file_time_type, int64_t, TimeSpec>;
46246035553Spatrick #else
46376d0caaeSpatrick using fs_time = time_util<file_time_type, time_t, TimeSpec>;
46446035553Spatrick #endif
46546035553Spatrick 
46676d0caaeSpatrick #if defined(__APPLE__)
46776d0caaeSpatrick inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
46876d0caaeSpatrick inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
46976d0caaeSpatrick #elif defined(__MVS__)
47076d0caaeSpatrick inline TimeSpec extract_mtime(StatT const& st) {
47176d0caaeSpatrick   TimeSpec TS = {st.st_mtime, 0};
47276d0caaeSpatrick   return TS;
47376d0caaeSpatrick }
47476d0caaeSpatrick inline TimeSpec extract_atime(StatT const& st) {
47576d0caaeSpatrick   TimeSpec TS = {st.st_atime, 0};
47676d0caaeSpatrick   return TS;
47776d0caaeSpatrick }
47876d0caaeSpatrick #elif defined(_AIX)
47976d0caaeSpatrick inline TimeSpec extract_mtime(StatT const& st) {
48076d0caaeSpatrick   TimeSpec TS = {st.st_mtime, st.st_mtime_n};
48176d0caaeSpatrick   return TS;
48276d0caaeSpatrick }
48376d0caaeSpatrick inline TimeSpec extract_atime(StatT const& st) {
48476d0caaeSpatrick   TimeSpec TS = {st.st_atime, st.st_atime_n};
48576d0caaeSpatrick   return TS;
48676d0caaeSpatrick }
48776d0caaeSpatrick #else
48876d0caaeSpatrick inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
48976d0caaeSpatrick inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
49076d0caaeSpatrick #endif
49146035553Spatrick 
49276d0caaeSpatrick #if !defined(_LIBCPP_WIN32API)
49376d0caaeSpatrick inline TimeVal make_timeval(TimeSpec const& ts) {
49446035553Spatrick   using namespace chrono;
49546035553Spatrick   auto Convert = [](long nsec) {
49676d0caaeSpatrick     using int_type = decltype(std::declval<TimeVal>().tv_usec);
49746035553Spatrick     auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
49846035553Spatrick     return static_cast<int_type>(dur);
49946035553Spatrick   };
50076d0caaeSpatrick   TimeVal TV = {};
50176d0caaeSpatrick   TV.tv_sec = ts.tv_sec;
50276d0caaeSpatrick   TV.tv_usec = Convert(ts.tv_nsec);
50376d0caaeSpatrick   return TV;
50476d0caaeSpatrick }
50576d0caaeSpatrick 
50676d0caaeSpatrick inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
50776d0caaeSpatrick                   error_code& ec) {
50876d0caaeSpatrick   TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])};
50946035553Spatrick   if (::utimes(p.c_str(), ConvertedTS) == -1) {
51046035553Spatrick     ec = capture_errno();
51146035553Spatrick     return true;
51246035553Spatrick   }
51346035553Spatrick   return false;
51446035553Spatrick }
51546035553Spatrick 
51646035553Spatrick #if defined(_LIBCPP_USE_UTIMENSAT)
51746035553Spatrick bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
51846035553Spatrick                      error_code& ec) {
51946035553Spatrick   if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
52046035553Spatrick     ec = capture_errno();
52146035553Spatrick     return true;
52246035553Spatrick   }
52346035553Spatrick   return false;
52446035553Spatrick }
52546035553Spatrick #endif
52646035553Spatrick 
52746035553Spatrick bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
52846035553Spatrick                     error_code& ec) {
52946035553Spatrick #if !defined(_LIBCPP_USE_UTIMENSAT)
53046035553Spatrick   return posix_utimes(p, TS, ec);
53146035553Spatrick #else
53246035553Spatrick   return posix_utimensat(p, TS, ec);
53346035553Spatrick #endif
53446035553Spatrick }
535*4bdff4beSrobert 
536*4bdff4beSrobert #if defined(DT_BLK)
537*4bdff4beSrobert template <class DirEntT, class = decltype(DirEntT::d_type)>
538*4bdff4beSrobert static file_type get_file_type(DirEntT* ent, int) {
539*4bdff4beSrobert   switch (ent->d_type) {
540*4bdff4beSrobert   case DT_BLK:
541*4bdff4beSrobert     return file_type::block;
542*4bdff4beSrobert   case DT_CHR:
543*4bdff4beSrobert     return file_type::character;
544*4bdff4beSrobert   case DT_DIR:
545*4bdff4beSrobert     return file_type::directory;
546*4bdff4beSrobert   case DT_FIFO:
547*4bdff4beSrobert     return file_type::fifo;
548*4bdff4beSrobert   case DT_LNK:
549*4bdff4beSrobert     return file_type::symlink;
550*4bdff4beSrobert   case DT_REG:
551*4bdff4beSrobert     return file_type::regular;
552*4bdff4beSrobert   case DT_SOCK:
553*4bdff4beSrobert     return file_type::socket;
554*4bdff4beSrobert   // Unlike in lstat, hitting "unknown" here simply means that the underlying
555*4bdff4beSrobert   // filesystem doesn't support d_type. Report is as 'none' so we correctly
556*4bdff4beSrobert   // set the cache to empty.
557*4bdff4beSrobert   case DT_UNKNOWN:
558*4bdff4beSrobert     break;
559*4bdff4beSrobert   }
560*4bdff4beSrobert   return file_type::none;
561*4bdff4beSrobert }
562*4bdff4beSrobert #endif // defined(DT_BLK)
563*4bdff4beSrobert 
564*4bdff4beSrobert template <class DirEntT>
565*4bdff4beSrobert static file_type get_file_type(DirEntT*, long) {
566*4bdff4beSrobert   return file_type::none;
567*4bdff4beSrobert }
568*4bdff4beSrobert 
569*4bdff4beSrobert static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
570*4bdff4beSrobert                                                   error_code& ec) {
571*4bdff4beSrobert   struct dirent* dir_entry_ptr = nullptr;
572*4bdff4beSrobert   errno = 0; // zero errno in order to detect errors
573*4bdff4beSrobert   ec.clear();
574*4bdff4beSrobert   if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
575*4bdff4beSrobert     if (errno)
576*4bdff4beSrobert       ec = capture_errno();
577*4bdff4beSrobert     return {};
578*4bdff4beSrobert   } else {
579*4bdff4beSrobert     return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
580*4bdff4beSrobert   }
581*4bdff4beSrobert }
582*4bdff4beSrobert 
583*4bdff4beSrobert #else // _LIBCPP_WIN32API
584*4bdff4beSrobert 
585*4bdff4beSrobert static file_type get_file_type(const WIN32_FIND_DATAW& data) {
586*4bdff4beSrobert   if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
587*4bdff4beSrobert       data.dwReserved0 == IO_REPARSE_TAG_SYMLINK)
588*4bdff4beSrobert     return file_type::symlink;
589*4bdff4beSrobert   if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
590*4bdff4beSrobert     return file_type::directory;
591*4bdff4beSrobert   return file_type::regular;
592*4bdff4beSrobert }
593*4bdff4beSrobert static uintmax_t get_file_size(const WIN32_FIND_DATAW& data) {
594*4bdff4beSrobert   return (static_cast<uint64_t>(data.nFileSizeHigh) << 32) + data.nFileSizeLow;
595*4bdff4beSrobert }
596*4bdff4beSrobert static file_time_type get_write_time(const WIN32_FIND_DATAW& data) {
597*4bdff4beSrobert   ULARGE_INTEGER tmp;
598*4bdff4beSrobert   const FILETIME& time = data.ftLastWriteTime;
599*4bdff4beSrobert   tmp.u.LowPart = time.dwLowDateTime;
600*4bdff4beSrobert   tmp.u.HighPart = time.dwHighDateTime;
601*4bdff4beSrobert   return file_time_type(file_time_type::duration(tmp.QuadPart));
602*4bdff4beSrobert }
603*4bdff4beSrobert 
604*4bdff4beSrobert #endif // !_LIBCPP_WIN32API
60546035553Spatrick 
60646035553Spatrick } // namespace
60746035553Spatrick } // end namespace detail
60846035553Spatrick 
60946035553Spatrick _LIBCPP_END_NAMESPACE_FILESYSTEM
61046035553Spatrick 
611*4bdff4beSrobert _LIBCPP_DIAGNOSTIC_POP
612*4bdff4beSrobert 
61346035553Spatrick #endif // FILESYSTEM_COMMON_H
614