blob: ed92877c425c381f541cc08d4587c6dfe4a4997f [file] [log] [blame]
Eric Fiselierc1699862018-07-20 01:22:32 +00001//===----------------------------------------------------------------------===////
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===////
9
10#ifndef FILESYSTEM_COMMON_H
11#define FILESYSTEM_COMMON_H
12
Eric Fiselier998a5c82018-07-27 03:07:09 +000013#include "__config"
14#include "filesystem"
Eric Fiselier9158bfd2018-07-23 02:00:52 +000015#include "array"
Eric Fiselierc1699862018-07-20 01:22:32 +000016#include "chrono"
17#include "cstdlib"
18#include "climits"
19
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;
Eric Fiselier998a5c82018-07-27 03:07:09 +000051 GuardVAList(va_list& target) : target(target), 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 Fiselierc48dba42018-07-23 11:46:47 +000070 array<char, 256> local_buff;
71 size_t size = local_buff.size();
Eric Fiselier9158bfd2018-07-23 02:00:52 +000072 auto ret = ::vsnprintf(local_buff.data(), size, msg, args_cp);
73
74 args_copy_guard.clear();
75
76 // handle empty expansion
77 if (ret == 0)
Eric Fiselierc48dba42018-07-23 11:46:47 +000078 return string{};
79 if (static_cast<size_t>(ret) < size)
80 return string(local_buff.data());
Eric Fiselier9158bfd2018-07-23 02:00:52 +000081
82 // we did not provide a long enough buffer on our first attempt.
83 // add 1 to size to account for null-byte in size cast to prevent overflow
Eric Fiselierc48dba42018-07-23 11:46:47 +000084 size = static_cast<size_t>(ret) + 1;
85 auto buff_ptr = unique_ptr<char[]>(new char[size]);
Eric Fiselier9158bfd2018-07-23 02:00:52 +000086 ret = ::vsnprintf(buff_ptr.get(), size, msg, args);
Eric Fiselierc48dba42018-07-23 11:46:47 +000087 return string(buff_ptr.get());
Eric Fiselier9158bfd2018-07-23 02:00:52 +000088}
89
90const char* unwrap(string const& s) { return s.c_str(); }
91const char* unwrap(path const& p) { return p.native().c_str(); }
92template <class Arg>
93Arg const& unwrap(Arg const& a) {
94 static_assert(!is_class<Arg>::value, "cannot pass class here");
95 return a;
96}
97
98template <class... Args>
Eric Fiselierc48dba42018-07-23 11:46:47 +000099string format_string(const char* fmt, Args const&... args) {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000100 return format_string_imp(fmt, unwrap(args)...);
101}
102
Eric Fiselierc48dba42018-07-23 11:46:47 +0000103error_code capture_errno() {
Eric Fiselierc1699862018-07-20 01:22:32 +0000104 _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
Eric Fiselierc48dba42018-07-23 11:46:47 +0000105 return error_code(errno, generic_category());
Eric Fiselierc1699862018-07-20 01:22:32 +0000106}
107
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000108template <class T>
109T error_value();
110template <>
Eric Fiseliere3081d52018-07-23 03:06:57 +0000111_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000112template <>
Eric Fiselierd77f3ef2018-07-25 21:01:45 +0000113bool error_value<bool>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000114 return false;
115}
116template <>
Eric Fiselierd77f3ef2018-07-25 21:01:45 +0000117uintmax_t error_value<uintmax_t>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000118 return uintmax_t(-1);
119}
120template <>
Eric Fiseliere3081d52018-07-23 03:06:57 +0000121_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000122 return file_time_type::min();
123}
124template <>
125path error_value<path>() {
126 return {};
Eric Fiselierc1699862018-07-20 01:22:32 +0000127}
128
Eric Fiselier9158bfd2018-07-23 02:00:52 +0000129template <class T>
130struct ErrorHandler {
131 const char* func_name;
132 error_code* ec = nullptr;
133 const path* p1 = nullptr;
134 const path* p2 = nullptr;
135
136 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
137 const path* p2 = nullptr)
138 : func_name(fname), ec(ec), p1(p1), p2(p2) {
139 if (ec)
140 ec->clear();
141 }
142
143 T report(const error_code& m_ec) const {
144 if (ec) {
145 *ec = m_ec;
146 return error_value<T>();
147 }
148 string what = string("in ") + func_name;
149 switch (bool(p1) + bool(p2)) {
150 case 0:
151 __throw_filesystem_error(what, m_ec);
152 case 1:
153 __throw_filesystem_error(what, *p1, m_ec);
154 case 2:
155 __throw_filesystem_error(what, *p1, *p2, m_ec);
156 }
157 _LIBCPP_UNREACHABLE();
158 }
159
160 template <class... Args>
161 T report(const error_code& m_ec, const char* msg, Args const&... args) const {
162 if (ec) {
163 *ec = m_ec;
164 return error_value<T>();
165 }
166 string what =
167 string("in ") + func_name + ": " + format_string(msg, args...);
168 switch (bool(p1) + bool(p2)) {
169 case 0:
170 __throw_filesystem_error(what, m_ec);
171 case 1:
172 __throw_filesystem_error(what, *p1, m_ec);
173 case 2:
174 __throw_filesystem_error(what, *p1, *p2, m_ec);
175 }
176 _LIBCPP_UNREACHABLE();
177 }
178
179 T report(errc const& err) const { return report(make_error_code(err)); }
180
181 template <class... Args>
182 T report(errc const& err, const char* msg, Args const&... args) const {
183 return report(make_error_code(err), msg, args...);
184 }
185
186private:
187 ErrorHandler(ErrorHandler const&) = delete;
188 ErrorHandler& operator=(ErrorHandler const&) = delete;
189};
Eric Fiselierc1699862018-07-20 01:22:32 +0000190
Eric Fiselierc55ac102018-07-25 20:51:49 +0000191using chrono::duration;
192using chrono::duration_cast;
Eric Fiselierc1699862018-07-20 01:22:32 +0000193
Eric Fiselierc55ac102018-07-25 20:51:49 +0000194using TimeSpec = struct ::timespec;
195using StatT = struct ::stat;
Eric Fiselierc1699862018-07-20 01:22:32 +0000196
Eric Fiselierc55ac102018-07-25 20:51:49 +0000197template <class FileTimeT, class TimeT,
Eric Fiselierc1699862018-07-20 01:22:32 +0000198 bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000199struct time_util_base {
200 using rep = typename FileTimeT::rep;
201 using fs_duration = typename FileTimeT::duration;
202 using fs_seconds = duration<rep>;
203 using fs_nanoseconds = duration<rep, nano>;
204 using fs_microseconds = duration<rep, micro>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000205
Eric Fiselierc55ac102018-07-25 20:51:49 +0000206 static constexpr rep max_seconds =
207 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
208
209 static constexpr rep max_nsec =
210 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
211 fs_seconds(max_seconds))
Eric Fiselierc1699862018-07-20 01:22:32 +0000212 .count();
213
Eric Fiselierc55ac102018-07-25 20:51:49 +0000214 static constexpr rep min_seconds =
215 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000216
Eric Fiselierc55ac102018-07-25 20:51:49 +0000217 static constexpr rep min_nsec_timespec =
218 duration_cast<fs_nanoseconds>(
219 (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
220 fs_seconds(1))
Eric Fiselierc1699862018-07-20 01:22:32 +0000221 .count();
222
Eric Fiselierc55ac102018-07-25 20:51:49 +0000223private:
Eric Fiselierb7e6c1d2018-07-25 22:07:36 +0000224#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
Eric Fiselierc55ac102018-07-25 20:51:49 +0000225 static constexpr fs_duration get_min_nsecs() {
226 return duration_cast<fs_duration>(
227 fs_nanoseconds(min_nsec_timespec) -
228 duration_cast<fs_nanoseconds>(fs_seconds(1)));
229 }
Eric Fiselierc1699862018-07-20 01:22:32 +0000230 // Static assert that these values properly round trip.
Eric Fiselierc55ac102018-07-25 20:51:49 +0000231 static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
Eric Fiselierc1699862018-07-20 01:22:32 +0000232 FileTimeT::duration::min(),
Eric Fiselierc55ac102018-07-25 20:51:49 +0000233 "value doesn't roundtrip");
234
235 static constexpr bool check_range() {
236 // This kinda sucks, but it's what happens when we don't have __int128_t.
237 if (sizeof(TimeT) == sizeof(rep)) {
238 typedef duration<long long, ratio<3600 * 24 * 365> > Years;
239 return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
240 duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
241 }
242 return max_seconds >= numeric_limits<TimeT>::max() &&
243 min_seconds <= numeric_limits<TimeT>::min();
244 }
245 static_assert(check_range(), "the representable range is unacceptable small");
246#endif
Eric Fiselierc1699862018-07-20 01:22:32 +0000247};
248
Eric Fiselierc55ac102018-07-25 20:51:49 +0000249template <class FileTimeT, class TimeT>
250struct time_util_base<FileTimeT, TimeT, true> {
251 using rep = typename FileTimeT::rep;
252 using fs_duration = typename FileTimeT::duration;
253 using fs_seconds = duration<rep>;
254 using fs_nanoseconds = duration<rep, nano>;
255 using fs_microseconds = duration<rep, micro>;
256
257 static const rep max_seconds;
258 static const rep max_nsec;
259 static const rep min_seconds;
260 static const rep min_nsec_timespec;
Eric Fiselierc1699862018-07-20 01:22:32 +0000261};
262
Eric Fiselierc55ac102018-07-25 20:51:49 +0000263template <class FileTimeT, class TimeT>
264const typename FileTimeT::rep
265 time_util_base<FileTimeT, TimeT, true>::max_seconds =
266 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000267
Eric Fiselierc55ac102018-07-25 20:51:49 +0000268template <class FileTimeT, class TimeT>
269const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
270 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
271 fs_seconds(max_seconds))
Eric Fiselierc1699862018-07-20 01:22:32 +0000272 .count();
273
Eric Fiselierc55ac102018-07-25 20:51:49 +0000274template <class FileTimeT, class TimeT>
275const typename FileTimeT::rep
276 time_util_base<FileTimeT, TimeT, true>::min_seconds =
277 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000278
Eric Fiselierc55ac102018-07-25 20:51:49 +0000279template <class FileTimeT, class TimeT>
280const typename FileTimeT::rep
281 time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
282 duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
283 fs_seconds(min_seconds)) +
284 fs_seconds(1))
285 .count();
Eric Fiselierc1699862018-07-20 01:22:32 +0000286
287template <class FileTimeT, class TimeT, class TimeSpecT>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000288struct time_util : time_util_base<FileTimeT, TimeT> {
289 using Base = time_util_base<FileTimeT, TimeT>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000290 using Base::max_nsec;
291 using Base::max_seconds;
292 using Base::min_nsec_timespec;
293 using Base::min_seconds;
294
Eric Fiselierc55ac102018-07-25 20:51:49 +0000295 using typename Base::fs_duration;
296 using typename Base::fs_microseconds;
297 using typename Base::fs_nanoseconds;
298 using typename Base::fs_seconds;
299
Eric Fiselierc1699862018-07-20 01:22:32 +0000300public:
301 template <class CType, class ChronoType>
Eric Fiselierc55ac102018-07-25 20:51:49 +0000302 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
303 ChronoType time) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000304 using Lim = numeric_limits<CType>;
305 if (time > Lim::max() || time < Lim::min())
306 return false;
307 *out = static_cast<CType>(time);
308 return true;
309 }
310
311 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
312 if (tm.tv_sec >= 0) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000313 return tm.tv_sec < max_seconds ||
Eric Fiselierc1699862018-07-20 01:22:32 +0000314 (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
315 } else if (tm.tv_sec == (min_seconds - 1)) {
316 return tm.tv_nsec >= min_nsec_timespec;
317 } else {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000318 return tm.tv_sec >= min_seconds;
Eric Fiselierc1699862018-07-20 01:22:32 +0000319 }
320 }
321
322 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000323 auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
324 auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
Eric Fiselierc1699862018-07-20 01:22:32 +0000325 if (nsecs.count() < 0) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000326 secs = secs + fs_seconds(1);
327 nsecs = nsecs + fs_seconds(1);
Eric Fiselierc1699862018-07-20 01:22:32 +0000328 }
329 using TLim = numeric_limits<TimeT>;
330 if (secs.count() >= 0)
331 return secs.count() <= TLim::max();
332 return secs.count() >= TLim::min();
333 }
334
335 static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
Eric Fiselierc55ac102018-07-25 20:51:49 +0000336 convert_from_timespec(TimeSpecT tm) {
337 if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
338 return FileTimeT(fs_seconds(tm.tv_sec) +
339 duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
Eric Fiselierc1699862018-07-20 01:22:32 +0000340 } else { // tm.tv_sec < 0
Eric Fiselierc55ac102018-07-25 20:51:49 +0000341 auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
342 fs_nanoseconds(tm.tv_nsec));
343 auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
Eric Fiselierc1699862018-07-20 01:22:32 +0000344 return FileTimeT(Dur);
345 }
346 }
347
Eric Fiselierc55ac102018-07-25 20:51:49 +0000348 template <class SubSecT>
349 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
350 set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000351 auto dur = tp.time_since_epoch();
Eric Fiselierc55ac102018-07-25 20:51:49 +0000352 auto sec_dur = duration_cast<fs_seconds>(dur);
353 auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
Eric Fiselierc1699862018-07-20 01:22:32 +0000354 // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
355 if (subsec_dur.count() < 0) {
356 if (sec_dur.count() > min_seconds) {
Eric Fiselierce344372018-07-25 21:53:43 +0000357 sec_dur = sec_dur - fs_seconds(1);
358 subsec_dur = subsec_dur + fs_seconds(1);
Eric Fiselierc1699862018-07-20 01:22:32 +0000359 } else {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000360 subsec_dur = fs_nanoseconds::zero();
Eric Fiselierc1699862018-07-20 01:22:32 +0000361 }
362 }
363 return checked_set(sec_out, sec_dur.count()) &&
364 checked_set(subsec_out, subsec_dur.count());
365 }
Eric Fiselierc55ac102018-07-25 20:51:49 +0000366 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
367 FileTimeT tp) {
368 if (!is_representable(tp))
369 return false;
370 return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
371 }
Eric Fiselierc1699862018-07-20 01:22:32 +0000372};
373
Eric Fiselierc55ac102018-07-25 20:51:49 +0000374using fs_time = time_util<file_time_type, time_t, TimeSpec>;
Eric Fiselierc1699862018-07-20 01:22:32 +0000375
376#if defined(__APPLE__)
377TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
378TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
379#else
380TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
381TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
382#endif
383
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000384// allow the utimes implementation to compile even it we're not going
385// to use it.
386
387bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
Eric Fiselier998a5c82018-07-27 03:07:09 +0000388 error_code& ec) {
Eric Fiselierc55ac102018-07-25 20:51:49 +0000389 using namespace chrono;
Alex Lorenz70cf5c42018-07-25 23:59:54 +0000390 auto Convert = [](long nsec) {
Eric Fiselier998a5c82018-07-27 03:07:09 +0000391 using int_type = decltype(std::declval< ::timeval>().tv_usec);
Alex Lorenz70cf5c42018-07-25 23:59:54 +0000392 auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
393 return static_cast<int_type>(dur);
Eric Fiselierc55ac102018-07-25 20:51:49 +0000394 };
395 struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
396 {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000397 if (::utimes(p.c_str(), ConvertedTS) == -1) {
Eric Fiselierc1699862018-07-20 01:22:32 +0000398 ec = capture_errno();
399 return true;
400 }
401 return false;
402}
403
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000404#if defined(_LIBCPP_USE_UTIMENSAT)
405bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
Eric Fiselier998a5c82018-07-27 03:07:09 +0000406 error_code& ec) {
407 if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000408 ec = capture_errno();
409 return true;
410 }
411 return false;
Eric Fiselierc1699862018-07-20 01:22:32 +0000412}
Eric Fiseliera0a7c1f2018-07-26 03:57:26 +0000413#endif
414
415bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
416 error_code& ec) {
417#if !defined(_LIBCPP_USE_UTIMENSAT)
418 return posix_utimes(p, TS, ec);
419#else
420 return posix_utimensat(p, TS, ec);
421#endif
422}
423
Eric Fiselierc1699862018-07-20 01:22:32 +0000424} // namespace
425} // end namespace detail
426
Eric Fiselier998a5c82018-07-27 03:07:09 +0000427_LIBCPP_END_NAMESPACE_FILESYSTEM
Eric Fiselierc1699862018-07-20 01:22:32 +0000428
Eric Fiselierc1699862018-07-20 01:22:32 +0000429#endif // FILESYSTEM_COMMON_H