blob: dc55f93da70c6b944fd3118763121da050dfdc3a [file] [log] [blame]
Eric Fiselierc1699862018-07-20 01:22:32 +00001//===----------------------------------------------------------------------===////
2//
Chandler Carruth57b08b02019-01-19 10:56:40 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Eric Fiselierc1699862018-07-20 01:22:32 +00006//
7//===----------------------------------------------------------------------===////
8
9#ifndef FILESYSTEM_COMMON_H
10#define FILESYSTEM_COMMON_H
11
Eric Fiselier998a5c82018-07-27 03:07:09 +000012#include "__config"
13#include "filesystem"
Eric Fiselier9158bfd2018-07-23 02:00:52 +000014#include "array"
Eric Fiselierc1699862018-07-20 01:22:32 +000015#include "chrono"
Eric Fiselierc1699862018-07-20 01:22:32 +000016#include "climits"
Louis Dionnec479e0c2020-10-30 11:19:07 -040017#include "cstdlib"
18#include "ctime"
Eric Fiselierc1699862018-07-20 01:22:32 +000019
20#include <unistd.h>
21#include <sys/stat.h>
22#include <sys/statvfs.h>
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +000023#include <sys/time.h> // for ::utimes as used in __last_write_time
Eric Fiselier998a5c82018-07-27 03:07:09 +000024#include <fcntl.h> /* values for fchmodat */
Eric Fiselierc1699862018-07-20 01:22:32 +000025
Eric Fiselier998a5c82018-07-27 03:07:09 +000026#include "../include/apple_availability.h"
Eric Fiselierc55ac102018-07-25 20:51:49 +000027
28#if !defined(__APPLE__)
Eric Fiselierc1699862018-07-20 01:22:32 +000029// We can use the presence of UTIME_OMIT to detect platforms that provide
30// utimensat.
31#if defined(UTIME_OMIT)
Eric Fiselierc55ac102018-07-25 20:51:49 +000032#define _LIBCPP_USE_UTIMENSAT
Eric Fiselierc1699862018-07-20 01:22:32 +000033#endif
Eric Fiselierc55ac102018-07-25 20:51:49 +000034#endif
Eric Fiselierc1699862018-07-20 01:22:32 +000035
Eric Fiselierc1699862018-07-20 01:22:32 +000036#if defined(__GNUC__)
37#pragma GCC diagnostic push
38#pragma GCC diagnostic ignored "-Wunused-function"
39#endif
40
Eric Fiselier998a5c82018-07-27 03:07:09 +000041_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
Eric Fiselierc1699862018-07-20 01:22:32 +000042
43namespace detail {
44namespace {
45
Eric Fiselierc48dba42018-07-23 11:46:47 +000046static string format_string_imp(const char* msg, ...) {
Eric Fiselier9158bfd2018-07-23 02:00:52 +000047 // we might need a second shot at this, so pre-emptivly make a copy
48 struct GuardVAList {
49 va_list& target;
50 bool active = true;
Louis Dionnec479e0c2020-10-30 11:19:07 -040051 GuardVAList(va_list& tgt) : target(tgt), active(true) {}
Eric Fiselier9158bfd2018-07-23 02:00:52 +000052 void clear() {
53 if (active)
54 va_end(target);
55 active = false;
56 }
57 ~GuardVAList() {
58 if (active)
59 va_end(target);
60 }
61 };
62 va_list args;
63 va_start(args, msg);
Eric Fiseliere3081d52018-07-23 03:06:57 +000064 GuardVAList args_guard(args);
Eric Fiselier9158bfd2018-07-23 02:00:52 +000065
66 va_list args_cp;
67 va_copy(args_cp, args);
Eric Fiseliere3081d52018-07-23 03:06:57 +000068 GuardVAList args_copy_guard(args_cp);
Eric Fiselier9158bfd2018-07-23 02:00:52 +000069
Eric Fiselier01a87ef2018-11-26 20:15:38 +000070 std::string result;
71
Eric Fiselierc48dba42018-07-23 11:46:47 +000072 array<char, 256> local_buff;
Eric Fiselier01a87ef2018-11-26 20:15:38 +000073 size_t size_with_null = local_buff.size();
74 auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
Eric Fiselier9158bfd2018-07-23 02:00:52 +000075
76 args_copy_guard.clear();
77
78 // handle empty expansion
79 if (ret == 0)
Eric Fiselier01a87ef2018-11-26 20:15:38 +000080 return result;
81 if (static_cast<size_t>(ret) < size_with_null) {
82 result.assign(local_buff.data(), static_cast<size_t>(ret));
83 return result;
84 }
Eric Fiselier9158bfd2018-07-23 02:00:52 +000085
Eric Fiselier01a87ef2018-11-26 20:15:38 +000086 // we did not provide a long enough buffer on our first attempt. The
87 // return value is the number of bytes (excluding the null byte) that are
88 // needed for formatting.
89 size_with_null = static_cast<size_t>(ret) + 1;
90 result.__resize_default_init(size_with_null - 1);
91 ret = ::vsnprintf(&result[0], size_with_null, msg, args);
92 _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
93
94 return result;
Eric Fiselier9158bfd2018-07-23 02:00:52 +000095}
96
97const char* unwrap(string const& s) { return s.c_str(); }
98const char* unwrap(path const& p) { return p.native().c_str(); }
99template <class Arg>
100Arg const& unwrap(Arg const& a) {
101 static_assert(!is_class<Arg>::value, "cannot pass class here");
102 return a;
103}
104
105template <class... Args>
Eric Fiselierc48dba42018-07-23 11:46:47 +0000106string format_string(const char* fmt, Args const&... args) {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000107 return format_string_imp(fmt, unwrap(args)...);
108}
109
Eric Fiselierc48dba42018-07-23 11:46:47 +0000110error_code capture_errno() {
Eric Fiselierc1699862018-07-20 01:22:32 +0000111 _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
Eric Fiselierc48dba42018-07-23 11:46:47 +0000112 return error_code(errno, generic_category());
Eric Fiselierc1699862018-07-20 01:22:32 +0000113}
114
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000115template <class T>
116T error_value();
117template <>
Eric Fiseliere3081d52018-07-23 03:06:57 +0000118_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000119template <>
Eric Fiselierd77f3ef2018-07-25 21:01:45 +0000120bool error_value<bool>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000121 return false;
122}
123template <>
Eric Fiselierd77f3ef2018-07-25 21:01:45 +0000124uintmax_t error_value<uintmax_t>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000125 return uintmax_t(-1);
126}
127template <>
Eric Fiseliere3081d52018-07-23 03:06:57 +0000128_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000129 return file_time_type::min();
130}
131template <>
132path error_value<path>() {
133 return {};
Eric Fiselierc1699862018-07-20 01:22:32 +0000134}
135
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000136template <class T>
137struct ErrorHandler {
Louis Dionnec479e0c2020-10-30 11:19:07 -0400138 const char* func_name_;
139 error_code* ec_ = nullptr;
140 const path* p1_ = nullptr;
141 const path* p2_ = nullptr;
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000142
143 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
144 const path* p2 = nullptr)
Louis Dionnec479e0c2020-10-30 11:19:07 -0400145 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
146 if (ec_)
147 ec_->clear();
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000148 }
149
Louis Dionnec479e0c2020-10-30 11:19:07 -0400150 T report(const error_code& ec) const {
151 if (ec_) {
152 *ec_ = ec;
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000153 return error_value<T>();
154 }
Louis Dionnec479e0c2020-10-30 11:19:07 -0400155 string what = string("in ") + func_name_;
156 switch (bool(p1_) + bool(p2_)) {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000157 case 0:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400158 __throw_filesystem_error(what, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000159 case 1:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400160 __throw_filesystem_error(what, *p1_, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000161 case 2:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400162 __throw_filesystem_error(what, *p1_, *p2_, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000163 }
164 _LIBCPP_UNREACHABLE();
165 }
166
167 template <class... Args>
Louis Dionnec479e0c2020-10-30 11:19:07 -0400168 T report(const error_code& ec, const char* msg, Args const&... args) const {
169 if (ec_) {
170 *ec_ = ec;
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000171 return error_value<T>();
172 }
173 string what =
Louis Dionnec479e0c2020-10-30 11:19:07 -0400174 string("in ") + func_name_ + ": " + format_string(msg, args...);
175 switch (bool(p1_) + bool(p2_)) {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000176 case 0:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400177 __throw_filesystem_error(what, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000178 case 1:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400179 __throw_filesystem_error(what, *p1_, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000180 case 2:
Louis Dionnec479e0c2020-10-30 11:19:07 -0400181 __throw_filesystem_error(what, *p1_, *p2_, ec);
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000182 }
183 _LIBCPP_UNREACHABLE();
184 }
185
186 T report(errc const& err) const { return report(make_error_code(err)); }
187
188 template <class... Args>
189 T report(errc const& err, const char* msg, Args const&... args) const {
190 return report(make_error_code(err), msg, args...);
191 }
192
193private:
194 ErrorHandler(ErrorHandler const&) = delete;
195 ErrorHandler& operator=(ErrorHandler const&) = delete;
196};
Eric Fiselierc1699862018-07-20 01:22:32 +0000197
Eric Fiselierc55ac102018-07-25 20:51:49 +0000198using chrono::duration;
199using chrono::duration_cast;
Eric Fiselierc1699862018-07-20 01:22:32 +0000200
Louis Dionne81b6aa02020-10-30 14:55:37 -0400201using TimeSpec = timespec;
Louis Dionnec479e0c2020-10-30 11:19:07 -0400202using StatT = struct stat;
Eric Fiselierc1699862018-07-20 01:22:32 +0000203
Eric Fiselierc55ac102018-07-25 20:51:49 +0000204template <class FileTimeT, class TimeT,
Eric Fiselierc1699862018-07-20 01:22:32 +0000205 bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000206struct time_util_base {
207 using rep = typename FileTimeT::rep;
208 using fs_duration = typename FileTimeT::duration;
209 using fs_seconds = duration<rep>;
210 using fs_nanoseconds = duration<rep, nano>;
211 using fs_microseconds = duration<rep, micro>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000212
Eric Fiselierc55ac102018-07-25 20:51:49 +0000213 static constexpr rep max_seconds =
214 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
215
216 static constexpr rep max_nsec =
217 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
218 fs_seconds(max_seconds))
Eric Fiselierc1699862018-07-20 01:22:32 +0000219 .count();
220
Eric Fiselierc55ac102018-07-25 20:51:49 +0000221 static constexpr rep min_seconds =
222 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000223
Eric Fiselierc55ac102018-07-25 20:51:49 +0000224 static constexpr rep min_nsec_timespec =
225 duration_cast<fs_nanoseconds>(
226 (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
227 fs_seconds(1))
Eric Fiselierc1699862018-07-20 01:22:32 +0000228 .count();
229
Eric Fiselierc55ac102018-07-25 20:51:49 +0000230private:
Eric Fiselierb7e6c1d2018-07-25 22:07:36 +0000231#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
Eric Fiselierc55ac102018-07-25 20:51:49 +0000232 static constexpr fs_duration get_min_nsecs() {
233 return duration_cast<fs_duration>(
234 fs_nanoseconds(min_nsec_timespec) -
235 duration_cast<fs_nanoseconds>(fs_seconds(1)));
236 }
Eric Fiselierc1699862018-07-20 01:22:32 +0000237 // Static assert that these values properly round trip.
Eric Fiselierc55ac102018-07-25 20:51:49 +0000238 static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
Eric Fiselierc1699862018-07-20 01:22:32 +0000239 FileTimeT::duration::min(),
Eric Fiselierc55ac102018-07-25 20:51:49 +0000240 "value doesn't roundtrip");
241
242 static constexpr bool check_range() {
243 // This kinda sucks, but it's what happens when we don't have __int128_t.
244 if (sizeof(TimeT) == sizeof(rep)) {
245 typedef duration<long long, ratio<3600 * 24 * 365> > Years;
246 return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
247 duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
248 }
249 return max_seconds >= numeric_limits<TimeT>::max() &&
250 min_seconds <= numeric_limits<TimeT>::min();
251 }
252 static_assert(check_range(), "the representable range is unacceptable small");
253#endif
Eric Fiselierc1699862018-07-20 01:22:32 +0000254};
255
Eric Fiselierc55ac102018-07-25 20:51:49 +0000256template <class FileTimeT, class TimeT>
257struct time_util_base<FileTimeT, TimeT, true> {
258 using rep = typename FileTimeT::rep;
259 using fs_duration = typename FileTimeT::duration;
260 using fs_seconds = duration<rep>;
261 using fs_nanoseconds = duration<rep, nano>;
262 using fs_microseconds = duration<rep, micro>;
263
264 static const rep max_seconds;
265 static const rep max_nsec;
266 static const rep min_seconds;
267 static const rep min_nsec_timespec;
Eric Fiselierc1699862018-07-20 01:22:32 +0000268};
269
Eric Fiselierc55ac102018-07-25 20:51:49 +0000270template <class FileTimeT, class TimeT>
271const typename FileTimeT::rep
272 time_util_base<FileTimeT, TimeT, true>::max_seconds =
273 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000274
Eric Fiselierc55ac102018-07-25 20:51:49 +0000275template <class FileTimeT, class TimeT>
276const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
277 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
278 fs_seconds(max_seconds))
Eric Fiselierc1699862018-07-20 01:22:32 +0000279 .count();
280
Eric Fiselierc55ac102018-07-25 20:51:49 +0000281template <class FileTimeT, class TimeT>
282const typename FileTimeT::rep
283 time_util_base<FileTimeT, TimeT, true>::min_seconds =
284 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000285
Eric Fiselierc55ac102018-07-25 20:51:49 +0000286template <class FileTimeT, class TimeT>
287const typename FileTimeT::rep
288 time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
289 duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
290 fs_seconds(min_seconds)) +
291 fs_seconds(1))
292 .count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000293
294template <class FileTimeT, class TimeT, class TimeSpecT>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000295struct time_util : time_util_base<FileTimeT, TimeT> {
296 using Base = time_util_base<FileTimeT, TimeT>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000297 using Base::max_nsec;
298 using Base::max_seconds;
299 using Base::min_nsec_timespec;
300 using Base::min_seconds;
301
Eric Fiselierc55ac102018-07-25 20:51:49 +0000302 using typename Base::fs_duration;
303 using typename Base::fs_microseconds;
304 using typename Base::fs_nanoseconds;
305 using typename Base::fs_seconds;
306
Eric Fiselierc1699862018-07-20 01:22:32 +0000307public:
308 template <class CType, class ChronoType>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000309 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
310 ChronoType time) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000311 using Lim = numeric_limits<CType>;
312 if (time > Lim::max() || time < Lim::min())
313 return false;
314 *out = static_cast<CType>(time);
315 return true;
316 }
317
318 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
319 if (tm.tv_sec >= 0) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000320 return tm.tv_sec < max_seconds ||
Eric Fiselierc1699862018-07-20 01:22:32 +0000321 (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
322 } else if (tm.tv_sec == (min_seconds - 1)) {
323 return tm.tv_nsec >= min_nsec_timespec;
324 } else {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000325 return tm.tv_sec >= min_seconds;
Eric Fiselierc1699862018-07-20 01:22:32 +0000326 }
327 }
328
329 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000330 auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
331 auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
Eric Fiselierc1699862018-07-20 01:22:32 +0000332 if (nsecs.count() < 0) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000333 secs = secs + fs_seconds(1);
334 nsecs = nsecs + fs_seconds(1);
Eric Fiselierc1699862018-07-20 01:22:32 +0000335 }
336 using TLim = numeric_limits<TimeT>;
337 if (secs.count() >= 0)
338 return secs.count() <= TLim::max();
339 return secs.count() >= TLim::min();
340 }
341
342 static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
Eric Fiselierc55ac102018-07-25 20:51:49 +0000343 convert_from_timespec(TimeSpecT tm) {
344 if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
345 return FileTimeT(fs_seconds(tm.tv_sec) +
346 duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
Eric Fiselierc1699862018-07-20 01:22:32 +0000347 } else { // tm.tv_sec < 0
Eric Fiselierc55ac102018-07-25 20:51:49 +0000348 auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
349 fs_nanoseconds(tm.tv_nsec));
350 auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
Eric Fiselierc1699862018-07-20 01:22:32 +0000351 return FileTimeT(Dur);
352 }
353 }
354
Eric Fiselierc55ac102018-07-25 20:51:49 +0000355 template <class SubSecT>
356 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
357 set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000358 auto dur = tp.time_since_epoch();
Eric Fiselierc55ac102018-07-25 20:51:49 +0000359 auto sec_dur = duration_cast<fs_seconds>(dur);
360 auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
Eric Fiselierc1699862018-07-20 01:22:32 +0000361 // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
362 if (subsec_dur.count() < 0) {
363 if (sec_dur.count() > min_seconds) {
Eric Fiselierce344372018-07-25 21:53:43 +0000364 sec_dur = sec_dur - fs_seconds(1);
365 subsec_dur = subsec_dur + fs_seconds(1);
Eric Fiselierc1699862018-07-20 01:22:32 +0000366 } else {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000367 subsec_dur = fs_nanoseconds::zero();
Eric Fiselierc1699862018-07-20 01:22:32 +0000368 }
369 }
370 return checked_set(sec_out, sec_dur.count()) &&
371 checked_set(subsec_out, subsec_dur.count());
372 }
Eric Fiselierc55ac102018-07-25 20:51:49 +0000373 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
374 FileTimeT tp) {
375 if (!is_representable(tp))
376 return false;
377 return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
378 }
Eric Fiselierc1699862018-07-20 01:22:32 +0000379};
380
Eric Fiselierc55ac102018-07-25 20:51:49 +0000381using fs_time = time_util<file_time_type, time_t, TimeSpec>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000382
383#if defined(__APPLE__)
384TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
385TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
386#else
387TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
388TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
389#endif
390
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000391// allow the utimes implementation to compile even it we're not going
392// to use it.
393
394bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
Eric Fiselier998a5c82018-07-27 03:07:09 +0000395 error_code& ec) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000396 using namespace chrono;
Alex Lorenz70cf5c42018-07-25 23:59:54 +0000397 auto Convert = [](long nsec) {
Eric Fiselier998a5c82018-07-27 03:07:09 +0000398 using int_type = decltype(std::declval< ::timeval>().tv_usec);
Alex Lorenz70cf5c42018-07-25 23:59:54 +0000399 auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
400 return static_cast<int_type>(dur);
Eric Fiselierc55ac102018-07-25 20:51:49 +0000401 };
402 struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
403 {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000404 if (::utimes(p.c_str(), ConvertedTS) == -1) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000405 ec = capture_errno();
406 return true;
407 }
408 return false;
409}
410
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000411#if defined(_LIBCPP_USE_UTIMENSAT)
412bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
Eric Fiselier998a5c82018-07-27 03:07:09 +0000413 error_code& ec) {
414 if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000415 ec = capture_errno();
416 return true;
417 }
418 return false;
Eric Fiselierc1699862018-07-20 01:22:32 +0000419}
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000420#endif
421
422bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
423 error_code& ec) {
424#if !defined(_LIBCPP_USE_UTIMENSAT)
425 return posix_utimes(p, TS, ec);
426#else
427 return posix_utimensat(p, TS, ec);
428#endif
429}
430
Eric Fiselierc1699862018-07-20 01:22:32 +0000431} // namespace
432} // end namespace detail
433
Eric Fiselier998a5c82018-07-27 03:07:09 +0000434_LIBCPP_END_NAMESPACE_FILESYSTEM
Eric Fiselierc1699862018-07-20 01:22:32 +0000435
Eric Fiselierc1699862018-07-20 01:22:32 +0000436#endif // FILESYSTEM_COMMON_H