1*c303c47eSjoerg //===----------------------------------------------------------------------===////
2*c303c47eSjoerg //
3*c303c47eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c303c47eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*c303c47eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c303c47eSjoerg //
7*c303c47eSjoerg //===----------------------------------------------------------------------===////
8*c303c47eSjoerg
9*c303c47eSjoerg #ifndef FILESYSTEM_COMMON_H
10*c303c47eSjoerg #define FILESYSTEM_COMMON_H
11*c303c47eSjoerg
12*c303c47eSjoerg #include "__config"
13*c303c47eSjoerg #include "filesystem"
14*c303c47eSjoerg #include "array"
15*c303c47eSjoerg #include "chrono"
16*c303c47eSjoerg #include "climits"
17*c303c47eSjoerg #include "cstdlib"
18*c303c47eSjoerg #include "ctime"
19*c303c47eSjoerg
20*c303c47eSjoerg #if !defined(_LIBCPP_WIN32API)
21*c303c47eSjoerg # include <unistd.h>
22*c303c47eSjoerg # include <sys/stat.h>
23*c303c47eSjoerg # include <sys/statvfs.h>
24*c303c47eSjoerg # include <sys/time.h> // for ::utimes as used in __last_write_time
25*c303c47eSjoerg # include <fcntl.h> /* values for fchmodat */
26*c303c47eSjoerg #endif
27*c303c47eSjoerg
28*c303c47eSjoerg #include "../include/apple_availability.h"
29*c303c47eSjoerg
30*c303c47eSjoerg #if !defined(__APPLE__)
31*c303c47eSjoerg // We can use the presence of UTIME_OMIT to detect platforms that provide
32*c303c47eSjoerg // utimensat.
33*c303c47eSjoerg #if defined(UTIME_OMIT)
34*c303c47eSjoerg #define _LIBCPP_USE_UTIMENSAT
35*c303c47eSjoerg #endif
36*c303c47eSjoerg #endif
37*c303c47eSjoerg
38*c303c47eSjoerg #if defined(__GNUC__) || defined(__clang__)
39*c303c47eSjoerg #pragma GCC diagnostic push
40*c303c47eSjoerg #pragma GCC diagnostic ignored "-Wunused-function"
41*c303c47eSjoerg #endif
42*c303c47eSjoerg
43*c303c47eSjoerg #if defined(_LIBCPP_WIN32API)
44*c303c47eSjoerg #define PS(x) (L##x)
45*c303c47eSjoerg #define PATH_CSTR_FMT "\"%ls\""
46*c303c47eSjoerg #else
47*c303c47eSjoerg #define PS(x) (x)
48*c303c47eSjoerg #define PATH_CSTR_FMT "\"%s\""
49*c303c47eSjoerg #endif
50*c303c47eSjoerg
51*c303c47eSjoerg _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
52*c303c47eSjoerg
53*c303c47eSjoerg namespace detail {
54*c303c47eSjoerg
55*c303c47eSjoerg #if defined(_LIBCPP_WIN32API)
56*c303c47eSjoerg // Non anonymous, to allow access from two translation units.
57*c303c47eSjoerg errc __win_err_to_errc(int err);
58*c303c47eSjoerg #endif
59*c303c47eSjoerg
60*c303c47eSjoerg namespace {
61*c303c47eSjoerg
62*c303c47eSjoerg static _LIBCPP_FORMAT_PRINTF(1, 0) string
format_string_impl(const char * msg,va_list ap)63*c303c47eSjoerg format_string_impl(const char* msg, va_list ap) {
64*c303c47eSjoerg array<char, 256> buf;
65*c303c47eSjoerg
66*c303c47eSjoerg va_list apcopy;
67*c303c47eSjoerg va_copy(apcopy, ap);
68*c303c47eSjoerg int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy);
69*c303c47eSjoerg va_end(apcopy);
70*c303c47eSjoerg
71*c303c47eSjoerg string result;
72*c303c47eSjoerg if (static_cast<size_t>(ret) < buf.size()) {
73*c303c47eSjoerg result.assign(buf.data(), static_cast<size_t>(ret));
74*c303c47eSjoerg } else {
75*c303c47eSjoerg // we did not provide a long enough buffer on our first attempt. The
76*c303c47eSjoerg // return value is the number of bytes (excluding the null byte) that are
77*c303c47eSjoerg // needed for formatting.
78*c303c47eSjoerg size_t size_with_null = static_cast<size_t>(ret) + 1;
79*c303c47eSjoerg result.__resize_default_init(size_with_null - 1);
80*c303c47eSjoerg ret = ::vsnprintf(&result[0], size_with_null, msg, ap);
81*c303c47eSjoerg _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
82*c303c47eSjoerg }
83*c303c47eSjoerg return result;
84*c303c47eSjoerg }
85*c303c47eSjoerg
86*c303c47eSjoerg static _LIBCPP_FORMAT_PRINTF(1, 2) string
format_string(const char * msg,...)87*c303c47eSjoerg format_string(const char* msg, ...) {
88*c303c47eSjoerg string ret;
89*c303c47eSjoerg va_list ap;
90*c303c47eSjoerg va_start(ap, msg);
91*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
92*c303c47eSjoerg try {
93*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
94*c303c47eSjoerg ret = format_string_impl(msg, ap);
95*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
96*c303c47eSjoerg } catch (...) {
97*c303c47eSjoerg va_end(ap);
98*c303c47eSjoerg throw;
99*c303c47eSjoerg }
100*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
101*c303c47eSjoerg va_end(ap);
102*c303c47eSjoerg return ret;
103*c303c47eSjoerg }
104*c303c47eSjoerg
capture_errno()105*c303c47eSjoerg error_code capture_errno() {
106*c303c47eSjoerg _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
107*c303c47eSjoerg return error_code(errno, generic_category());
108*c303c47eSjoerg }
109*c303c47eSjoerg
110*c303c47eSjoerg #if defined(_LIBCPP_WIN32API)
make_windows_error(int err)111*c303c47eSjoerg error_code make_windows_error(int err) {
112*c303c47eSjoerg return make_error_code(__win_err_to_errc(err));
113*c303c47eSjoerg }
114*c303c47eSjoerg #endif
115*c303c47eSjoerg
116*c303c47eSjoerg template <class T>
117*c303c47eSjoerg T error_value();
118*c303c47eSjoerg template <>
119*c303c47eSjoerg _LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
120*c303c47eSjoerg template <>
121*c303c47eSjoerg bool error_value<bool>() {
122*c303c47eSjoerg return false;
123*c303c47eSjoerg }
124*c303c47eSjoerg #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__
125*c303c47eSjoerg template <>
126*c303c47eSjoerg size_t error_value<size_t>() {
127*c303c47eSjoerg return size_t(-1);
128*c303c47eSjoerg }
129*c303c47eSjoerg #endif
130*c303c47eSjoerg template <>
131*c303c47eSjoerg uintmax_t error_value<uintmax_t>() {
132*c303c47eSjoerg return uintmax_t(-1);
133*c303c47eSjoerg }
134*c303c47eSjoerg template <>
135*c303c47eSjoerg _LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
136*c303c47eSjoerg return file_time_type::min();
137*c303c47eSjoerg }
138*c303c47eSjoerg template <>
139*c303c47eSjoerg path error_value<path>() {
140*c303c47eSjoerg return {};
141*c303c47eSjoerg }
142*c303c47eSjoerg
143*c303c47eSjoerg template <class T>
144*c303c47eSjoerg struct ErrorHandler {
145*c303c47eSjoerg const char* func_name_;
146*c303c47eSjoerg error_code* ec_ = nullptr;
147*c303c47eSjoerg const path* p1_ = nullptr;
148*c303c47eSjoerg const path* p2_ = nullptr;
149*c303c47eSjoerg
150*c303c47eSjoerg ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
151*c303c47eSjoerg const path* p2 = nullptr)
func_name_ErrorHandler152*c303c47eSjoerg : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
153*c303c47eSjoerg if (ec_)
154*c303c47eSjoerg ec_->clear();
155*c303c47eSjoerg }
156*c303c47eSjoerg
reportErrorHandler157*c303c47eSjoerg T report(const error_code& ec) const {
158*c303c47eSjoerg if (ec_) {
159*c303c47eSjoerg *ec_ = ec;
160*c303c47eSjoerg return error_value<T>();
161*c303c47eSjoerg }
162*c303c47eSjoerg string what = string("in ") + func_name_;
163*c303c47eSjoerg switch (bool(p1_) + bool(p2_)) {
164*c303c47eSjoerg case 0:
165*c303c47eSjoerg __throw_filesystem_error(what, ec);
166*c303c47eSjoerg case 1:
167*c303c47eSjoerg __throw_filesystem_error(what, *p1_, ec);
168*c303c47eSjoerg case 2:
169*c303c47eSjoerg __throw_filesystem_error(what, *p1_, *p2_, ec);
170*c303c47eSjoerg }
171*c303c47eSjoerg _LIBCPP_UNREACHABLE();
172*c303c47eSjoerg }
173*c303c47eSjoerg
174*c303c47eSjoerg _LIBCPP_FORMAT_PRINTF(3, 0)
report_implErrorHandler175*c303c47eSjoerg void report_impl(const error_code& ec, const char* msg, va_list ap) const {
176*c303c47eSjoerg if (ec_) {
177*c303c47eSjoerg *ec_ = ec;
178*c303c47eSjoerg return;
179*c303c47eSjoerg }
180*c303c47eSjoerg string what =
181*c303c47eSjoerg string("in ") + func_name_ + ": " + format_string_impl(msg, ap);
182*c303c47eSjoerg switch (bool(p1_) + bool(p2_)) {
183*c303c47eSjoerg case 0:
184*c303c47eSjoerg __throw_filesystem_error(what, ec);
185*c303c47eSjoerg case 1:
186*c303c47eSjoerg __throw_filesystem_error(what, *p1_, ec);
187*c303c47eSjoerg case 2:
188*c303c47eSjoerg __throw_filesystem_error(what, *p1_, *p2_, ec);
189*c303c47eSjoerg }
190*c303c47eSjoerg _LIBCPP_UNREACHABLE();
191*c303c47eSjoerg }
192*c303c47eSjoerg
193*c303c47eSjoerg _LIBCPP_FORMAT_PRINTF(3, 4)
reportErrorHandler194*c303c47eSjoerg T report(const error_code& ec, const char* msg, ...) const {
195*c303c47eSjoerg va_list ap;
196*c303c47eSjoerg va_start(ap, msg);
197*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
198*c303c47eSjoerg try {
199*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
200*c303c47eSjoerg report_impl(ec, msg, ap);
201*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
202*c303c47eSjoerg } catch (...) {
203*c303c47eSjoerg va_end(ap);
204*c303c47eSjoerg throw;
205*c303c47eSjoerg }
206*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
207*c303c47eSjoerg va_end(ap);
208*c303c47eSjoerg return error_value<T>();
209*c303c47eSjoerg }
210*c303c47eSjoerg
reportErrorHandler211*c303c47eSjoerg T report(errc const& err) const {
212*c303c47eSjoerg return report(make_error_code(err));
213*c303c47eSjoerg }
214*c303c47eSjoerg
215*c303c47eSjoerg _LIBCPP_FORMAT_PRINTF(3, 4)
reportErrorHandler216*c303c47eSjoerg T report(errc const& err, const char* msg, ...) const {
217*c303c47eSjoerg va_list ap;
218*c303c47eSjoerg va_start(ap, msg);
219*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
220*c303c47eSjoerg try {
221*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
222*c303c47eSjoerg report_impl(make_error_code(err), msg, ap);
223*c303c47eSjoerg #ifndef _LIBCPP_NO_EXCEPTIONS
224*c303c47eSjoerg } catch (...) {
225*c303c47eSjoerg va_end(ap);
226*c303c47eSjoerg throw;
227*c303c47eSjoerg }
228*c303c47eSjoerg #endif // _LIBCPP_NO_EXCEPTIONS
229*c303c47eSjoerg va_end(ap);
230*c303c47eSjoerg return error_value<T>();
231*c303c47eSjoerg }
232*c303c47eSjoerg
233*c303c47eSjoerg private:
234*c303c47eSjoerg ErrorHandler(ErrorHandler const&) = delete;
235*c303c47eSjoerg ErrorHandler& operator=(ErrorHandler const&) = delete;
236*c303c47eSjoerg };
237*c303c47eSjoerg
238*c303c47eSjoerg using chrono::duration;
239*c303c47eSjoerg using chrono::duration_cast;
240*c303c47eSjoerg
241*c303c47eSjoerg #if defined(_LIBCPP_WIN32API)
242*c303c47eSjoerg // Various C runtime versions (UCRT, or the legacy msvcrt.dll used by
243*c303c47eSjoerg // some mingw toolchains) provide different stat function implementations,
244*c303c47eSjoerg // with a number of limitations with respect to what we want from the
245*c303c47eSjoerg // stat function. Instead provide our own (in the anonymous detail namespace
246*c303c47eSjoerg // in posix_compat.h) which does exactly what we want, along with our own
247*c303c47eSjoerg // stat structure and flag macros.
248*c303c47eSjoerg
249*c303c47eSjoerg struct TimeSpec {
250*c303c47eSjoerg int64_t tv_sec;
251*c303c47eSjoerg int64_t tv_nsec;
252*c303c47eSjoerg };
253*c303c47eSjoerg struct StatT {
254*c303c47eSjoerg unsigned st_mode;
255*c303c47eSjoerg TimeSpec st_atim;
256*c303c47eSjoerg TimeSpec st_mtim;
257*c303c47eSjoerg uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber
258*c303c47eSjoerg struct FileIdStruct {
259*c303c47eSjoerg unsigned char id[16]; // FILE_ID_INFO::FileId
260*c303c47eSjoerg bool operator==(const FileIdStruct &other) const {
261*c303c47eSjoerg for (int i = 0; i < 16; i++)
262*c303c47eSjoerg if (id[i] != other.id[i])
263*c303c47eSjoerg return false;
264*c303c47eSjoerg return true;
265*c303c47eSjoerg }
266*c303c47eSjoerg } st_ino;
267*c303c47eSjoerg uint32_t st_nlink;
268*c303c47eSjoerg uintmax_t st_size;
269*c303c47eSjoerg };
270*c303c47eSjoerg
271*c303c47eSjoerg #else
272*c303c47eSjoerg using TimeSpec = struct timespec;
273*c303c47eSjoerg using TimeVal = struct timeval;
274*c303c47eSjoerg using StatT = struct stat;
275*c303c47eSjoerg #endif
276*c303c47eSjoerg
277*c303c47eSjoerg template <class FileTimeT, class TimeT,
278*c303c47eSjoerg bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
279*c303c47eSjoerg struct time_util_base {
280*c303c47eSjoerg using rep = typename FileTimeT::rep;
281*c303c47eSjoerg using fs_duration = typename FileTimeT::duration;
282*c303c47eSjoerg using fs_seconds = duration<rep>;
283*c303c47eSjoerg using fs_nanoseconds = duration<rep, nano>;
284*c303c47eSjoerg using fs_microseconds = duration<rep, micro>;
285*c303c47eSjoerg
286*c303c47eSjoerg static constexpr rep max_seconds =
287*c303c47eSjoerg duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
288*c303c47eSjoerg
289*c303c47eSjoerg static constexpr rep max_nsec =
290*c303c47eSjoerg duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
291*c303c47eSjoerg fs_seconds(max_seconds))
292*c303c47eSjoerg .count();
293*c303c47eSjoerg
294*c303c47eSjoerg static constexpr rep min_seconds =
295*c303c47eSjoerg duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
296*c303c47eSjoerg
297*c303c47eSjoerg static constexpr rep min_nsec_timespec =
298*c303c47eSjoerg duration_cast<fs_nanoseconds>(
299*c303c47eSjoerg (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
300*c303c47eSjoerg fs_seconds(1))
301*c303c47eSjoerg .count();
302*c303c47eSjoerg
303*c303c47eSjoerg private:
get_min_nsecstime_util_base304*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 fs_duration get_min_nsecs() {
305*c303c47eSjoerg return duration_cast<fs_duration>(
306*c303c47eSjoerg fs_nanoseconds(min_nsec_timespec) -
307*c303c47eSjoerg duration_cast<fs_nanoseconds>(fs_seconds(1)));
308*c303c47eSjoerg }
309*c303c47eSjoerg // Static assert that these values properly round trip.
310*c303c47eSjoerg static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
311*c303c47eSjoerg FileTimeT::duration::min(),
312*c303c47eSjoerg "value doesn't roundtrip");
313*c303c47eSjoerg
check_rangetime_util_base314*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool check_range() {
315*c303c47eSjoerg // This kinda sucks, but it's what happens when we don't have __int128_t.
316*c303c47eSjoerg if (sizeof(TimeT) == sizeof(rep)) {
317*c303c47eSjoerg typedef duration<long long, ratio<3600 * 24 * 365> > Years;
318*c303c47eSjoerg return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
319*c303c47eSjoerg duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
320*c303c47eSjoerg }
321*c303c47eSjoerg return max_seconds >= numeric_limits<TimeT>::max() &&
322*c303c47eSjoerg min_seconds <= numeric_limits<TimeT>::min();
323*c303c47eSjoerg }
324*c303c47eSjoerg static_assert(check_range(), "the representable range is unacceptable small");
325*c303c47eSjoerg };
326*c303c47eSjoerg
327*c303c47eSjoerg template <class FileTimeT, class TimeT>
328*c303c47eSjoerg struct time_util_base<FileTimeT, TimeT, true> {
329*c303c47eSjoerg using rep = typename FileTimeT::rep;
330*c303c47eSjoerg using fs_duration = typename FileTimeT::duration;
331*c303c47eSjoerg using fs_seconds = duration<rep>;
332*c303c47eSjoerg using fs_nanoseconds = duration<rep, nano>;
333*c303c47eSjoerg using fs_microseconds = duration<rep, micro>;
334*c303c47eSjoerg
335*c303c47eSjoerg static const rep max_seconds;
336*c303c47eSjoerg static const rep max_nsec;
337*c303c47eSjoerg static const rep min_seconds;
338*c303c47eSjoerg static const rep min_nsec_timespec;
339*c303c47eSjoerg };
340*c303c47eSjoerg
341*c303c47eSjoerg template <class FileTimeT, class TimeT>
342*c303c47eSjoerg const typename FileTimeT::rep
343*c303c47eSjoerg time_util_base<FileTimeT, TimeT, true>::max_seconds =
344*c303c47eSjoerg duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
345*c303c47eSjoerg
346*c303c47eSjoerg template <class FileTimeT, class TimeT>
347*c303c47eSjoerg const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
348*c303c47eSjoerg duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
349*c303c47eSjoerg fs_seconds(max_seconds))
350*c303c47eSjoerg .count();
351*c303c47eSjoerg
352*c303c47eSjoerg template <class FileTimeT, class TimeT>
353*c303c47eSjoerg const typename FileTimeT::rep
354*c303c47eSjoerg time_util_base<FileTimeT, TimeT, true>::min_seconds =
355*c303c47eSjoerg duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
356*c303c47eSjoerg
357*c303c47eSjoerg template <class FileTimeT, class TimeT>
358*c303c47eSjoerg const typename FileTimeT::rep
359*c303c47eSjoerg time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
360*c303c47eSjoerg duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
361*c303c47eSjoerg fs_seconds(min_seconds)) +
362*c303c47eSjoerg fs_seconds(1))
363*c303c47eSjoerg .count();
364*c303c47eSjoerg
365*c303c47eSjoerg template <class FileTimeT, class TimeT, class TimeSpecT>
366*c303c47eSjoerg struct time_util : time_util_base<FileTimeT, TimeT> {
367*c303c47eSjoerg using Base = time_util_base<FileTimeT, TimeT>;
368*c303c47eSjoerg using Base::max_nsec;
369*c303c47eSjoerg using Base::max_seconds;
370*c303c47eSjoerg using Base::min_nsec_timespec;
371*c303c47eSjoerg using Base::min_seconds;
372*c303c47eSjoerg
373*c303c47eSjoerg using typename Base::fs_duration;
374*c303c47eSjoerg using typename Base::fs_microseconds;
375*c303c47eSjoerg using typename Base::fs_nanoseconds;
376*c303c47eSjoerg using typename Base::fs_seconds;
377*c303c47eSjoerg
378*c303c47eSjoerg public:
379*c303c47eSjoerg template <class CType, class ChronoType>
380*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
381*c303c47eSjoerg ChronoType time) {
382*c303c47eSjoerg using Lim = numeric_limits<CType>;
383*c303c47eSjoerg if (time > Lim::max() || time < Lim::min())
384*c303c47eSjoerg return false;
385*c303c47eSjoerg *out = static_cast<CType>(time);
386*c303c47eSjoerg return true;
387*c303c47eSjoerg }
388*c303c47eSjoerg
389*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
390*c303c47eSjoerg if (tm.tv_sec >= 0) {
391*c303c47eSjoerg return tm.tv_sec < max_seconds ||
392*c303c47eSjoerg (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
393*c303c47eSjoerg } else if (tm.tv_sec == (min_seconds - 1)) {
394*c303c47eSjoerg return tm.tv_nsec >= min_nsec_timespec;
395*c303c47eSjoerg } else {
396*c303c47eSjoerg return tm.tv_sec >= min_seconds;
397*c303c47eSjoerg }
398*c303c47eSjoerg }
399*c303c47eSjoerg
400*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
401*c303c47eSjoerg auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
402*c303c47eSjoerg auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
403*c303c47eSjoerg if (nsecs.count() < 0) {
404*c303c47eSjoerg secs = secs + fs_seconds(1);
405*c303c47eSjoerg nsecs = nsecs + fs_seconds(1);
406*c303c47eSjoerg }
407*c303c47eSjoerg using TLim = numeric_limits<TimeT>;
408*c303c47eSjoerg if (secs.count() >= 0)
409*c303c47eSjoerg return secs.count() <= TLim::max();
410*c303c47eSjoerg return secs.count() >= TLim::min();
411*c303c47eSjoerg }
412*c303c47eSjoerg
413*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
414*c303c47eSjoerg convert_from_timespec(TimeSpecT tm) {
415*c303c47eSjoerg if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
416*c303c47eSjoerg return FileTimeT(fs_seconds(tm.tv_sec) +
417*c303c47eSjoerg duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
418*c303c47eSjoerg } else { // tm.tv_sec < 0
419*c303c47eSjoerg auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
420*c303c47eSjoerg fs_nanoseconds(tm.tv_nsec));
421*c303c47eSjoerg auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
422*c303c47eSjoerg return FileTimeT(Dur);
423*c303c47eSjoerg }
424*c303c47eSjoerg }
425*c303c47eSjoerg
426*c303c47eSjoerg template <class SubSecT>
427*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
428*c303c47eSjoerg set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
429*c303c47eSjoerg auto dur = tp.time_since_epoch();
430*c303c47eSjoerg auto sec_dur = duration_cast<fs_seconds>(dur);
431*c303c47eSjoerg auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
432*c303c47eSjoerg // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
433*c303c47eSjoerg if (subsec_dur.count() < 0) {
434*c303c47eSjoerg if (sec_dur.count() > min_seconds) {
435*c303c47eSjoerg sec_dur = sec_dur - fs_seconds(1);
436*c303c47eSjoerg subsec_dur = subsec_dur + fs_seconds(1);
437*c303c47eSjoerg } else {
438*c303c47eSjoerg subsec_dur = fs_nanoseconds::zero();
439*c303c47eSjoerg }
440*c303c47eSjoerg }
441*c303c47eSjoerg return checked_set(sec_out, sec_dur.count()) &&
442*c303c47eSjoerg checked_set(subsec_out, subsec_dur.count());
443*c303c47eSjoerg }
444*c303c47eSjoerg static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
445*c303c47eSjoerg FileTimeT tp) {
446*c303c47eSjoerg if (!is_representable(tp))
447*c303c47eSjoerg return false;
448*c303c47eSjoerg return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
449*c303c47eSjoerg }
450*c303c47eSjoerg };
451*c303c47eSjoerg
452*c303c47eSjoerg #if defined(_LIBCPP_WIN32API)
453*c303c47eSjoerg using fs_time = time_util<file_time_type, int64_t, TimeSpec>;
454*c303c47eSjoerg #else
455*c303c47eSjoerg using fs_time = time_util<file_time_type, time_t, TimeSpec>;
456*c303c47eSjoerg #endif
457*c303c47eSjoerg
458*c303c47eSjoerg #if defined(__APPLE__)
459*c303c47eSjoerg inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
460*c303c47eSjoerg inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
461*c303c47eSjoerg #elif defined(__MVS__)
462*c303c47eSjoerg inline TimeSpec extract_mtime(StatT const& st) {
463*c303c47eSjoerg TimeSpec TS = {st.st_mtime, 0};
464*c303c47eSjoerg return TS;
465*c303c47eSjoerg }
466*c303c47eSjoerg inline TimeSpec extract_atime(StatT const& st) {
467*c303c47eSjoerg TimeSpec TS = {st.st_atime, 0};
468*c303c47eSjoerg return TS;
469*c303c47eSjoerg }
470*c303c47eSjoerg #elif defined(_AIX)
471*c303c47eSjoerg inline TimeSpec extract_mtime(StatT const& st) {
472*c303c47eSjoerg TimeSpec TS = {st.st_mtime, st.st_mtime_n};
473*c303c47eSjoerg return TS;
474*c303c47eSjoerg }
475*c303c47eSjoerg inline TimeSpec extract_atime(StatT const& st) {
476*c303c47eSjoerg TimeSpec TS = {st.st_atime, st.st_atime_n};
477*c303c47eSjoerg return TS;
478*c303c47eSjoerg }
479*c303c47eSjoerg #else
480*c303c47eSjoerg inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
481*c303c47eSjoerg inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
482*c303c47eSjoerg #endif
483*c303c47eSjoerg
484*c303c47eSjoerg #if !defined(_LIBCPP_WIN32API)
485*c303c47eSjoerg inline TimeVal make_timeval(TimeSpec const& ts) {
486*c303c47eSjoerg using namespace chrono;
487*c303c47eSjoerg auto Convert = [](long nsec) {
488*c303c47eSjoerg using int_type = decltype(std::declval<TimeVal>().tv_usec);
489*c303c47eSjoerg auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
490*c303c47eSjoerg return static_cast<int_type>(dur);
491*c303c47eSjoerg };
492*c303c47eSjoerg TimeVal TV = {};
493*c303c47eSjoerg TV.tv_sec = ts.tv_sec;
494*c303c47eSjoerg TV.tv_usec = Convert(ts.tv_nsec);
495*c303c47eSjoerg return TV;
496*c303c47eSjoerg }
497*c303c47eSjoerg
498*c303c47eSjoerg inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
499*c303c47eSjoerg error_code& ec) {
500*c303c47eSjoerg TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])};
501*c303c47eSjoerg if (::utimes(p.c_str(), ConvertedTS) == -1) {
502*c303c47eSjoerg ec = capture_errno();
503*c303c47eSjoerg return true;
504*c303c47eSjoerg }
505*c303c47eSjoerg return false;
506*c303c47eSjoerg }
507*c303c47eSjoerg
508*c303c47eSjoerg #if defined(_LIBCPP_USE_UTIMENSAT)
509*c303c47eSjoerg bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
510*c303c47eSjoerg error_code& ec) {
511*c303c47eSjoerg if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
512*c303c47eSjoerg ec = capture_errno();
513*c303c47eSjoerg return true;
514*c303c47eSjoerg }
515*c303c47eSjoerg return false;
516*c303c47eSjoerg }
517*c303c47eSjoerg #endif
518*c303c47eSjoerg
519*c303c47eSjoerg bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
520*c303c47eSjoerg error_code& ec) {
521*c303c47eSjoerg #if !defined(_LIBCPP_USE_UTIMENSAT)
522*c303c47eSjoerg return posix_utimes(p, TS, ec);
523*c303c47eSjoerg #else
524*c303c47eSjoerg return posix_utimensat(p, TS, ec);
525*c303c47eSjoerg #endif
526*c303c47eSjoerg }
527*c303c47eSjoerg #endif /* !_LIBCPP_WIN32API */
528*c303c47eSjoerg
529*c303c47eSjoerg } // namespace
530*c303c47eSjoerg } // end namespace detail
531*c303c47eSjoerg
532*c303c47eSjoerg _LIBCPP_END_NAMESPACE_FILESYSTEM
533*c303c47eSjoerg
534*c303c47eSjoerg #endif // FILESYSTEM_COMMON_H
535