106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #ifndef FILESYSTEM_TIME_UTILS_H 1006c3fb27SDimitry Andric #define FILESYSTEM_TIME_UTILS_H 1106c3fb27SDimitry Andric 1206c3fb27SDimitry Andric #include <__config> 1306c3fb27SDimitry Andric #include <array> 1406c3fb27SDimitry Andric #include <chrono> 1506c3fb27SDimitry Andric #include <filesystem> 1606c3fb27SDimitry Andric #include <limits> 1706c3fb27SDimitry Andric #include <ratio> 1806c3fb27SDimitry Andric #include <system_error> 1906c3fb27SDimitry Andric #include <type_traits> 2006c3fb27SDimitry Andric #include <utility> 2106c3fb27SDimitry Andric 2206c3fb27SDimitry Andric #include "error.h" 2306c3fb27SDimitry Andric #include "format_string.h" 2406c3fb27SDimitry Andric 2506c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 2606c3fb27SDimitry Andric # define WIN32_LEAN_AND_MEAN 2706c3fb27SDimitry Andric # define NOMINMAX 2806c3fb27SDimitry Andric # include <windows.h> 2906c3fb27SDimitry Andric #else 3006c3fb27SDimitry Andric # include <fcntl.h> 3106c3fb27SDimitry Andric # include <sys/stat.h> 3206c3fb27SDimitry Andric # include <sys/time.h> // for ::utimes as used in __last_write_time 3306c3fb27SDimitry Andric #endif 3406c3fb27SDimitry Andric 3506c3fb27SDimitry Andric // We can use the presence of UTIME_OMIT to detect platforms that provide utimensat. 3606c3fb27SDimitry Andric #if defined(UTIME_OMIT) 3706c3fb27SDimitry Andric # define _LIBCPP_USE_UTIMENSAT 3806c3fb27SDimitry Andric #endif 3906c3fb27SDimitry Andric 4006c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 4106c3fb27SDimitry Andric 4206c3fb27SDimitry Andric namespace detail { 4306c3fb27SDimitry Andric 4406c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 4506c3fb27SDimitry Andric // Various C runtime versions (UCRT, or the legacy msvcrt.dll used by 4606c3fb27SDimitry Andric // some mingw toolchains) provide different stat function implementations, 4706c3fb27SDimitry Andric // with a number of limitations with respect to what we want from the 4806c3fb27SDimitry Andric // stat function. Instead provide our own which does exactly what we want, 4906c3fb27SDimitry Andric // along with our own stat structure and flag macros. 5006c3fb27SDimitry Andric 5106c3fb27SDimitry Andric struct TimeSpec { 5206c3fb27SDimitry Andric int64_t tv_sec; 5306c3fb27SDimitry Andric int64_t tv_nsec; 5406c3fb27SDimitry Andric }; 5506c3fb27SDimitry Andric struct StatT { 5606c3fb27SDimitry Andric unsigned st_mode; 5706c3fb27SDimitry Andric TimeSpec st_atim; 5806c3fb27SDimitry Andric TimeSpec st_mtim; 5906c3fb27SDimitry Andric uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber 6006c3fb27SDimitry Andric struct FileIdStruct { 6106c3fb27SDimitry Andric unsigned char id[16]; // FILE_ID_INFO::FileId 6206c3fb27SDimitry Andric bool operator==(const FileIdStruct &other) const { 6306c3fb27SDimitry Andric for (int i = 0; i < 16; i++) 6406c3fb27SDimitry Andric if (id[i] != other.id[i]) 6506c3fb27SDimitry Andric return false; 6606c3fb27SDimitry Andric return true; 6706c3fb27SDimitry Andric } 6806c3fb27SDimitry Andric } st_ino; 6906c3fb27SDimitry Andric uint32_t st_nlink; 7006c3fb27SDimitry Andric uintmax_t st_size; 7106c3fb27SDimitry Andric }; 7206c3fb27SDimitry Andric 7306c3fb27SDimitry Andric // There were 369 years and 89 leap days from the Windows epoch 7406c3fb27SDimitry Andric // (1601) to the Unix epoch (1970). 7506c3fb27SDimitry Andric #define FILE_TIME_OFFSET_SECS (uint64_t(369 * 365 + 89) * (24 * 60 * 60)) 7606c3fb27SDimitry Andric 7706c3fb27SDimitry Andric inline TimeSpec filetime_to_timespec(LARGE_INTEGER li) { 7806c3fb27SDimitry Andric TimeSpec ret; 7906c3fb27SDimitry Andric ret.tv_sec = li.QuadPart / 10000000 - FILE_TIME_OFFSET_SECS; 8006c3fb27SDimitry Andric ret.tv_nsec = (li.QuadPart % 10000000) * 100; 8106c3fb27SDimitry Andric return ret; 8206c3fb27SDimitry Andric } 8306c3fb27SDimitry Andric 8406c3fb27SDimitry Andric inline TimeSpec filetime_to_timespec(FILETIME ft) { 8506c3fb27SDimitry Andric LARGE_INTEGER li; 8606c3fb27SDimitry Andric li.LowPart = ft.dwLowDateTime; 8706c3fb27SDimitry Andric li.HighPart = ft.dwHighDateTime; 8806c3fb27SDimitry Andric return filetime_to_timespec(li); 8906c3fb27SDimitry Andric } 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric inline FILETIME timespec_to_filetime(TimeSpec ts) { 9206c3fb27SDimitry Andric LARGE_INTEGER li; 9306c3fb27SDimitry Andric li.QuadPart = 9406c3fb27SDimitry Andric ts.tv_nsec / 100 + (ts.tv_sec + FILE_TIME_OFFSET_SECS) * 10000000; 9506c3fb27SDimitry Andric FILETIME ft; 9606c3fb27SDimitry Andric ft.dwLowDateTime = li.LowPart; 9706c3fb27SDimitry Andric ft.dwHighDateTime = li.HighPart; 9806c3fb27SDimitry Andric return ft; 9906c3fb27SDimitry Andric } 10006c3fb27SDimitry Andric 10106c3fb27SDimitry Andric #else 10206c3fb27SDimitry Andric using TimeSpec = struct timespec; 10306c3fb27SDimitry Andric using TimeVal = struct timeval; 10406c3fb27SDimitry Andric using StatT = struct stat; 10506c3fb27SDimitry Andric 10606c3fb27SDimitry Andric inline TimeVal make_timeval(TimeSpec const& ts) { 10706c3fb27SDimitry Andric using namespace chrono; 10806c3fb27SDimitry Andric auto Convert = [](long nsec) { 10906c3fb27SDimitry Andric using int_type = decltype(std::declval<TimeVal>().tv_usec); 11006c3fb27SDimitry Andric auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count(); 11106c3fb27SDimitry Andric return static_cast<int_type>(dur); 11206c3fb27SDimitry Andric }; 11306c3fb27SDimitry Andric TimeVal TV = {}; 11406c3fb27SDimitry Andric TV.tv_sec = ts.tv_sec; 11506c3fb27SDimitry Andric TV.tv_usec = Convert(ts.tv_nsec); 11606c3fb27SDimitry Andric return TV; 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric #endif 11906c3fb27SDimitry Andric 12006c3fb27SDimitry Andric using chrono::duration; 12106c3fb27SDimitry Andric using chrono::duration_cast; 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric template <class FileTimeT, class TimeT, 12406c3fb27SDimitry Andric bool IsFloat = is_floating_point<typename FileTimeT::rep>::value> 12506c3fb27SDimitry Andric struct time_util_base { 12606c3fb27SDimitry Andric using rep = typename FileTimeT::rep; 12706c3fb27SDimitry Andric using fs_duration = typename FileTimeT::duration; 12806c3fb27SDimitry Andric using fs_seconds = duration<rep>; 12906c3fb27SDimitry Andric using fs_nanoseconds = duration<rep, nano>; 13006c3fb27SDimitry Andric using fs_microseconds = duration<rep, micro>; 13106c3fb27SDimitry Andric 13206c3fb27SDimitry Andric static constexpr rep max_seconds = 13306c3fb27SDimitry Andric duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); 13406c3fb27SDimitry Andric 13506c3fb27SDimitry Andric static constexpr rep max_nsec = 13606c3fb27SDimitry Andric duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - 13706c3fb27SDimitry Andric fs_seconds(max_seconds)) 13806c3fb27SDimitry Andric .count(); 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric static constexpr rep min_seconds = 14106c3fb27SDimitry Andric duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); 14206c3fb27SDimitry Andric 14306c3fb27SDimitry Andric static constexpr rep min_nsec_timespec = 14406c3fb27SDimitry Andric duration_cast<fs_nanoseconds>( 14506c3fb27SDimitry Andric (FileTimeT::duration::min() - fs_seconds(min_seconds)) + 14606c3fb27SDimitry Andric fs_seconds(1)) 14706c3fb27SDimitry Andric .count(); 14806c3fb27SDimitry Andric 14906c3fb27SDimitry Andric private: 150*5f757f3fSDimitry Andric static constexpr fs_duration get_min_nsecs() { 15106c3fb27SDimitry Andric return duration_cast<fs_duration>( 15206c3fb27SDimitry Andric fs_nanoseconds(min_nsec_timespec) - 15306c3fb27SDimitry Andric duration_cast<fs_nanoseconds>(fs_seconds(1))); 15406c3fb27SDimitry Andric } 15506c3fb27SDimitry Andric // Static assert that these values properly round trip. 15606c3fb27SDimitry Andric static_assert(fs_seconds(min_seconds) + get_min_nsecs() == 15706c3fb27SDimitry Andric FileTimeT::duration::min(), 15806c3fb27SDimitry Andric "value doesn't roundtrip"); 15906c3fb27SDimitry Andric 160*5f757f3fSDimitry Andric static constexpr bool check_range() { 16106c3fb27SDimitry Andric // This kinda sucks, but it's what happens when we don't have __int128_t. 16206c3fb27SDimitry Andric if (sizeof(TimeT) == sizeof(rep)) { 16306c3fb27SDimitry Andric typedef duration<long long, ratio<3600 * 24 * 365> > Years; 16406c3fb27SDimitry Andric return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) && 16506c3fb27SDimitry Andric duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250); 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric return max_seconds >= numeric_limits<TimeT>::max() && 16806c3fb27SDimitry Andric min_seconds <= numeric_limits<TimeT>::min(); 16906c3fb27SDimitry Andric } 17006c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 14 17106c3fb27SDimitry Andric static_assert(check_range(), "the representable range is unacceptable small"); 17206c3fb27SDimitry Andric #endif 17306c3fb27SDimitry Andric }; 17406c3fb27SDimitry Andric 17506c3fb27SDimitry Andric template <class FileTimeT, class TimeT> 17606c3fb27SDimitry Andric struct time_util_base<FileTimeT, TimeT, true> { 17706c3fb27SDimitry Andric using rep = typename FileTimeT::rep; 17806c3fb27SDimitry Andric using fs_duration = typename FileTimeT::duration; 17906c3fb27SDimitry Andric using fs_seconds = duration<rep>; 18006c3fb27SDimitry Andric using fs_nanoseconds = duration<rep, nano>; 18106c3fb27SDimitry Andric using fs_microseconds = duration<rep, micro>; 18206c3fb27SDimitry Andric 18306c3fb27SDimitry Andric static const rep max_seconds; 18406c3fb27SDimitry Andric static const rep max_nsec; 18506c3fb27SDimitry Andric static const rep min_seconds; 18606c3fb27SDimitry Andric static const rep min_nsec_timespec; 18706c3fb27SDimitry Andric }; 18806c3fb27SDimitry Andric 18906c3fb27SDimitry Andric template <class FileTimeT, class TimeT> 19006c3fb27SDimitry Andric const typename FileTimeT::rep 19106c3fb27SDimitry Andric time_util_base<FileTimeT, TimeT, true>::max_seconds = 19206c3fb27SDimitry Andric duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); 19306c3fb27SDimitry Andric 19406c3fb27SDimitry Andric template <class FileTimeT, class TimeT> 19506c3fb27SDimitry Andric const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec = 19606c3fb27SDimitry Andric duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - 19706c3fb27SDimitry Andric fs_seconds(max_seconds)) 19806c3fb27SDimitry Andric .count(); 19906c3fb27SDimitry Andric 20006c3fb27SDimitry Andric template <class FileTimeT, class TimeT> 20106c3fb27SDimitry Andric const typename FileTimeT::rep 20206c3fb27SDimitry Andric time_util_base<FileTimeT, TimeT, true>::min_seconds = 20306c3fb27SDimitry Andric duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric template <class FileTimeT, class TimeT> 20606c3fb27SDimitry Andric const typename FileTimeT::rep 20706c3fb27SDimitry Andric time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec = 20806c3fb27SDimitry Andric duration_cast<fs_nanoseconds>((FileTimeT::duration::min() - 20906c3fb27SDimitry Andric fs_seconds(min_seconds)) + 21006c3fb27SDimitry Andric fs_seconds(1)) 21106c3fb27SDimitry Andric .count(); 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric template <class FileTimeT, class TimeT, class TimeSpecT> 21406c3fb27SDimitry Andric struct time_util : time_util_base<FileTimeT, TimeT> { 21506c3fb27SDimitry Andric using Base = time_util_base<FileTimeT, TimeT>; 21606c3fb27SDimitry Andric using Base::max_nsec; 21706c3fb27SDimitry Andric using Base::max_seconds; 21806c3fb27SDimitry Andric using Base::min_nsec_timespec; 21906c3fb27SDimitry Andric using Base::min_seconds; 22006c3fb27SDimitry Andric 22106c3fb27SDimitry Andric using typename Base::fs_duration; 22206c3fb27SDimitry Andric using typename Base::fs_microseconds; 22306c3fb27SDimitry Andric using typename Base::fs_nanoseconds; 22406c3fb27SDimitry Andric using typename Base::fs_seconds; 22506c3fb27SDimitry Andric 22606c3fb27SDimitry Andric public: 22706c3fb27SDimitry Andric template <class CType, class ChronoType> 228*5f757f3fSDimitry Andric static constexpr bool checked_set(CType* out, 22906c3fb27SDimitry Andric ChronoType time) { 23006c3fb27SDimitry Andric using Lim = numeric_limits<CType>; 23106c3fb27SDimitry Andric if (time > Lim::max() || time < Lim::min()) 23206c3fb27SDimitry Andric return false; 23306c3fb27SDimitry Andric *out = static_cast<CType>(time); 23406c3fb27SDimitry Andric return true; 23506c3fb27SDimitry Andric } 23606c3fb27SDimitry Andric 237*5f757f3fSDimitry Andric static constexpr bool is_representable(TimeSpecT tm) { 23806c3fb27SDimitry Andric if (tm.tv_sec >= 0) { 23906c3fb27SDimitry Andric return tm.tv_sec < max_seconds || 24006c3fb27SDimitry Andric (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); 24106c3fb27SDimitry Andric } else if (tm.tv_sec == (min_seconds - 1)) { 24206c3fb27SDimitry Andric return tm.tv_nsec >= min_nsec_timespec; 24306c3fb27SDimitry Andric } else { 24406c3fb27SDimitry Andric return tm.tv_sec >= min_seconds; 24506c3fb27SDimitry Andric } 24606c3fb27SDimitry Andric } 24706c3fb27SDimitry Andric 248*5f757f3fSDimitry Andric static constexpr bool is_representable(FileTimeT tm) { 24906c3fb27SDimitry Andric auto secs = duration_cast<fs_seconds>(tm.time_since_epoch()); 25006c3fb27SDimitry Andric auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs); 25106c3fb27SDimitry Andric if (nsecs.count() < 0) { 25206c3fb27SDimitry Andric secs = secs + fs_seconds(1); 25306c3fb27SDimitry Andric nsecs = nsecs + fs_seconds(1); 25406c3fb27SDimitry Andric } 25506c3fb27SDimitry Andric using TLim = numeric_limits<TimeT>; 25606c3fb27SDimitry Andric if (secs.count() >= 0) 25706c3fb27SDimitry Andric return secs.count() <= TLim::max(); 25806c3fb27SDimitry Andric return secs.count() >= TLim::min(); 25906c3fb27SDimitry Andric } 26006c3fb27SDimitry Andric 261*5f757f3fSDimitry Andric static constexpr FileTimeT 26206c3fb27SDimitry Andric convert_from_timespec(TimeSpecT tm) { 26306c3fb27SDimitry Andric if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { 26406c3fb27SDimitry Andric return FileTimeT(fs_seconds(tm.tv_sec) + 26506c3fb27SDimitry Andric duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec))); 26606c3fb27SDimitry Andric } else { // tm.tv_sec < 0 26706c3fb27SDimitry Andric auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) - 26806c3fb27SDimitry Andric fs_nanoseconds(tm.tv_nsec)); 26906c3fb27SDimitry Andric auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; 27006c3fb27SDimitry Andric return FileTimeT(Dur); 27106c3fb27SDimitry Andric } 27206c3fb27SDimitry Andric } 27306c3fb27SDimitry Andric 27406c3fb27SDimitry Andric template <class SubSecT> 275*5f757f3fSDimitry Andric static constexpr bool 27606c3fb27SDimitry Andric set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { 27706c3fb27SDimitry Andric auto dur = tp.time_since_epoch(); 27806c3fb27SDimitry Andric auto sec_dur = duration_cast<fs_seconds>(dur); 27906c3fb27SDimitry Andric auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur); 28006c3fb27SDimitry Andric // The tv_nsec and tv_usec fields must not be negative so adjust accordingly 28106c3fb27SDimitry Andric if (subsec_dur.count() < 0) { 28206c3fb27SDimitry Andric if (sec_dur.count() > min_seconds) { 28306c3fb27SDimitry Andric sec_dur = sec_dur - fs_seconds(1); 28406c3fb27SDimitry Andric subsec_dur = subsec_dur + fs_seconds(1); 28506c3fb27SDimitry Andric } else { 28606c3fb27SDimitry Andric subsec_dur = fs_nanoseconds::zero(); 28706c3fb27SDimitry Andric } 28806c3fb27SDimitry Andric } 28906c3fb27SDimitry Andric return checked_set(sec_out, sec_dur.count()) && 29006c3fb27SDimitry Andric checked_set(subsec_out, subsec_dur.count()); 29106c3fb27SDimitry Andric } 292*5f757f3fSDimitry Andric static constexpr bool convert_to_timespec(TimeSpecT& dest, 29306c3fb27SDimitry Andric FileTimeT tp) { 29406c3fb27SDimitry Andric if (!is_representable(tp)) 29506c3fb27SDimitry Andric return false; 29606c3fb27SDimitry Andric return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); 29706c3fb27SDimitry Andric } 29806c3fb27SDimitry Andric }; 29906c3fb27SDimitry Andric 30006c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 30106c3fb27SDimitry Andric using fs_time = time_util<file_time_type, int64_t, TimeSpec>; 30206c3fb27SDimitry Andric #else 30306c3fb27SDimitry Andric using fs_time = time_util<file_time_type, time_t, TimeSpec>; 30406c3fb27SDimitry Andric #endif 30506c3fb27SDimitry Andric 30606c3fb27SDimitry Andric #if defined(__APPLE__) 30706c3fb27SDimitry Andric inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } 30806c3fb27SDimitry Andric inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } 30906c3fb27SDimitry Andric #elif defined(__MVS__) 31006c3fb27SDimitry Andric inline TimeSpec extract_mtime(StatT const& st) { 31106c3fb27SDimitry Andric TimeSpec TS = {st.st_mtime, 0}; 31206c3fb27SDimitry Andric return TS; 31306c3fb27SDimitry Andric } 31406c3fb27SDimitry Andric inline TimeSpec extract_atime(StatT const& st) { 31506c3fb27SDimitry Andric TimeSpec TS = {st.st_atime, 0}; 31606c3fb27SDimitry Andric return TS; 31706c3fb27SDimitry Andric } 31806c3fb27SDimitry Andric #elif defined(_AIX) 31906c3fb27SDimitry Andric inline TimeSpec extract_mtime(StatT const& st) { 32006c3fb27SDimitry Andric TimeSpec TS = {st.st_mtime, st.st_mtime_n}; 32106c3fb27SDimitry Andric return TS; 32206c3fb27SDimitry Andric } 32306c3fb27SDimitry Andric inline TimeSpec extract_atime(StatT const& st) { 32406c3fb27SDimitry Andric TimeSpec TS = {st.st_atime, st.st_atime_n}; 32506c3fb27SDimitry Andric return TS; 32606c3fb27SDimitry Andric } 32706c3fb27SDimitry Andric #else 32806c3fb27SDimitry Andric inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } 32906c3fb27SDimitry Andric inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } 33006c3fb27SDimitry Andric #endif 33106c3fb27SDimitry Andric 33206c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_FILESYSTEM 33306c3fb27SDimitry Andric 33406c3fb27SDimitry Andric #if !defined(_LIBCPP_WIN32API) 33506c3fb27SDimitry Andric inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS, 33606c3fb27SDimitry Andric error_code& ec) { 33706c3fb27SDimitry Andric TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; 33806c3fb27SDimitry Andric if (::utimes(p.c_str(), ConvertedTS) == -1) { 33906c3fb27SDimitry Andric ec = capture_errno(); 34006c3fb27SDimitry Andric return true; 34106c3fb27SDimitry Andric } 34206c3fb27SDimitry Andric return false; 34306c3fb27SDimitry Andric } 34406c3fb27SDimitry Andric 34506c3fb27SDimitry Andric #if defined(_LIBCPP_USE_UTIMENSAT) 34606c3fb27SDimitry Andric inline bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS, 34706c3fb27SDimitry Andric error_code& ec) { 34806c3fb27SDimitry Andric if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) { 34906c3fb27SDimitry Andric ec = capture_errno(); 35006c3fb27SDimitry Andric return true; 35106c3fb27SDimitry Andric } 35206c3fb27SDimitry Andric return false; 35306c3fb27SDimitry Andric } 35406c3fb27SDimitry Andric #endif 35506c3fb27SDimitry Andric 35606c3fb27SDimitry Andric inline bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS, 35706c3fb27SDimitry Andric error_code& ec) { 35806c3fb27SDimitry Andric #if !defined(_LIBCPP_USE_UTIMENSAT) 35906c3fb27SDimitry Andric return posix_utimes(p, TS, ec); 36006c3fb27SDimitry Andric #else 36106c3fb27SDimitry Andric return posix_utimensat(p, TS, ec); 36206c3fb27SDimitry Andric #endif 36306c3fb27SDimitry Andric } 36406c3fb27SDimitry Andric 36506c3fb27SDimitry Andric #endif // !_LIBCPP_WIN32API 36606c3fb27SDimitry Andric 36706c3fb27SDimitry Andric inline file_time_type __extract_last_write_time(const path& p, const StatT& st, 36806c3fb27SDimitry Andric error_code* ec) { 36906c3fb27SDimitry Andric using detail::fs_time; 37006c3fb27SDimitry Andric ErrorHandler<file_time_type> err("last_write_time", ec, &p); 37106c3fb27SDimitry Andric 37206c3fb27SDimitry Andric auto ts = detail::extract_mtime(st); 37306c3fb27SDimitry Andric if (!fs_time::is_representable(ts)) 37406c3fb27SDimitry Andric return err.report(errc::value_too_large); 37506c3fb27SDimitry Andric 37606c3fb27SDimitry Andric return fs_time::convert_from_timespec(ts); 37706c3fb27SDimitry Andric } 37806c3fb27SDimitry Andric 37906c3fb27SDimitry Andric #endif // !_LIBCPP_HAS_NO_FILESYSTEM 38006c3fb27SDimitry Andric 38106c3fb27SDimitry Andric } // end namespace detail 38206c3fb27SDimitry Andric 38306c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM 38406c3fb27SDimitry Andric 38506c3fb27SDimitry Andric #endif // FILESYSTEM_TIME_UTILS_H 386