]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libc++/src/experimental/filesystem/filesystem_time_helper.h
MFC r343918: Teach /etc/rc.d/growfs how to handle systems running ZFS.
[FreeBSD/FreeBSD.git] / contrib / libc++ / src / experimental / filesystem / filesystem_time_helper.h
1 //===----------------------------------------------------------------------===////
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_TIME_HELPER_H
11 #define FILESYSTEM_TIME_HELPER_H
12
13 #include "experimental/__config"
14 #include "chrono"
15 #include "cstdlib"
16 #include "climits"
17
18 #include <unistd.h>
19 #include <sys/stat.h>
20 #if !defined(UTIME_OMIT)
21 #include <sys/time.h> // for ::utimes as used in __last_write_time
22 #endif
23
24 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
25
26 namespace time_detail { namespace {
27
28 using namespace chrono;
29
30 template <class FileTimeT,
31           bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
32 struct fs_time_util_base {
33   static constexpr auto max_seconds =
34       duration_cast<seconds>(FileTimeT::duration::max()).count();
35
36   static constexpr auto max_nsec =
37       duration_cast<nanoseconds>(FileTimeT::duration::max() -
38                                  seconds(max_seconds))
39           .count();
40
41   static constexpr auto min_seconds =
42       duration_cast<seconds>(FileTimeT::duration::min()).count();
43
44   static constexpr auto min_nsec_timespec =
45       duration_cast<nanoseconds>(
46           (FileTimeT::duration::min() - seconds(min_seconds)) + seconds(1))
47           .count();
48
49   // Static assert that these values properly round trip.
50   static_assert((seconds(min_seconds) +
51                  duration_cast<microseconds>(nanoseconds(min_nsec_timespec))) -
52                         duration_cast<microseconds>(seconds(1)) ==
53                     FileTimeT::duration::min(),
54                 "");
55 };
56
57 template <class FileTimeT>
58 struct fs_time_util_base<FileTimeT, true> {
59   static const long long max_seconds;
60   static const long long max_nsec;
61   static const long long min_seconds;
62   static const long long min_nsec_timespec;
63 };
64
65 template <class FileTimeT>
66 const long long fs_time_util_base<FileTimeT, true>::max_seconds =
67     duration_cast<seconds>(FileTimeT::duration::max()).count();
68
69 template <class FileTimeT>
70 const long long fs_time_util_base<FileTimeT, true>::max_nsec =
71     duration_cast<nanoseconds>(FileTimeT::duration::max() -
72                                seconds(max_seconds))
73         .count();
74
75 template <class FileTimeT>
76 const long long fs_time_util_base<FileTimeT, true>::min_seconds =
77     duration_cast<seconds>(FileTimeT::duration::min()).count();
78
79 template <class FileTimeT>
80 const long long fs_time_util_base<FileTimeT, true>::min_nsec_timespec =
81     duration_cast<nanoseconds>((FileTimeT::duration::min() -
82                                 seconds(min_seconds)) +
83                                seconds(1))
84         .count();
85
86 template <class FileTimeT, class TimeT, class TimeSpecT>
87 struct fs_time_util : fs_time_util_base<FileTimeT> {
88   using Base = fs_time_util_base<FileTimeT>;
89   using Base::max_nsec;
90   using Base::max_seconds;
91   using Base::min_nsec_timespec;
92   using Base::min_seconds;
93
94 public:
95   template <class CType, class ChronoType>
96   static bool checked_set(CType* out, ChronoType time) {
97     using Lim = numeric_limits<CType>;
98     if (time > Lim::max() || time < Lim::min())
99       return false;
100     *out = static_cast<CType>(time);
101     return true;
102   }
103
104   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
105     if (tm.tv_sec >= 0) {
106       return (tm.tv_sec < max_seconds) ||
107              (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
108     } else if (tm.tv_sec == (min_seconds - 1)) {
109       return tm.tv_nsec >= min_nsec_timespec;
110     } else {
111       return (tm.tv_sec >= min_seconds);
112     }
113   }
114
115   static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
116     auto secs = duration_cast<seconds>(tm.time_since_epoch());
117     auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs);
118     if (nsecs.count() < 0) {
119       secs = secs + seconds(1);
120       nsecs = nsecs + seconds(1);
121     }
122     using TLim = numeric_limits<TimeT>;
123     if (secs.count() >= 0)
124       return secs.count() <= TLim::max();
125     return secs.count() >= TLim::min();
126   }
127
128   static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
129   convert_timespec(TimeSpecT tm) {
130     auto adj_msec = duration_cast<microseconds>(nanoseconds(tm.tv_nsec));
131     if (tm.tv_sec >= 0) {
132       auto Dur = seconds(tm.tv_sec) + microseconds(adj_msec);
133       return FileTimeT(Dur);
134     } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() ==
135                0) {
136       return FileTimeT(seconds(tm.tv_sec));
137     } else { // tm.tv_sec < 0
138       auto adj_subsec =
139           duration_cast<microseconds>(seconds(1) - nanoseconds(tm.tv_nsec));
140       auto Dur = seconds(tm.tv_sec + 1) - adj_subsec;
141       return FileTimeT(Dur);
142     }
143   }
144
145   template <class SubSecDurT, class SubSecT>
146   static bool set_times_checked(TimeT* sec_out, SubSecT* subsec_out,
147                                 FileTimeT tp) {
148     using namespace chrono;
149     auto dur = tp.time_since_epoch();
150     auto sec_dur = duration_cast<seconds>(dur);
151     auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur);
152     // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
153     if (subsec_dur.count() < 0) {
154       if (sec_dur.count() > min_seconds) {
155         sec_dur -= seconds(1);
156         subsec_dur += seconds(1);
157       } else {
158         subsec_dur = SubSecDurT::zero();
159       }
160     }
161     return checked_set(sec_out, sec_dur.count()) &&
162            checked_set(subsec_out, subsec_dur.count());
163   }
164 };
165
166 } // end namespace
167 } // end namespace time_detail
168
169 using time_detail::fs_time_util;
170
171 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
172
173 #endif // FILESYSTEM_TIME_HELPER_H