14ba319b5SDimitry Andric //===----------------------------------------------------------------------===////
24ba319b5SDimitry Andric //
34ba319b5SDimitry Andric //                     The LLVM Compiler Infrastructure
44ba319b5SDimitry Andric //
54ba319b5SDimitry Andric // This file is dual licensed under the MIT and the University of Illinois Open
64ba319b5SDimitry Andric // Source Licenses. See LICENSE.TXT for details.
74ba319b5SDimitry Andric //
84ba319b5SDimitry Andric //===----------------------------------------------------------------------===////
94ba319b5SDimitry Andric 
104ba319b5SDimitry Andric #ifndef FILESYSTEM_COMMON_H
114ba319b5SDimitry Andric #define FILESYSTEM_COMMON_H
124ba319b5SDimitry Andric 
134ba319b5SDimitry Andric #include "__config"
144ba319b5SDimitry Andric #include "filesystem"
154ba319b5SDimitry Andric #include "array"
164ba319b5SDimitry Andric #include "chrono"
174ba319b5SDimitry Andric #include "cstdlib"
184ba319b5SDimitry Andric #include "climits"
194ba319b5SDimitry Andric 
204ba319b5SDimitry Andric #include <unistd.h>
214ba319b5SDimitry Andric #include <sys/stat.h>
224ba319b5SDimitry Andric #include <sys/statvfs.h>
234ba319b5SDimitry Andric #include <sys/time.h> // for ::utimes as used in __last_write_time
244ba319b5SDimitry Andric #include <fcntl.h>    /* values for fchmodat */
254ba319b5SDimitry Andric 
264ba319b5SDimitry Andric #include "../include/apple_availability.h"
274ba319b5SDimitry Andric 
284ba319b5SDimitry Andric #if !defined(__APPLE__)
294ba319b5SDimitry Andric // We can use the presence of UTIME_OMIT to detect platforms that provide
304ba319b5SDimitry Andric // utimensat.
314ba319b5SDimitry Andric #if defined(UTIME_OMIT)
324ba319b5SDimitry Andric #define _LIBCPP_USE_UTIMENSAT
334ba319b5SDimitry Andric #endif
344ba319b5SDimitry Andric #endif
354ba319b5SDimitry Andric 
364ba319b5SDimitry Andric #if defined(__GNUC__)
374ba319b5SDimitry Andric #pragma GCC diagnostic push
384ba319b5SDimitry Andric #pragma GCC diagnostic ignored "-Wunused-function"
394ba319b5SDimitry Andric #endif
404ba319b5SDimitry Andric 
414ba319b5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
424ba319b5SDimitry Andric 
434ba319b5SDimitry Andric namespace detail {
444ba319b5SDimitry Andric namespace {
454ba319b5SDimitry Andric 
format_string_imp(const char * msg,...)464ba319b5SDimitry Andric static string format_string_imp(const char* msg, ...) {
474ba319b5SDimitry Andric   // we might need a second shot at this, so pre-emptivly make a copy
484ba319b5SDimitry Andric   struct GuardVAList {
494ba319b5SDimitry Andric     va_list& target;
504ba319b5SDimitry Andric     bool active = true;
514ba319b5SDimitry Andric     GuardVAList(va_list& target) : target(target), active(true) {}
524ba319b5SDimitry Andric     void clear() {
534ba319b5SDimitry Andric       if (active)
544ba319b5SDimitry Andric         va_end(target);
554ba319b5SDimitry Andric       active = false;
564ba319b5SDimitry Andric     }
574ba319b5SDimitry Andric     ~GuardVAList() {
584ba319b5SDimitry Andric       if (active)
594ba319b5SDimitry Andric         va_end(target);
604ba319b5SDimitry Andric     }
614ba319b5SDimitry Andric   };
624ba319b5SDimitry Andric   va_list args;
634ba319b5SDimitry Andric   va_start(args, msg);
644ba319b5SDimitry Andric   GuardVAList args_guard(args);
654ba319b5SDimitry Andric 
664ba319b5SDimitry Andric   va_list args_cp;
674ba319b5SDimitry Andric   va_copy(args_cp, args);
684ba319b5SDimitry Andric   GuardVAList args_copy_guard(args_cp);
694ba319b5SDimitry Andric 
70*b5893f02SDimitry Andric   std::string result;
71*b5893f02SDimitry Andric 
724ba319b5SDimitry Andric   array<char, 256> local_buff;
73*b5893f02SDimitry Andric   size_t size_with_null = local_buff.size();
74*b5893f02SDimitry Andric   auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
754ba319b5SDimitry Andric 
764ba319b5SDimitry Andric   args_copy_guard.clear();
774ba319b5SDimitry Andric 
784ba319b5SDimitry Andric   // handle empty expansion
794ba319b5SDimitry Andric   if (ret == 0)
80*b5893f02SDimitry Andric     return result;
81*b5893f02SDimitry Andric   if (static_cast<size_t>(ret) < size_with_null) {
82*b5893f02SDimitry Andric     result.assign(local_buff.data(), static_cast<size_t>(ret));
83*b5893f02SDimitry Andric     return result;
84*b5893f02SDimitry Andric   }
854ba319b5SDimitry Andric 
86*b5893f02SDimitry Andric   // we did not provide a long enough buffer on our first attempt. The
87*b5893f02SDimitry Andric   // return value is the number of bytes (excluding the null byte) that are
88*b5893f02SDimitry Andric   // needed for formatting.
89*b5893f02SDimitry Andric   size_with_null = static_cast<size_t>(ret) + 1;
90*b5893f02SDimitry Andric   result.__resize_default_init(size_with_null - 1);
91*b5893f02SDimitry Andric   ret = ::vsnprintf(&result[0], size_with_null, msg, args);
92*b5893f02SDimitry Andric   _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
93*b5893f02SDimitry Andric 
94*b5893f02SDimitry Andric   return result;
954ba319b5SDimitry Andric }
964ba319b5SDimitry Andric 
unwrap(string const & s)974ba319b5SDimitry Andric const char* unwrap(string const& s) { return s.c_str(); }
unwrap(path const & p)984ba319b5SDimitry Andric const char* unwrap(path const& p) { return p.native().c_str(); }
994ba319b5SDimitry Andric template <class Arg>
unwrap(Arg const & a)1004ba319b5SDimitry Andric Arg const& unwrap(Arg const& a) {
1014ba319b5SDimitry Andric   static_assert(!is_class<Arg>::value, "cannot pass class here");
1024ba319b5SDimitry Andric   return a;
1034ba319b5SDimitry Andric }
1044ba319b5SDimitry Andric 
1054ba319b5SDimitry Andric template <class... Args>
format_string(const char * fmt,Args const &...args)1064ba319b5SDimitry Andric string format_string(const char* fmt, Args const&... args) {
1074ba319b5SDimitry Andric   return format_string_imp(fmt, unwrap(args)...);
1084ba319b5SDimitry Andric }
1094ba319b5SDimitry Andric 
capture_errno()1104ba319b5SDimitry Andric error_code capture_errno() {
1114ba319b5SDimitry Andric   _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
1124ba319b5SDimitry Andric   return error_code(errno, generic_category());
1134ba319b5SDimitry Andric }
1144ba319b5SDimitry Andric 
1154ba319b5SDimitry Andric template <class T>
1164ba319b5SDimitry Andric T error_value();
1174ba319b5SDimitry Andric template <>
1184ba319b5SDimitry Andric _LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
1194ba319b5SDimitry Andric template <>
1204ba319b5SDimitry Andric bool error_value<bool>() {
1214ba319b5SDimitry Andric   return false;
1224ba319b5SDimitry Andric }
1234ba319b5SDimitry Andric template <>
1244ba319b5SDimitry Andric uintmax_t error_value<uintmax_t>() {
1254ba319b5SDimitry Andric   return uintmax_t(-1);
1264ba319b5SDimitry Andric }
1274ba319b5SDimitry Andric template <>
1284ba319b5SDimitry Andric _LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
1294ba319b5SDimitry Andric   return file_time_type::min();
1304ba319b5SDimitry Andric }
1314ba319b5SDimitry Andric template <>
1324ba319b5SDimitry Andric path error_value<path>() {
1334ba319b5SDimitry Andric   return {};
1344ba319b5SDimitry Andric }
1354ba319b5SDimitry Andric 
1364ba319b5SDimitry Andric template <class T>
1374ba319b5SDimitry Andric struct ErrorHandler {
1384ba319b5SDimitry Andric   const char* func_name;
1394ba319b5SDimitry Andric   error_code* ec = nullptr;
1404ba319b5SDimitry Andric   const path* p1 = nullptr;
1414ba319b5SDimitry Andric   const path* p2 = nullptr;
1424ba319b5SDimitry Andric 
1434ba319b5SDimitry Andric   ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
1444ba319b5SDimitry Andric                const path* p2 = nullptr)
func_nameErrorHandler1454ba319b5SDimitry Andric       : func_name(fname), ec(ec), p1(p1), p2(p2) {
1464ba319b5SDimitry Andric     if (ec)
1474ba319b5SDimitry Andric       ec->clear();
1484ba319b5SDimitry Andric   }
1494ba319b5SDimitry Andric 
reportErrorHandler1504ba319b5SDimitry Andric   T report(const error_code& m_ec) const {
1514ba319b5SDimitry Andric     if (ec) {
1524ba319b5SDimitry Andric       *ec = m_ec;
1534ba319b5SDimitry Andric       return error_value<T>();
1544ba319b5SDimitry Andric     }
1554ba319b5SDimitry Andric     string what = string("in ") + func_name;
1564ba319b5SDimitry Andric     switch (bool(p1) + bool(p2)) {
1574ba319b5SDimitry Andric     case 0:
1584ba319b5SDimitry Andric       __throw_filesystem_error(what, m_ec);
1594ba319b5SDimitry Andric     case 1:
1604ba319b5SDimitry Andric       __throw_filesystem_error(what, *p1, m_ec);
1614ba319b5SDimitry Andric     case 2:
1624ba319b5SDimitry Andric       __throw_filesystem_error(what, *p1, *p2, m_ec);
1634ba319b5SDimitry Andric     }
1644ba319b5SDimitry Andric     _LIBCPP_UNREACHABLE();
1654ba319b5SDimitry Andric   }
1664ba319b5SDimitry Andric 
1674ba319b5SDimitry Andric   template <class... Args>
reportErrorHandler1684ba319b5SDimitry Andric   T report(const error_code& m_ec, const char* msg, Args const&... args) const {
1694ba319b5SDimitry Andric     if (ec) {
1704ba319b5SDimitry Andric       *ec = m_ec;
1714ba319b5SDimitry Andric       return error_value<T>();
1724ba319b5SDimitry Andric     }
1734ba319b5SDimitry Andric     string what =
1744ba319b5SDimitry Andric         string("in ") + func_name + ": " + format_string(msg, args...);
1754ba319b5SDimitry Andric     switch (bool(p1) + bool(p2)) {
1764ba319b5SDimitry Andric     case 0:
1774ba319b5SDimitry Andric       __throw_filesystem_error(what, m_ec);
1784ba319b5SDimitry Andric     case 1:
1794ba319b5SDimitry Andric       __throw_filesystem_error(what, *p1, m_ec);
1804ba319b5SDimitry Andric     case 2:
1814ba319b5SDimitry Andric       __throw_filesystem_error(what, *p1, *p2, m_ec);
1824ba319b5SDimitry Andric     }
1834ba319b5SDimitry Andric     _LIBCPP_UNREACHABLE();
1844ba319b5SDimitry Andric   }
1854ba319b5SDimitry Andric 
reportErrorHandler1864ba319b5SDimitry Andric   T report(errc const& err) const { return report(make_error_code(err)); }
1874ba319b5SDimitry Andric 
1884ba319b5SDimitry Andric   template <class... Args>
reportErrorHandler1894ba319b5SDimitry Andric   T report(errc const& err, const char* msg, Args const&... args) const {
1904ba319b5SDimitry Andric     return report(make_error_code(err), msg, args...);
1914ba319b5SDimitry Andric   }
1924ba319b5SDimitry Andric 
1934ba319b5SDimitry Andric private:
1944ba319b5SDimitry Andric   ErrorHandler(ErrorHandler const&) = delete;
1954ba319b5SDimitry Andric   ErrorHandler& operator=(ErrorHandler const&) = delete;
1964ba319b5SDimitry Andric };
1974ba319b5SDimitry Andric 
1984ba319b5SDimitry Andric using chrono::duration;
1994ba319b5SDimitry Andric using chrono::duration_cast;
2004ba319b5SDimitry Andric 
2014ba319b5SDimitry Andric using TimeSpec = struct ::timespec;
2024ba319b5SDimitry Andric using StatT = struct ::stat;
2034ba319b5SDimitry Andric 
2044ba319b5SDimitry Andric template <class FileTimeT, class TimeT,
2054ba319b5SDimitry Andric           bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
2064ba319b5SDimitry Andric struct time_util_base {
2074ba319b5SDimitry Andric   using rep = typename FileTimeT::rep;
2084ba319b5SDimitry Andric   using fs_duration = typename FileTimeT::duration;
2094ba319b5SDimitry Andric   using fs_seconds = duration<rep>;
2104ba319b5SDimitry Andric   using fs_nanoseconds = duration<rep, nano>;
2114ba319b5SDimitry Andric   using fs_microseconds = duration<rep, micro>;
2124ba319b5SDimitry Andric 
2134ba319b5SDimitry Andric   static constexpr rep max_seconds =
2144ba319b5SDimitry Andric       duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
2154ba319b5SDimitry Andric 
2164ba319b5SDimitry Andric   static constexpr rep max_nsec =
2174ba319b5SDimitry Andric       duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
2184ba319b5SDimitry Andric                                     fs_seconds(max_seconds))
2194ba319b5SDimitry Andric           .count();
2204ba319b5SDimitry Andric 
2214ba319b5SDimitry Andric   static constexpr rep min_seconds =
2224ba319b5SDimitry Andric       duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
2234ba319b5SDimitry Andric 
2244ba319b5SDimitry Andric   static constexpr rep min_nsec_timespec =
2254ba319b5SDimitry Andric       duration_cast<fs_nanoseconds>(
2264ba319b5SDimitry Andric           (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
2274ba319b5SDimitry Andric           fs_seconds(1))
2284ba319b5SDimitry Andric           .count();
2294ba319b5SDimitry Andric 
2304ba319b5SDimitry Andric private:
2314ba319b5SDimitry Andric #if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
get_min_nsecstime_util_base2324ba319b5SDimitry Andric   static constexpr fs_duration get_min_nsecs() {
2334ba319b5SDimitry Andric     return duration_cast<fs_duration>(
2344ba319b5SDimitry Andric         fs_nanoseconds(min_nsec_timespec) -
2354ba319b5SDimitry Andric         duration_cast<fs_nanoseconds>(fs_seconds(1)));
2364ba319b5SDimitry Andric   }
2374ba319b5SDimitry Andric   // Static assert that these values properly round trip.
2384ba319b5SDimitry Andric   static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
2394ba319b5SDimitry Andric                     FileTimeT::duration::min(),
2404ba319b5SDimitry Andric                 "value doesn't roundtrip");
2414ba319b5SDimitry Andric 
check_rangetime_util_base2424ba319b5SDimitry Andric   static constexpr bool check_range() {
2434ba319b5SDimitry Andric     // This kinda sucks, but it's what happens when we don't have __int128_t.
2444ba319b5SDimitry Andric     if (sizeof(TimeT) == sizeof(rep)) {
2454ba319b5SDimitry Andric       typedef duration<long long, ratio<3600 * 24 * 365> > Years;
2464ba319b5SDimitry Andric       return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
2474ba319b5SDimitry Andric              duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
2484ba319b5SDimitry Andric     }
2494ba319b5SDimitry Andric     return max_seconds >= numeric_limits<TimeT>::max() &&
2504ba319b5SDimitry Andric            min_seconds <= numeric_limits<TimeT>::min();
2514ba319b5SDimitry Andric   }
2524ba319b5SDimitry Andric   static_assert(check_range(), "the representable range is unacceptable small");
2534ba319b5SDimitry Andric #endif
2544ba319b5SDimitry Andric };
2554ba319b5SDimitry Andric 
2564ba319b5SDimitry Andric template <class FileTimeT, class TimeT>
2574ba319b5SDimitry Andric struct time_util_base<FileTimeT, TimeT, true> {
2584ba319b5SDimitry Andric   using rep = typename FileTimeT::rep;
2594ba319b5SDimitry Andric   using fs_duration = typename FileTimeT::duration;
2604ba319b5SDimitry Andric   using fs_seconds = duration<rep>;
2614ba319b5SDimitry Andric   using fs_nanoseconds = duration<rep, nano>;
2624ba319b5SDimitry Andric   using fs_microseconds = duration<rep, micro>;
2634ba319b5SDimitry Andric 
2644ba319b5SDimitry Andric   static const rep max_seconds;
2654ba319b5SDimitry Andric   static const rep max_nsec;
2664ba319b5SDimitry Andric   static const rep min_seconds;
2674ba319b5SDimitry Andric   static const rep min_nsec_timespec;
2684ba319b5SDimitry Andric };
2694ba319b5SDimitry Andric 
2704ba319b5SDimitry Andric template <class FileTimeT, class TimeT>
2714ba319b5SDimitry Andric const typename FileTimeT::rep
2724ba319b5SDimitry Andric     time_util_base<FileTimeT, TimeT, true>::max_seconds =
2734ba319b5SDimitry Andric         duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
2744ba319b5SDimitry Andric 
2754ba319b5SDimitry Andric template <class FileTimeT, class TimeT>
2764ba319b5SDimitry Andric const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
2774ba319b5SDimitry Andric     duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
2784ba319b5SDimitry Andric                                   fs_seconds(max_seconds))
2794ba319b5SDimitry Andric         .count();
2804ba319b5SDimitry Andric 
2814ba319b5SDimitry Andric template <class FileTimeT, class TimeT>
2824ba319b5SDimitry Andric const typename FileTimeT::rep
2834ba319b5SDimitry Andric     time_util_base<FileTimeT, TimeT, true>::min_seconds =
2844ba319b5SDimitry Andric         duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
2854ba319b5SDimitry Andric 
2864ba319b5SDimitry Andric template <class FileTimeT, class TimeT>
2874ba319b5SDimitry Andric const typename FileTimeT::rep
2884ba319b5SDimitry Andric     time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
2894ba319b5SDimitry Andric         duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
2904ba319b5SDimitry Andric                                        fs_seconds(min_seconds)) +
2914ba319b5SDimitry Andric                                       fs_seconds(1))
2924ba319b5SDimitry Andric             .count();
2934ba319b5SDimitry Andric 
2944ba319b5SDimitry Andric template <class FileTimeT, class TimeT, class TimeSpecT>
2954ba319b5SDimitry Andric struct time_util : time_util_base<FileTimeT, TimeT> {
2964ba319b5SDimitry Andric   using Base = time_util_base<FileTimeT, TimeT>;
2974ba319b5SDimitry Andric   using Base::max_nsec;
2984ba319b5SDimitry Andric   using Base::max_seconds;
2994ba319b5SDimitry Andric   using Base::min_nsec_timespec;
3004ba319b5SDimitry Andric   using Base::min_seconds;
3014ba319b5SDimitry Andric 
3024ba319b5SDimitry Andric   using typename Base::fs_duration;
3034ba319b5SDimitry Andric   using typename Base::fs_microseconds;
3044ba319b5SDimitry Andric   using typename Base::fs_nanoseconds;
3054ba319b5SDimitry Andric   using typename Base::fs_seconds;
3064ba319b5SDimitry Andric 
3074ba319b5SDimitry Andric public:
3084ba319b5SDimitry Andric   template <class CType, class ChronoType>
3094ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
3104ba319b5SDimitry Andric                                                         ChronoType time) {
3114ba319b5SDimitry Andric     using Lim = numeric_limits<CType>;
3124ba319b5SDimitry Andric     if (time > Lim::max() || time < Lim::min())
3134ba319b5SDimitry Andric       return false;
3144ba319b5SDimitry Andric     *out = static_cast<CType>(time);
3154ba319b5SDimitry Andric     return true;
3164ba319b5SDimitry Andric   }
3174ba319b5SDimitry Andric 
3184ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
3194ba319b5SDimitry Andric     if (tm.tv_sec >= 0) {
3204ba319b5SDimitry Andric       return tm.tv_sec < max_seconds ||
3214ba319b5SDimitry Andric              (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
3224ba319b5SDimitry Andric     } else if (tm.tv_sec == (min_seconds - 1)) {
3234ba319b5SDimitry Andric       return tm.tv_nsec >= min_nsec_timespec;
3244ba319b5SDimitry Andric     } else {
3254ba319b5SDimitry Andric       return tm.tv_sec >= min_seconds;
3264ba319b5SDimitry Andric     }
3274ba319b5SDimitry Andric   }
3284ba319b5SDimitry Andric 
3294ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
3304ba319b5SDimitry Andric     auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
3314ba319b5SDimitry Andric     auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
3324ba319b5SDimitry Andric     if (nsecs.count() < 0) {
3334ba319b5SDimitry Andric       secs = secs + fs_seconds(1);
3344ba319b5SDimitry Andric       nsecs = nsecs + fs_seconds(1);
3354ba319b5SDimitry Andric     }
3364ba319b5SDimitry Andric     using TLim = numeric_limits<TimeT>;
3374ba319b5SDimitry Andric     if (secs.count() >= 0)
3384ba319b5SDimitry Andric       return secs.count() <= TLim::max();
3394ba319b5SDimitry Andric     return secs.count() >= TLim::min();
3404ba319b5SDimitry Andric   }
3414ba319b5SDimitry Andric 
3424ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
3434ba319b5SDimitry Andric   convert_from_timespec(TimeSpecT tm) {
3444ba319b5SDimitry Andric     if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
3454ba319b5SDimitry Andric       return FileTimeT(fs_seconds(tm.tv_sec) +
3464ba319b5SDimitry Andric                        duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
3474ba319b5SDimitry Andric     } else { // tm.tv_sec < 0
3484ba319b5SDimitry Andric       auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
3494ba319b5SDimitry Andric                                                    fs_nanoseconds(tm.tv_nsec));
3504ba319b5SDimitry Andric       auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
3514ba319b5SDimitry Andric       return FileTimeT(Dur);
3524ba319b5SDimitry Andric     }
3534ba319b5SDimitry Andric   }
3544ba319b5SDimitry Andric 
3554ba319b5SDimitry Andric   template <class SubSecT>
3564ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
3574ba319b5SDimitry Andric   set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
3584ba319b5SDimitry Andric     auto dur = tp.time_since_epoch();
3594ba319b5SDimitry Andric     auto sec_dur = duration_cast<fs_seconds>(dur);
3604ba319b5SDimitry Andric     auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
3614ba319b5SDimitry Andric     // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
3624ba319b5SDimitry Andric     if (subsec_dur.count() < 0) {
3634ba319b5SDimitry Andric       if (sec_dur.count() > min_seconds) {
3644ba319b5SDimitry Andric         sec_dur = sec_dur - fs_seconds(1);
3654ba319b5SDimitry Andric         subsec_dur = subsec_dur + fs_seconds(1);
3664ba319b5SDimitry Andric       } else {
3674ba319b5SDimitry Andric         subsec_dur = fs_nanoseconds::zero();
3684ba319b5SDimitry Andric       }
3694ba319b5SDimitry Andric     }
3704ba319b5SDimitry Andric     return checked_set(sec_out, sec_dur.count()) &&
3714ba319b5SDimitry Andric            checked_set(subsec_out, subsec_dur.count());
3724ba319b5SDimitry Andric   }
3734ba319b5SDimitry Andric   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
3744ba319b5SDimitry Andric                                                                 FileTimeT tp) {
3754ba319b5SDimitry Andric     if (!is_representable(tp))
3764ba319b5SDimitry Andric       return false;
3774ba319b5SDimitry Andric     return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
3784ba319b5SDimitry Andric   }
3794ba319b5SDimitry Andric };
3804ba319b5SDimitry Andric 
3814ba319b5SDimitry Andric using fs_time = time_util<file_time_type, time_t, TimeSpec>;
3824ba319b5SDimitry Andric 
3834ba319b5SDimitry Andric #if defined(__APPLE__)
3844ba319b5SDimitry Andric TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
3854ba319b5SDimitry Andric TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
3864ba319b5SDimitry Andric #else
3874ba319b5SDimitry Andric TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
3884ba319b5SDimitry Andric TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
3894ba319b5SDimitry Andric #endif
3904ba319b5SDimitry Andric 
3914ba319b5SDimitry Andric // allow the utimes implementation to compile even it we're not going
3924ba319b5SDimitry Andric // to use it.
3934ba319b5SDimitry Andric 
3944ba319b5SDimitry Andric bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
3954ba319b5SDimitry Andric                   error_code& ec) {
3964ba319b5SDimitry Andric   using namespace chrono;
3974ba319b5SDimitry Andric   auto Convert = [](long nsec) {
3984ba319b5SDimitry Andric     using int_type = decltype(std::declval< ::timeval>().tv_usec);
3994ba319b5SDimitry Andric     auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
4004ba319b5SDimitry Andric     return static_cast<int_type>(dur);
4014ba319b5SDimitry Andric   };
4024ba319b5SDimitry Andric   struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
4034ba319b5SDimitry Andric                                      {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
4044ba319b5SDimitry Andric   if (::utimes(p.c_str(), ConvertedTS) == -1) {
4054ba319b5SDimitry Andric     ec = capture_errno();
4064ba319b5SDimitry Andric     return true;
4074ba319b5SDimitry Andric   }
4084ba319b5SDimitry Andric   return false;
4094ba319b5SDimitry Andric }
4104ba319b5SDimitry Andric 
4114ba319b5SDimitry Andric #if defined(_LIBCPP_USE_UTIMENSAT)
4124ba319b5SDimitry Andric bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
4134ba319b5SDimitry Andric                      error_code& ec) {
4144ba319b5SDimitry Andric   if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
4154ba319b5SDimitry Andric     ec = capture_errno();
4164ba319b5SDimitry Andric     return true;
4174ba319b5SDimitry Andric   }
4184ba319b5SDimitry Andric   return false;
4194ba319b5SDimitry Andric }
4204ba319b5SDimitry Andric #endif
4214ba319b5SDimitry Andric 
4224ba319b5SDimitry Andric bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
4234ba319b5SDimitry Andric                     error_code& ec) {
4244ba319b5SDimitry Andric #if !defined(_LIBCPP_USE_UTIMENSAT)
4254ba319b5SDimitry Andric   return posix_utimes(p, TS, ec);
4264ba319b5SDimitry Andric #else
4274ba319b5SDimitry Andric   return posix_utimensat(p, TS, ec);
4284ba319b5SDimitry Andric #endif
4294ba319b5SDimitry Andric }
4304ba319b5SDimitry Andric 
4314ba319b5SDimitry Andric } // namespace
4324ba319b5SDimitry Andric } // end namespace detail
4334ba319b5SDimitry Andric 
4344ba319b5SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM
4354ba319b5SDimitry Andric 
4364ba319b5SDimitry Andric #endif // FILESYSTEM_COMMON_H
437