/Users/buildslave/jenkins/workspace/coverage/llvm-project/libcxx/src/filesystem/filesystem_common.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===----------------------------------------------------------------------===//// |
2 | | // |
3 | | // 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 |
6 | | // |
7 | | //===----------------------------------------------------------------------===//// |
8 | | |
9 | | #ifndef FILESYSTEM_COMMON_H |
10 | | #define FILESYSTEM_COMMON_H |
11 | | |
12 | | #include "__config" |
13 | | #include "filesystem" |
14 | | #include "array" |
15 | | #include "chrono" |
16 | | #include "climits" |
17 | | #include "cstdlib" |
18 | | #include "ctime" |
19 | | |
20 | | #if !defined(_LIBCPP_WIN32API) |
21 | | # include <unistd.h> |
22 | | # include <sys/stat.h> |
23 | | # include <sys/statvfs.h> |
24 | | # include <sys/time.h> // for ::utimes as used in __last_write_time |
25 | | # include <fcntl.h> /* values for fchmodat */ |
26 | | #endif |
27 | | |
28 | | #include "../include/apple_availability.h" |
29 | | |
30 | | #if !defined(__APPLE__) |
31 | | // We can use the presence of UTIME_OMIT to detect platforms that provide |
32 | | // utimensat. |
33 | | #if defined(UTIME_OMIT) |
34 | | #define _LIBCPP_USE_UTIMENSAT |
35 | | #endif |
36 | | #endif |
37 | | |
38 | | #if defined(__GNUC__) |
39 | | #pragma GCC diagnostic push |
40 | | #pragma GCC diagnostic ignored "-Wunused-function" |
41 | | #endif |
42 | | |
43 | | #if defined(_LIBCPP_WIN32API) |
44 | | #define PS(x) (L##x) |
45 | | #else |
46 | 0 | #define PS(x) (x) |
47 | | #endif |
48 | | |
49 | | _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM |
50 | | |
51 | | namespace detail { |
52 | | |
53 | | #if defined(_LIBCPP_WIN32API) |
54 | | // Non anonymous, to allow access from two translation units. |
55 | | errc __win_err_to_errc(int err); |
56 | | #endif |
57 | | |
58 | | namespace { |
59 | | |
60 | 0 | static string format_string_imp(const char* msg, ...) { |
61 | | // we might need a second shot at this, so pre-emptivly make a copy |
62 | 0 | struct GuardVAList { |
63 | 0 | va_list& target; |
64 | 0 | bool active = true; |
65 | 0 | GuardVAList(va_list& tgt) : target(tgt), active(true) {} Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::GuardVAList(__va_list_tag (&) [1]) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::GuardVAList(__va_list_tag (&) [1]) |
66 | 0 | void clear() { |
67 | 0 | if (active) |
68 | 0 | va_end(target); |
69 | 0 | active = false; |
70 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::clear() Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::clear() |
71 | 0 | ~GuardVAList() { |
72 | 0 | if (active) |
73 | 0 | va_end(target); |
74 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::~GuardVAList() Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...)::GuardVAList::~GuardVAList() |
75 | 0 | }; |
76 | 0 | va_list args; |
77 | 0 | va_start(args, msg); |
78 | 0 | GuardVAList args_guard(args); |
79 | |
|
80 | 0 | va_list args_cp; |
81 | 0 | va_copy(args_cp, args); |
82 | 0 | GuardVAList args_copy_guard(args_cp); |
83 | |
|
84 | 0 | std::string result; |
85 | |
|
86 | 0 | array<char, 256> local_buff; |
87 | 0 | size_t size_with_null = local_buff.size(); |
88 | 0 | auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp); |
89 | |
|
90 | 0 | args_copy_guard.clear(); |
91 | | |
92 | | // handle empty expansion |
93 | 0 | if (ret == 0) |
94 | 0 | return result; |
95 | 0 | if (static_cast<size_t>(ret) < size_with_null) { |
96 | 0 | result.assign(local_buff.data(), static_cast<size_t>(ret)); |
97 | 0 | return result; |
98 | 0 | } |
99 | | |
100 | | // we did not provide a long enough buffer on our first attempt. The |
101 | | // return value is the number of bytes (excluding the null byte) that are |
102 | | // needed for formatting. |
103 | 0 | size_with_null = static_cast<size_t>(ret) + 1; |
104 | 0 | result.__resize_default_init(size_with_null - 1); |
105 | 0 | ret = ::vsnprintf(&result[0], size_with_null, msg, args); |
106 | 0 | _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); |
107 | |
|
108 | 0 | return result; |
109 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_imp(char const*, ...) |
110 | | |
111 | 0 | const path::value_type* unwrap(path::string_type const& s) { return s.c_str(); } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::unwrap(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::unwrap(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) |
112 | 0 | const path::value_type* unwrap(path const& p) { return p.native().c_str(); } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::unwrap(std::__1::__fs::filesystem::path const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::unwrap(std::__1::__fs::filesystem::path const&) |
113 | | template <class Arg> |
114 | 0 | Arg const& unwrap(Arg const& a) { |
115 | 0 | static_assert(!is_class<Arg>::value, "cannot pass class here"); |
116 | 0 | return a; |
117 | 0 | } |
118 | | |
119 | | template <class... Args> |
120 | 0 | string format_string(const char* fmt, Args const&... args) { |
121 | 0 | return format_string_imp(fmt, unwrap(args)...); |
122 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<char const*>(char const*, char const* const&) Unexecuted instantiation: operations.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<char const*, char const*>(char const*, char const* const&, char const* const&) Unexecuted instantiation: operations.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<char const*, char const*, char const*>(char const*, char const* const&, char const* const&, char const* const&) Unexecuted instantiation: operations.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<>(char const*) Unexecuted instantiation: operations.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<std::__1::__fs::filesystem::path>(char const*, std::__1::__fs::filesystem::path const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string<std::__1::__fs::filesystem::path>(char const*, std::__1::__fs::filesystem::path const&) |
123 | | |
124 | 0 | error_code capture_errno() { |
125 | 0 | _LIBCPP_ASSERT(errno, "Expected errno to be non-zero"); |
126 | 0 | return error_code(errno, generic_category()); |
127 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::capture_errno() Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::capture_errno() |
128 | | |
129 | | #if defined(_LIBCPP_WIN32API) |
130 | | error_code make_windows_error(int err) { |
131 | | return make_error_code(__win_err_to_errc(err)); |
132 | | } |
133 | | #endif |
134 | | |
135 | | template <class T> |
136 | | T error_value(); |
137 | | template <> |
138 | 0 | _LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {} Unexecuted instantiation: operations.cpp:void std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<void>() Unexecuted instantiation: directory_iterator.cpp:void std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<void>() |
139 | | template <> |
140 | 0 | bool error_value<bool>() { |
141 | 0 | return false; |
142 | 0 | } Unexecuted instantiation: operations.cpp:bool std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<bool>() Unexecuted instantiation: directory_iterator.cpp:bool std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<bool>() |
143 | | #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ |
144 | | template <> |
145 | | size_t error_value<size_t>() { |
146 | | return size_t(-1); |
147 | | } |
148 | | #endif |
149 | | template <> |
150 | 0 | uintmax_t error_value<uintmax_t>() { |
151 | 0 | return uintmax_t(-1); |
152 | 0 | } Unexecuted instantiation: operations.cpp:unsigned long std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<unsigned long>() Unexecuted instantiation: directory_iterator.cpp:unsigned long std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<unsigned long>() |
153 | | template <> |
154 | 0 | _LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() { |
155 | 0 | return file_time_type::min(); |
156 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > >() Unexecuted instantiation: directory_iterator.cpp:std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > >() |
157 | | template <> |
158 | 0 | path error_value<path>() { |
159 | 0 | return {}; |
160 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::path std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<std::__1::__fs::filesystem::path>() Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::path std::__1::__fs::filesystem::detail::(anonymous namespace)::error_value<std::__1::__fs::filesystem::path>() |
161 | | |
162 | | template <class T> |
163 | | struct ErrorHandler { |
164 | | const char* func_name_; |
165 | | error_code* ec_ = nullptr; |
166 | | const path* p1_ = nullptr; |
167 | | const path* p2_ = nullptr; |
168 | | |
169 | | ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, |
170 | | const path* p2 = nullptr) |
171 | 0 | : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { |
172 | 0 | if (ec_) |
173 | 0 | ec_->clear(); |
174 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<unsigned long>::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > >::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::ErrorHandler(char const*, std::__1::error_code*, std::__1::__fs::filesystem::path const*, std::__1::__fs::filesystem::path const*) |
175 | | |
176 | 0 | T report(const error_code& ec) const { |
177 | 0 | if (ec_) { |
178 | 0 | *ec_ = ec; |
179 | 0 | return error_value<T>(); |
180 | 0 | } |
181 | 0 | string what = string("in ") + func_name_; |
182 | 0 | switch (bool(p1_) + bool(p2_)) { |
183 | 0 | case 0: |
184 | 0 | __throw_filesystem_error(what, ec); |
185 | 0 | case 1: |
186 | 0 | __throw_filesystem_error(what, *p1_, ec); |
187 | 0 | case 2: |
188 | 0 | __throw_filesystem_error(what, *p1_, *p2_, ec); |
189 | 0 | } |
190 | 0 | _LIBCPP_UNREACHABLE(); |
191 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report(std::__1::error_code const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report(std::__1::error_code const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::report(std::__1::error_code const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<unsigned long>::report(std::__1::error_code const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > >::report(std::__1::error_code const&) const Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report(std::__1::error_code const&) const |
192 | | |
193 | | template <class... Args> |
194 | 0 | T report(const error_code& ec, const char* msg, Args const&... args) const { |
195 | 0 | if (ec_) { |
196 | 0 | *ec_ = ec; |
197 | 0 | return error_value<T>(); |
198 | 0 | } |
199 | 0 | string what = |
200 | 0 | string("in ") + func_name_ + ": " + format_string(msg, args...); |
201 | 0 | switch (bool(p1_) + bool(p2_)) { |
202 | 0 | case 0: |
203 | 0 | __throw_filesystem_error(what, ec); |
204 | 0 | case 1: |
205 | 0 | __throw_filesystem_error(what, *p1_, ec); |
206 | 0 | case 2: |
207 | 0 | __throw_filesystem_error(what, *p1_, *p2_, ec); |
208 | 0 | } |
209 | 0 | _LIBCPP_UNREACHABLE(); |
210 | 0 | } Unexecuted instantiation: operations.cpp:void std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report<>(std::__1::error_code const&, char const*) const Unexecuted instantiation: operations.cpp:bool std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::report<>(std::__1::error_code const&, char const*) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::path std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report<>(std::__1::error_code const&, char const*) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::path std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report<std::__1::__fs::filesystem::path>(std::__1::error_code const&, char const*, std::__1::__fs::filesystem::path const&) const Unexecuted instantiation: directory_iterator.cpp:void std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report<std::__1::__fs::filesystem::path>(std::__1::error_code const&, char const*, std::__1::__fs::filesystem::path const&) const |
211 | | |
212 | 0 | T report(errc const& err) const { return report(make_error_code(err)); } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::chrono::time_point<std::__1::__fs::filesystem::_FilesystemClock, std::__1::chrono::duration<__int128, std::__1::ratio<1l, 1000000000l> > > >::report(std::__1::errc const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report(std::__1::errc const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::report(std::__1::errc const&) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report(std::__1::errc const&) const |
213 | | |
214 | | template <class... Args> |
215 | 0 | T report(errc const& err, const char* msg, Args const&... args) const { |
216 | 0 | return report(make_error_code(err), msg, args...); |
217 | 0 | } Unexecuted instantiation: operations.cpp:bool std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::report<>(std::__1::errc const&, char const*) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::path std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report<std::__1::__fs::filesystem::path>(std::__1::errc const&, char const*, std::__1::__fs::filesystem::path const&) const |
218 | | |
219 | | private: |
220 | | ErrorHandler(ErrorHandler const&) = delete; |
221 | | ErrorHandler& operator=(ErrorHandler const&) = delete; |
222 | | }; |
223 | | |
224 | | using chrono::duration; |
225 | | using chrono::duration_cast; |
226 | | |
227 | | using TimeSpec = struct timespec; |
228 | | using TimeVal = struct timeval; |
229 | | using StatT = struct stat; |
230 | | |
231 | | template <class FileTimeT, class TimeT, |
232 | | bool IsFloat = is_floating_point<typename FileTimeT::rep>::value> |
233 | | struct time_util_base { |
234 | | using rep = typename FileTimeT::rep; |
235 | | using fs_duration = typename FileTimeT::duration; |
236 | | using fs_seconds = duration<rep>; |
237 | | using fs_nanoseconds = duration<rep, nano>; |
238 | | using fs_microseconds = duration<rep, micro>; |
239 | | |
240 | | static constexpr rep max_seconds = |
241 | | duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); |
242 | | |
243 | | static constexpr rep max_nsec = |
244 | | duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - |
245 | | fs_seconds(max_seconds)) |
246 | | .count(); |
247 | | |
248 | | static constexpr rep min_seconds = |
249 | | duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); |
250 | | |
251 | | static constexpr rep min_nsec_timespec = |
252 | | duration_cast<fs_nanoseconds>( |
253 | | (FileTimeT::duration::min() - fs_seconds(min_seconds)) + |
254 | | fs_seconds(1)) |
255 | | .count(); |
256 | | |
257 | | private: |
258 | | #if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR) |
259 | 0 | static constexpr fs_duration get_min_nsecs() { |
260 | 0 | return duration_cast<fs_duration>( |
261 | 0 | fs_nanoseconds(min_nsec_timespec) - |
262 | 0 | duration_cast<fs_nanoseconds>(fs_seconds(1))); |
263 | 0 | } |
264 | | // Static assert that these values properly round trip. |
265 | | static_assert(fs_seconds(min_seconds) + get_min_nsecs() == |
266 | | FileTimeT::duration::min(), |
267 | | "value doesn't roundtrip"); |
268 | | |
269 | 0 | static constexpr bool check_range() { |
270 | 0 | // This kinda sucks, but it's what happens when we don't have __int128_t. |
271 | 0 | if (sizeof(TimeT) == sizeof(rep)) { |
272 | 0 | typedef duration<long long, ratio<3600 * 24 * 365> > Years; |
273 | 0 | return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) && |
274 | 0 | duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250); |
275 | 0 | } |
276 | 0 | return max_seconds >= numeric_limits<TimeT>::max() && |
277 | 0 | min_seconds <= numeric_limits<TimeT>::min(); |
278 | 0 | } |
279 | | static_assert(check_range(), "the representable range is unacceptable small"); |
280 | | #endif |
281 | | }; |
282 | | |
283 | | template <class FileTimeT, class TimeT> |
284 | | struct time_util_base<FileTimeT, TimeT, true> { |
285 | | using rep = typename FileTimeT::rep; |
286 | | using fs_duration = typename FileTimeT::duration; |
287 | | using fs_seconds = duration<rep>; |
288 | | using fs_nanoseconds = duration<rep, nano>; |
289 | | using fs_microseconds = duration<rep, micro>; |
290 | | |
291 | | static const rep max_seconds; |
292 | | static const rep max_nsec; |
293 | | static const rep min_seconds; |
294 | | static const rep min_nsec_timespec; |
295 | | }; |
296 | | |
297 | | template <class FileTimeT, class TimeT> |
298 | | const typename FileTimeT::rep |
299 | | time_util_base<FileTimeT, TimeT, true>::max_seconds = |
300 | | duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); |
301 | | |
302 | | template <class FileTimeT, class TimeT> |
303 | | const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec = |
304 | | duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - |
305 | | fs_seconds(max_seconds)) |
306 | | .count(); |
307 | | |
308 | | template <class FileTimeT, class TimeT> |
309 | | const typename FileTimeT::rep |
310 | | time_util_base<FileTimeT, TimeT, true>::min_seconds = |
311 | | duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); |
312 | | |
313 | | template <class FileTimeT, class TimeT> |
314 | | const typename FileTimeT::rep |
315 | | time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec = |
316 | | duration_cast<fs_nanoseconds>((FileTimeT::duration::min() - |
317 | | fs_seconds(min_seconds)) + |
318 | | fs_seconds(1)) |
319 | | .count(); |
320 | | |
321 | | template <class FileTimeT, class TimeT, class TimeSpecT> |
322 | | struct time_util : time_util_base<FileTimeT, TimeT> { |
323 | | using Base = time_util_base<FileTimeT, TimeT>; |
324 | | using Base::max_nsec; |
325 | | using Base::max_seconds; |
326 | | using Base::min_nsec_timespec; |
327 | | using Base::min_seconds; |
328 | | |
329 | | using typename Base::fs_duration; |
330 | | using typename Base::fs_microseconds; |
331 | | using typename Base::fs_nanoseconds; |
332 | | using typename Base::fs_seconds; |
333 | | |
334 | | public: |
335 | | template <class CType, class ChronoType> |
336 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out, |
337 | 0 | ChronoType time) { |
338 | 0 | using Lim = numeric_limits<CType>; |
339 | 0 | if (time > Lim::max() || time < Lim::min()) |
340 | 0 | return false; |
341 | 0 | *out = static_cast<CType>(time); |
342 | 0 | return true; |
343 | 0 | } |
344 | | |
345 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) { |
346 | 0 | if (tm.tv_sec >= 0) { |
347 | 0 | return tm.tv_sec < max_seconds || |
348 | 0 | (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); |
349 | 0 | } else if (tm.tv_sec == (min_seconds - 1)) { |
350 | 0 | return tm.tv_nsec >= min_nsec_timespec; |
351 | 0 | } else { |
352 | 0 | return tm.tv_sec >= min_seconds; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) { |
357 | 0 | auto secs = duration_cast<fs_seconds>(tm.time_since_epoch()); |
358 | 0 | auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs); |
359 | 0 | if (nsecs.count() < 0) { |
360 | 0 | secs = secs + fs_seconds(1); |
361 | 0 | nsecs = nsecs + fs_seconds(1); |
362 | 0 | } |
363 | 0 | using TLim = numeric_limits<TimeT>; |
364 | 0 | if (secs.count() >= 0) |
365 | 0 | return secs.count() <= TLim::max(); |
366 | 0 | return secs.count() >= TLim::min(); |
367 | 0 | } |
368 | | |
369 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT |
370 | 0 | convert_from_timespec(TimeSpecT tm) { |
371 | 0 | if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { |
372 | 0 | return FileTimeT(fs_seconds(tm.tv_sec) + |
373 | 0 | duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec))); |
374 | 0 | } else { // tm.tv_sec < 0 |
375 | 0 | auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) - |
376 | 0 | fs_nanoseconds(tm.tv_nsec)); |
377 | 0 | auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; |
378 | 0 | return FileTimeT(Dur); |
379 | 0 | } |
380 | 0 | } |
381 | | |
382 | | template <class SubSecT> |
383 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool |
384 | 0 | set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { |
385 | 0 | auto dur = tp.time_since_epoch(); |
386 | 0 | auto sec_dur = duration_cast<fs_seconds>(dur); |
387 | 0 | auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur); |
388 | | // The tv_nsec and tv_usec fields must not be negative so adjust accordingly |
389 | 0 | if (subsec_dur.count() < 0) { |
390 | 0 | if (sec_dur.count() > min_seconds) { |
391 | 0 | sec_dur = sec_dur - fs_seconds(1); |
392 | 0 | subsec_dur = subsec_dur + fs_seconds(1); |
393 | 0 | } else { |
394 | 0 | subsec_dur = fs_nanoseconds::zero(); |
395 | 0 | } |
396 | 0 | } |
397 | 0 | return checked_set(sec_out, sec_dur.count()) && |
398 | 0 | checked_set(subsec_out, subsec_dur.count()); |
399 | 0 | } |
400 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest, |
401 | 0 | FileTimeT tp) { |
402 | 0 | if (!is_representable(tp)) |
403 | 0 | return false; |
404 | 0 | return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); |
405 | 0 | } |
406 | | }; |
407 | | |
408 | | using fs_time = time_util<file_time_type, time_t, TimeSpec>; |
409 | | |
410 | | #if defined(__APPLE__) |
411 | 0 | inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::extract_mtime(stat const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::extract_mtime(stat const&) |
412 | 0 | inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::extract_atime(stat const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::extract_atime(stat const&) |
413 | | #elif defined(__MVS__) |
414 | | inline TimeSpec extract_mtime(StatT const& st) { |
415 | | TimeSpec TS = {st.st_mtime, 0}; |
416 | | return TS; |
417 | | } |
418 | | inline TimeSpec extract_atime(StatT const& st) { |
419 | | TimeSpec TS = {st.st_atime, 0}; |
420 | | return TS; |
421 | | } |
422 | | #else |
423 | | inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } |
424 | | inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } |
425 | | #endif |
426 | | |
427 | 0 | inline TimeVal make_timeval(TimeSpec const& ts) { |
428 | 0 | using namespace chrono; |
429 | 0 | auto Convert = [](long nsec) { |
430 | 0 | using int_type = decltype(std::declval<TimeVal>().tv_usec); |
431 | 0 | auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count(); |
432 | 0 | return static_cast<int_type>(dur); |
433 | 0 | }; |
434 | 0 | TimeVal TV = {}; |
435 | 0 | TV.tv_sec = ts.tv_sec; |
436 | 0 | TV.tv_usec = Convert(ts.tv_nsec); |
437 | 0 | return TV; |
438 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::make_timeval(timespec const&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::make_timeval(timespec const&) |
439 | | |
440 | | inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS, |
441 | 0 | error_code& ec) { |
442 | 0 | TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; |
443 | 0 | if (::utimes(p.c_str(), ConvertedTS) == -1) { |
444 | 0 | ec = capture_errno(); |
445 | 0 | return true; |
446 | 0 | } |
447 | 0 | return false; |
448 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_utimes(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_utimes(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) |
449 | | |
450 | | #if defined(_LIBCPP_USE_UTIMENSAT) |
451 | | bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS, |
452 | 0 | error_code& ec) { |
453 | 0 | if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) { |
454 | 0 | ec = capture_errno(); |
455 | 0 | return true; |
456 | 0 | } |
457 | 0 | return false; |
458 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_utimensat(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_utimensat(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) |
459 | | #endif |
460 | | |
461 | | bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS, |
462 | 0 | error_code& ec) { |
463 | | #if !defined(_LIBCPP_USE_UTIMENSAT) |
464 | | return posix_utimes(p, TS, ec); |
465 | | #else |
466 | 0 | return posix_utimensat(p, TS, ec); |
467 | 0 | #endif |
468 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::set_file_times(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::set_file_times(std::__1::__fs::filesystem::path const&, std::__1::array<timespec, 2ul> const&, std::__1::error_code&) |
469 | | |
470 | | } // namespace |
471 | | } // end namespace detail |
472 | | |
473 | | _LIBCPP_END_NAMESPACE_FILESYSTEM |
474 | | |
475 | | #endif // FILESYSTEM_COMMON_H |