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