/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 <__assert> |
13 | | #include <__config> |
14 | | #include <array> |
15 | | #include <chrono> |
16 | | #include <climits> |
17 | | #include <cstdarg> |
18 | | #include <ctime> |
19 | | #include <filesystem> |
20 | | #include <ratio> |
21 | | #include <system_error> |
22 | | #include <utility> |
23 | | |
24 | | #if defined(_LIBCPP_WIN32API) |
25 | | # define WIN32_LEAN_AND_MEAN |
26 | | # define NOMINMAX |
27 | | # include <windows.h> |
28 | | #else |
29 | | # include <dirent.h> // for DIR & friends |
30 | | # include <fcntl.h> /* values for fchmodat */ |
31 | | # include <sys/stat.h> |
32 | | # include <sys/statvfs.h> |
33 | | # include <sys/time.h> // for ::utimes as used in __last_write_time |
34 | | # include <unistd.h> |
35 | | #endif // defined(_LIBCPP_WIN32API) |
36 | | |
37 | | #include "../include/apple_availability.h" |
38 | | |
39 | | #if !defined(__APPLE__) |
40 | | // We can use the presence of UTIME_OMIT to detect platforms that provide |
41 | | // utimensat. |
42 | | #if defined(UTIME_OMIT) |
43 | | #define _LIBCPP_USE_UTIMENSAT |
44 | | #endif |
45 | | #endif |
46 | | |
47 | | _LIBCPP_DIAGNOSTIC_PUSH |
48 | | _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") |
49 | | _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") |
50 | | |
51 | | #if defined(_LIBCPP_WIN32API) |
52 | | # define PATHSTR(x) (L##x) |
53 | | # define PATH_CSTR_FMT "\"%ls\"" |
54 | | #else |
55 | 0 | # define PATHSTR(x) (x) |
56 | 0 | # define PATH_CSTR_FMT "\"%s\"" |
57 | | #endif |
58 | | |
59 | | _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM |
60 | | |
61 | | namespace detail { |
62 | | |
63 | | #if defined(_LIBCPP_WIN32API) |
64 | | // Non anonymous, to allow access from two translation units. |
65 | | errc __win_err_to_errc(int err); |
66 | | #endif |
67 | | |
68 | | namespace { |
69 | | |
70 | | static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string |
71 | 0 | format_string_impl(const char* msg, va_list ap) { |
72 | 0 | array<char, 256> buf; |
73 | |
|
74 | 0 | va_list apcopy; |
75 | 0 | va_copy(apcopy, ap); |
76 | 0 | int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); |
77 | 0 | va_end(apcopy); |
78 | |
|
79 | 0 | string result; |
80 | 0 | if (static_cast<size_t>(ret) < buf.size()) { |
81 | 0 | result.assign(buf.data(), static_cast<size_t>(ret)); |
82 | 0 | } else { |
83 | | // we did not provide a long enough buffer on our first attempt. The |
84 | | // return value is the number of bytes (excluding the null byte) that are |
85 | | // needed for formatting. |
86 | 0 | size_t size_with_null = static_cast<size_t>(ret) + 1; |
87 | 0 | result.__resize_default_init(size_with_null - 1); |
88 | 0 | ret = ::vsnprintf(&result[0], size_with_null, msg, ap); |
89 | 0 | _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); |
90 | 0 | } |
91 | 0 | return result; |
92 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_impl(char const*, __va_list_tag*) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string_impl(char const*, __va_list_tag*) |
93 | | |
94 | | static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) string |
95 | 0 | format_string(const char* msg, ...) { |
96 | 0 | string ret; |
97 | 0 | va_list ap; |
98 | 0 | va_start(ap, msg); |
99 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
100 | 0 | try { |
101 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
102 | 0 | ret = format_string_impl(msg, ap); |
103 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
104 | 0 | } catch (...) { |
105 | 0 | va_end(ap); |
106 | 0 | throw; |
107 | 0 | } |
108 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
109 | 0 | va_end(ap); |
110 | 0 | return ret; |
111 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string(char const*, ...) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::format_string(char const*, ...) |
112 | | |
113 | 0 | error_code capture_errno() { |
114 | 0 | _LIBCPP_ASSERT(errno != 0, "Expected errno to be non-zero"); |
115 | 0 | return error_code(errno, generic_category()); |
116 | 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() |
117 | | |
118 | | #if defined(_LIBCPP_WIN32API) |
119 | | error_code make_windows_error(int err) { |
120 | | return make_error_code(__win_err_to_errc(err)); |
121 | | } |
122 | | #endif |
123 | | |
124 | | template <class T> |
125 | | T error_value(); |
126 | | template <> |
127 | 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>() |
128 | | template <> |
129 | 0 | bool error_value<bool>() { |
130 | 0 | return false; |
131 | 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>() |
132 | | #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ |
133 | | template <> |
134 | | size_t error_value<size_t>() { |
135 | | return size_t(-1); |
136 | | } |
137 | | #endif |
138 | | template <> |
139 | 0 | uintmax_t error_value<uintmax_t>() { |
140 | 0 | return uintmax_t(-1); |
141 | 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>() |
142 | | template <> |
143 | 0 | _LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() { |
144 | 0 | return file_time_type::min(); |
145 | 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> > > >() |
146 | | template <> |
147 | 0 | path error_value<path>() { |
148 | 0 | return {}; |
149 | 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>() |
150 | | |
151 | | template <class T> |
152 | | struct ErrorHandler { |
153 | | const char* func_name_; |
154 | | error_code* ec_ = nullptr; |
155 | | const path* p1_ = nullptr; |
156 | | const path* p2_ = nullptr; |
157 | | |
158 | | ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, |
159 | | const path* p2 = nullptr) |
160 | 0 | : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { |
161 | 0 | if (ec_) |
162 | 0 | ec_->clear(); |
163 | 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*) |
164 | | |
165 | 0 | T report(const error_code& ec) const { |
166 | 0 | if (ec_) { |
167 | 0 | *ec_ = ec; |
168 | 0 | return error_value<T>(); |
169 | 0 | } |
170 | 0 | string what = string("in ") + func_name_; |
171 | 0 | switch (bool(p1_) + bool(p2_)) { |
172 | 0 | case 0: |
173 | 0 | __throw_filesystem_error(what, ec); |
174 | 0 | case 1: |
175 | 0 | __throw_filesystem_error(what, *p1_, ec); |
176 | 0 | case 2: |
177 | 0 | __throw_filesystem_error(what, *p1_, *p2_, ec); |
178 | 0 | } |
179 | 0 | __libcpp_unreachable(); |
180 | 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 |
181 | | |
182 | | _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) |
183 | 0 | void report_impl(const error_code& ec, const char* msg, va_list ap) const { |
184 | 0 | if (ec_) { |
185 | 0 | *ec_ = ec; |
186 | 0 | return; |
187 | 0 | } |
188 | 0 | string what = |
189 | 0 | string("in ") + func_name_ + ": " + format_string_impl(msg, ap); |
190 | 0 | switch (bool(p1_) + bool(p2_)) { |
191 | 0 | case 0: |
192 | 0 | __throw_filesystem_error(what, ec); |
193 | 0 | case 1: |
194 | 0 | __throw_filesystem_error(what, *p1_, ec); |
195 | 0 | case 2: |
196 | 0 | __throw_filesystem_error(what, *p1_, *p2_, ec); |
197 | 0 | } |
198 | 0 | __libcpp_unreachable(); |
199 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report_impl(std::__1::error_code const&, char const*, __va_list_tag*) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<bool>::report_impl(std::__1::error_code const&, char const*, __va_list_tag*) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report_impl(std::__1::error_code const&, char const*, __va_list_tag*) const Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report_impl(std::__1::error_code const&, char const*, __va_list_tag*) const |
200 | | |
201 | | _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) |
202 | 0 | T report(const error_code& ec, const char* msg, ...) const { |
203 | 0 | va_list ap; |
204 | 0 | va_start(ap, msg); |
205 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
206 | 0 | try { |
207 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
208 | 0 | report_impl(ec, msg, ap); |
209 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
210 | 0 | } catch (...) { |
211 | 0 | va_end(ap); |
212 | 0 | throw; |
213 | 0 | } |
214 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
215 | 0 | va_end(ap); |
216 | 0 | return error_value<T>(); |
217 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report(std::__1::error_code const&, char const*, ...) const Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report(std::__1::error_code const&, char const*, ...) const Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::ErrorHandler<void>::report(std::__1::error_code const&, char const*, ...) const |
218 | | |
219 | 0 | T report(errc const& err) const { |
220 | 0 | return report(make_error_code(err)); |
221 | 0 | } 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 |
222 | | |
223 | | _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) |
224 | 0 | T report(errc const& err, const char* msg, ...) const { |
225 | 0 | va_list ap; |
226 | 0 | va_start(ap, msg); |
227 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
228 | 0 | try { |
229 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
230 | 0 | report_impl(make_error_code(err), msg, ap); |
231 | 0 | #ifndef _LIBCPP_NO_EXCEPTIONS |
232 | 0 | } catch (...) { |
233 | 0 | va_end(ap); |
234 | 0 | throw; |
235 | 0 | } |
236 | 0 | #endif // _LIBCPP_NO_EXCEPTIONS |
237 | 0 | va_end(ap); |
238 | 0 | return error_value<T>(); |
239 | 0 | } Unexecuted instantiation: operations.cpp: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::detail::(anonymous namespace)::ErrorHandler<std::__1::__fs::filesystem::path>::report(std::__1::errc const&, char const*, ...) const |
240 | | |
241 | | private: |
242 | | ErrorHandler(ErrorHandler const&) = delete; |
243 | | ErrorHandler& operator=(ErrorHandler const&) = delete; |
244 | | }; |
245 | | |
246 | | using chrono::duration; |
247 | | using chrono::duration_cast; |
248 | | |
249 | | #if defined(_LIBCPP_WIN32API) |
250 | | // Various C runtime versions (UCRT, or the legacy msvcrt.dll used by |
251 | | // some mingw toolchains) provide different stat function implementations, |
252 | | // with a number of limitations with respect to what we want from the |
253 | | // stat function. Instead provide our own (in the anonymous detail namespace |
254 | | // in posix_compat.h) which does exactly what we want, along with our own |
255 | | // stat structure and flag macros. |
256 | | |
257 | | struct TimeSpec { |
258 | | int64_t tv_sec; |
259 | | int64_t tv_nsec; |
260 | | }; |
261 | | struct StatT { |
262 | | unsigned st_mode; |
263 | | TimeSpec st_atim; |
264 | | TimeSpec st_mtim; |
265 | | uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber |
266 | | struct FileIdStruct { |
267 | | unsigned char id[16]; // FILE_ID_INFO::FileId |
268 | | bool operator==(const FileIdStruct &other) const { |
269 | | for (int i = 0; i < 16; i++) |
270 | | if (id[i] != other.id[i]) |
271 | | return false; |
272 | | return true; |
273 | | } |
274 | | } st_ino; |
275 | | uint32_t st_nlink; |
276 | | uintmax_t st_size; |
277 | | }; |
278 | | |
279 | | #else |
280 | | using TimeSpec = struct timespec; |
281 | | using TimeVal = struct timeval; |
282 | | using StatT = struct stat; |
283 | | #endif |
284 | | |
285 | | template <class FileTimeT, class TimeT, |
286 | | bool IsFloat = is_floating_point<typename FileTimeT::rep>::value> |
287 | | struct time_util_base { |
288 | | using rep = typename FileTimeT::rep; |
289 | | using fs_duration = typename FileTimeT::duration; |
290 | | using fs_seconds = duration<rep>; |
291 | | using fs_nanoseconds = duration<rep, nano>; |
292 | | using fs_microseconds = duration<rep, micro>; |
293 | | |
294 | | static constexpr rep max_seconds = |
295 | | duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); |
296 | | |
297 | | static constexpr rep max_nsec = |
298 | | duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - |
299 | | fs_seconds(max_seconds)) |
300 | | .count(); |
301 | | |
302 | | static constexpr rep min_seconds = |
303 | | duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); |
304 | | |
305 | | static constexpr rep min_nsec_timespec = |
306 | | duration_cast<fs_nanoseconds>( |
307 | | (FileTimeT::duration::min() - fs_seconds(min_seconds)) + |
308 | | fs_seconds(1)) |
309 | | .count(); |
310 | | |
311 | | private: |
312 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 fs_duration get_min_nsecs() { |
313 | 0 | return duration_cast<fs_duration>( |
314 | 0 | fs_nanoseconds(min_nsec_timespec) - |
315 | 0 | duration_cast<fs_nanoseconds>(fs_seconds(1))); |
316 | 0 | } |
317 | | // Static assert that these values properly round trip. |
318 | | static_assert(fs_seconds(min_seconds) + get_min_nsecs() == |
319 | | FileTimeT::duration::min(), |
320 | | "value doesn't roundtrip"); |
321 | | |
322 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool check_range() { |
323 | 0 | // This kinda sucks, but it's what happens when we don't have __int128_t. |
324 | 0 | if (sizeof(TimeT) == sizeof(rep)) { |
325 | 0 | typedef duration<long long, ratio<3600 * 24 * 365> > Years; |
326 | 0 | return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) && |
327 | 0 | duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250); |
328 | 0 | } |
329 | 0 | return max_seconds >= numeric_limits<TimeT>::max() && |
330 | 0 | min_seconds <= numeric_limits<TimeT>::min(); |
331 | 0 | } |
332 | | static_assert(check_range(), "the representable range is unacceptable small"); |
333 | | }; |
334 | | |
335 | | template <class FileTimeT, class TimeT> |
336 | | struct time_util_base<FileTimeT, TimeT, true> { |
337 | | using rep = typename FileTimeT::rep; |
338 | | using fs_duration = typename FileTimeT::duration; |
339 | | using fs_seconds = duration<rep>; |
340 | | using fs_nanoseconds = duration<rep, nano>; |
341 | | using fs_microseconds = duration<rep, micro>; |
342 | | |
343 | | static const rep max_seconds; |
344 | | static const rep max_nsec; |
345 | | static const rep min_seconds; |
346 | | static const rep min_nsec_timespec; |
347 | | }; |
348 | | |
349 | | template <class FileTimeT, class TimeT> |
350 | | const typename FileTimeT::rep |
351 | | time_util_base<FileTimeT, TimeT, true>::max_seconds = |
352 | | duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); |
353 | | |
354 | | template <class FileTimeT, class TimeT> |
355 | | const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec = |
356 | | duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - |
357 | | fs_seconds(max_seconds)) |
358 | | .count(); |
359 | | |
360 | | template <class FileTimeT, class TimeT> |
361 | | const typename FileTimeT::rep |
362 | | time_util_base<FileTimeT, TimeT, true>::min_seconds = |
363 | | duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); |
364 | | |
365 | | template <class FileTimeT, class TimeT> |
366 | | const typename FileTimeT::rep |
367 | | time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec = |
368 | | duration_cast<fs_nanoseconds>((FileTimeT::duration::min() - |
369 | | fs_seconds(min_seconds)) + |
370 | | fs_seconds(1)) |
371 | | .count(); |
372 | | |
373 | | template <class FileTimeT, class TimeT, class TimeSpecT> |
374 | | struct time_util : time_util_base<FileTimeT, TimeT> { |
375 | | using Base = time_util_base<FileTimeT, TimeT>; |
376 | | using Base::max_nsec; |
377 | | using Base::max_seconds; |
378 | | using Base::min_nsec_timespec; |
379 | | using Base::min_seconds; |
380 | | |
381 | | using typename Base::fs_duration; |
382 | | using typename Base::fs_microseconds; |
383 | | using typename Base::fs_nanoseconds; |
384 | | using typename Base::fs_seconds; |
385 | | |
386 | | public: |
387 | | template <class CType, class ChronoType> |
388 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out, |
389 | 0 | ChronoType time) { |
390 | 0 | using Lim = numeric_limits<CType>; |
391 | 0 | if (time > Lim::max() || time < Lim::min()) |
392 | 0 | return false; |
393 | 0 | *out = static_cast<CType>(time); |
394 | 0 | return true; |
395 | 0 | } |
396 | | |
397 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) { |
398 | 0 | if (tm.tv_sec >= 0) { |
399 | 0 | return tm.tv_sec < max_seconds || |
400 | 0 | (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); |
401 | 0 | } else if (tm.tv_sec == (min_seconds - 1)) { |
402 | 0 | return tm.tv_nsec >= min_nsec_timespec; |
403 | 0 | } else { |
404 | 0 | return tm.tv_sec >= min_seconds; |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | 0 | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) { |
409 | 0 | auto secs = duration_cast<fs_seconds>(tm.time_since_epoch()); |
410 | 0 | auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs); |
411 | 0 | if (nsecs.count() < 0) { |
412 | 0 | secs = secs + fs_seconds(1); |
413 | 0 | nsecs = nsecs + fs_seconds(1); |
414 | 0 | } |
415 | 0 | using TLim = numeric_limits<TimeT>; |
416 | 0 | if (secs.count() >= 0) |
417 | 0 | return secs.count() <= TLim::max(); |
418 | 0 | return secs.count() >= TLim::min(); |
419 | 0 | } |
420 | | |
421 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT |
422 | 0 | convert_from_timespec(TimeSpecT tm) { |
423 | 0 | if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { |
424 | 0 | return FileTimeT(fs_seconds(tm.tv_sec) + |
425 | 0 | duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec))); |
426 | 0 | } else { // tm.tv_sec < 0 |
427 | 0 | auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) - |
428 | 0 | fs_nanoseconds(tm.tv_nsec)); |
429 | 0 | auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; |
430 | 0 | return FileTimeT(Dur); |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | | template <class SubSecT> |
435 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool |
436 | 0 | set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { |
437 | 0 | auto dur = tp.time_since_epoch(); |
438 | 0 | auto sec_dur = duration_cast<fs_seconds>(dur); |
439 | 0 | auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur); |
440 | | // The tv_nsec and tv_usec fields must not be negative so adjust accordingly |
441 | 0 | if (subsec_dur.count() < 0) { |
442 | 0 | if (sec_dur.count() > min_seconds) { |
443 | 0 | sec_dur = sec_dur - fs_seconds(1); |
444 | 0 | subsec_dur = subsec_dur + fs_seconds(1); |
445 | 0 | } else { |
446 | 0 | subsec_dur = fs_nanoseconds::zero(); |
447 | 0 | } |
448 | 0 | } |
449 | 0 | return checked_set(sec_out, sec_dur.count()) && |
450 | 0 | checked_set(subsec_out, subsec_dur.count()); |
451 | 0 | } |
452 | | static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest, |
453 | 0 | FileTimeT tp) { |
454 | 0 | if (!is_representable(tp)) |
455 | 0 | return false; |
456 | 0 | return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); |
457 | 0 | } |
458 | | }; |
459 | | |
460 | | #if defined(_LIBCPP_WIN32API) |
461 | | using fs_time = time_util<file_time_type, int64_t, TimeSpec>; |
462 | | #else |
463 | | using fs_time = time_util<file_time_type, time_t, TimeSpec>; |
464 | | #endif |
465 | | |
466 | | #if defined(__APPLE__) |
467 | 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&) |
468 | 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&) |
469 | | #elif defined(__MVS__) |
470 | | inline TimeSpec extract_mtime(StatT const& st) { |
471 | | TimeSpec TS = {st.st_mtime, 0}; |
472 | | return TS; |
473 | | } |
474 | | inline TimeSpec extract_atime(StatT const& st) { |
475 | | TimeSpec TS = {st.st_atime, 0}; |
476 | | return TS; |
477 | | } |
478 | | #elif defined(_AIX) |
479 | | inline TimeSpec extract_mtime(StatT const& st) { |
480 | | TimeSpec TS = {st.st_mtime, st.st_mtime_n}; |
481 | | return TS; |
482 | | } |
483 | | inline TimeSpec extract_atime(StatT const& st) { |
484 | | TimeSpec TS = {st.st_atime, st.st_atime_n}; |
485 | | return TS; |
486 | | } |
487 | | #else |
488 | | inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } |
489 | | inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } |
490 | | #endif |
491 | | |
492 | | #if !defined(_LIBCPP_WIN32API) |
493 | 0 | inline TimeVal make_timeval(TimeSpec const& ts) { |
494 | 0 | using namespace chrono; |
495 | 0 | auto Convert = [](long nsec) { |
496 | 0 | using int_type = decltype(std::declval<TimeVal>().tv_usec); |
497 | 0 | auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count(); |
498 | 0 | return static_cast<int_type>(dur); |
499 | 0 | }; |
500 | 0 | TimeVal TV = {}; |
501 | 0 | TV.tv_sec = ts.tv_sec; |
502 | 0 | TV.tv_usec = Convert(ts.tv_nsec); |
503 | 0 | return TV; |
504 | 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&) |
505 | | |
506 | | inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS, |
507 | 0 | error_code& ec) { |
508 | 0 | TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; |
509 | 0 | if (::utimes(p.c_str(), ConvertedTS) == -1) { |
510 | 0 | ec = capture_errno(); |
511 | 0 | return true; |
512 | 0 | } |
513 | 0 | return false; |
514 | 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&) |
515 | | |
516 | | #if defined(_LIBCPP_USE_UTIMENSAT) |
517 | | bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS, |
518 | 0 | error_code& ec) { |
519 | 0 | if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) { |
520 | 0 | ec = capture_errno(); |
521 | 0 | return true; |
522 | 0 | } |
523 | 0 | return false; |
524 | 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&) |
525 | | #endif |
526 | | |
527 | | bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS, |
528 | 0 | error_code& ec) { |
529 | | #if !defined(_LIBCPP_USE_UTIMENSAT) |
530 | | return posix_utimes(p, TS, ec); |
531 | | #else |
532 | 0 | return posix_utimensat(p, TS, ec); |
533 | 0 | #endif |
534 | 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&) |
535 | | |
536 | | #if defined(DT_BLK) |
537 | | template <class DirEntT, class = decltype(DirEntT::d_type)> |
538 | 0 | static file_type get_file_type(DirEntT* ent, int) { |
539 | 0 | switch (ent->d_type) { |
540 | 0 | case DT_BLK: |
541 | 0 | return file_type::block; |
542 | 0 | case DT_CHR: |
543 | 0 | return file_type::character; |
544 | 0 | case DT_DIR: |
545 | 0 | return file_type::directory; |
546 | 0 | case DT_FIFO: |
547 | 0 | return file_type::fifo; |
548 | 0 | case DT_LNK: |
549 | 0 | return file_type::symlink; |
550 | 0 | case DT_REG: |
551 | 0 | return file_type::regular; |
552 | 0 | case DT_SOCK: |
553 | 0 | return file_type::socket; |
554 | | // Unlike in lstat, hitting "unknown" here simply means that the underlying |
555 | | // filesystem doesn't support d_type. Report is as 'none' so we correctly |
556 | | // set the cache to empty. |
557 | 0 | case DT_UNKNOWN: |
558 | 0 | break; |
559 | 0 | } |
560 | 0 | return file_type::none; |
561 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::file_type std::__1::__fs::filesystem::detail::(anonymous namespace)::get_file_type<dirent, unsigned char>(dirent*, int) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::file_type std::__1::__fs::filesystem::detail::(anonymous namespace)::get_file_type<dirent, unsigned char>(dirent*, int) |
562 | | #endif // defined(DT_BLK) |
563 | | |
564 | | template <class DirEntT> |
565 | | static file_type get_file_type(DirEntT*, long) { |
566 | | return file_type::none; |
567 | | } |
568 | | |
569 | | static pair<string_view, file_type> posix_readdir(DIR* dir_stream, |
570 | 0 | error_code& ec) { |
571 | 0 | struct dirent* dir_entry_ptr = nullptr; |
572 | 0 | errno = 0; // zero errno in order to detect errors |
573 | 0 | ec.clear(); |
574 | 0 | if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { |
575 | 0 | if (errno) |
576 | 0 | ec = capture_errno(); |
577 | 0 | return {}; |
578 | 0 | } else { |
579 | 0 | return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)}; |
580 | 0 | } |
581 | 0 | } Unexecuted instantiation: operations.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_readdir(DIR*, std::__1::error_code&) Unexecuted instantiation: directory_iterator.cpp:std::__1::__fs::filesystem::detail::(anonymous namespace)::posix_readdir(DIR*, std::__1::error_code&) |
582 | | |
583 | | #else // _LIBCPP_WIN32API |
584 | | |
585 | | static file_type get_file_type(const WIN32_FIND_DATAW& data) { |
586 | | if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && |
587 | | data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) |
588 | | return file_type::symlink; |
589 | | if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
590 | | return file_type::directory; |
591 | | return file_type::regular; |
592 | | } |
593 | | static uintmax_t get_file_size(const WIN32_FIND_DATAW& data) { |
594 | | return (static_cast<uint64_t>(data.nFileSizeHigh) << 32) + data.nFileSizeLow; |
595 | | } |
596 | | static file_time_type get_write_time(const WIN32_FIND_DATAW& data) { |
597 | | ULARGE_INTEGER tmp; |
598 | | const FILETIME& time = data.ftLastWriteTime; |
599 | | tmp.u.LowPart = time.dwLowDateTime; |
600 | | tmp.u.HighPart = time.dwHighDateTime; |
601 | | return file_time_type(file_time_type::duration(tmp.QuadPart)); |
602 | | } |
603 | | |
604 | | #endif // !_LIBCPP_WIN32API |
605 | | |
606 | | } // namespace |
607 | | } // end namespace detail |
608 | | |
609 | | _LIBCPP_END_NAMESPACE_FILESYSTEM |
610 | | |
611 | | _LIBCPP_DIAGNOSTIC_POP |
612 | | |
613 | | #endif // FILESYSTEM_COMMON_H |