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__) || defined(__clang__) 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 #define PATH_CSTR_FMT "\"%ls\"" 46 #else 47 #define PS(x) (x) 48 #define PATH_CSTR_FMT "\"%s\"" 49 #endif 50 51 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 52 53 namespace detail { 54 55 #if defined(_LIBCPP_WIN32API) 56 // Non anonymous, to allow access from two translation units. 57 errc __win_err_to_errc(int err); 58 #endif 59 60 namespace { 61 62 static _LIBCPP_FORMAT_PRINTF(1, 0) string 63 format_string_impl(const char* msg, va_list ap) { 64 array<char, 256> buf; 65 66 va_list apcopy; 67 va_copy(apcopy, ap); 68 int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); 69 va_end(apcopy); 70 71 string result; 72 if (static_cast<size_t>(ret) < buf.size()) { 73 result.assign(buf.data(), static_cast<size_t>(ret)); 74 } else { 75 // we did not provide a long enough buffer on our first attempt. The 76 // return value is the number of bytes (excluding the null byte) that are 77 // needed for formatting. 78 size_t size_with_null = static_cast<size_t>(ret) + 1; 79 result.__resize_default_init(size_with_null - 1); 80 ret = ::vsnprintf(&result[0], size_with_null, msg, ap); 81 _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); 82 } 83 return result; 84 } 85 86 static _LIBCPP_FORMAT_PRINTF(1, 2) string 87 format_string(const char* msg, ...) { 88 string ret; 89 va_list ap; 90 va_start(ap, msg); 91 #ifndef _LIBCPP_NO_EXCEPTIONS 92 try { 93 #endif // _LIBCPP_NO_EXCEPTIONS 94 ret = format_string_impl(msg, ap); 95 #ifndef _LIBCPP_NO_EXCEPTIONS 96 } catch (...) { 97 va_end(ap); 98 throw; 99 } 100 #endif // _LIBCPP_NO_EXCEPTIONS 101 va_end(ap); 102 return ret; 103 } 104 105 error_code capture_errno() { 106 _LIBCPP_ASSERT(errno, "Expected errno to be non-zero"); 107 return error_code(errno, generic_category()); 108 } 109 110 #if defined(_LIBCPP_WIN32API) 111 error_code make_windows_error(int err) { 112 return make_error_code(__win_err_to_errc(err)); 113 } 114 #endif 115 116 template <class T> 117 T error_value(); 118 template <> 119 _LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {} 120 template <> 121 bool error_value<bool>() { 122 return false; 123 } 124 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ 125 template <> 126 size_t error_value<size_t>() { 127 return size_t(-1); 128 } 129 #endif 130 template <> 131 uintmax_t error_value<uintmax_t>() { 132 return uintmax_t(-1); 133 } 134 template <> 135 _LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() { 136 return file_time_type::min(); 137 } 138 template <> 139 path error_value<path>() { 140 return {}; 141 } 142 143 template <class T> 144 struct ErrorHandler { 145 const char* func_name_; 146 error_code* ec_ = nullptr; 147 const path* p1_ = nullptr; 148 const path* p2_ = nullptr; 149 150 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, 151 const path* p2 = nullptr) 152 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { 153 if (ec_) 154 ec_->clear(); 155 } 156 157 T report(const error_code& ec) const { 158 if (ec_) { 159 *ec_ = ec; 160 return error_value<T>(); 161 } 162 string what = string("in ") + func_name_; 163 switch (bool(p1_) + bool(p2_)) { 164 case 0: 165 __throw_filesystem_error(what, ec); 166 case 1: 167 __throw_filesystem_error(what, *p1_, ec); 168 case 2: 169 __throw_filesystem_error(what, *p1_, *p2_, ec); 170 } 171 _LIBCPP_UNREACHABLE(); 172 } 173 174 _LIBCPP_FORMAT_PRINTF(3, 0) 175 void report_impl(const error_code& ec, const char* msg, va_list ap) const { 176 if (ec_) { 177 *ec_ = ec; 178 return; 179 } 180 string what = 181 string("in ") + func_name_ + ": " + format_string_impl(msg, ap); 182 switch (bool(p1_) + bool(p2_)) { 183 case 0: 184 __throw_filesystem_error(what, ec); 185 case 1: 186 __throw_filesystem_error(what, *p1_, ec); 187 case 2: 188 __throw_filesystem_error(what, *p1_, *p2_, ec); 189 } 190 _LIBCPP_UNREACHABLE(); 191 } 192 193 _LIBCPP_FORMAT_PRINTF(3, 4) 194 T report(const error_code& ec, const char* msg, ...) const { 195 va_list ap; 196 va_start(ap, msg); 197 #ifndef _LIBCPP_NO_EXCEPTIONS 198 try { 199 #endif // _LIBCPP_NO_EXCEPTIONS 200 report_impl(ec, msg, ap); 201 #ifndef _LIBCPP_NO_EXCEPTIONS 202 } catch (...) { 203 va_end(ap); 204 throw; 205 } 206 #endif // _LIBCPP_NO_EXCEPTIONS 207 va_end(ap); 208 return error_value<T>(); 209 } 210 211 T report(errc const& err) const { 212 return report(make_error_code(err)); 213 } 214 215 _LIBCPP_FORMAT_PRINTF(3, 4) 216 T report(errc const& err, const char* msg, ...) const { 217 va_list ap; 218 va_start(ap, msg); 219 #ifndef _LIBCPP_NO_EXCEPTIONS 220 try { 221 #endif // _LIBCPP_NO_EXCEPTIONS 222 report_impl(make_error_code(err), msg, ap); 223 #ifndef _LIBCPP_NO_EXCEPTIONS 224 } catch (...) { 225 va_end(ap); 226 throw; 227 } 228 #endif // _LIBCPP_NO_EXCEPTIONS 229 va_end(ap); 230 return error_value<T>(); 231 } 232 233 private: 234 ErrorHandler(ErrorHandler const&) = delete; 235 ErrorHandler& operator=(ErrorHandler const&) = delete; 236 }; 237 238 using chrono::duration; 239 using chrono::duration_cast; 240 241 #if defined(_LIBCPP_WIN32API) 242 // Various C runtime versions (UCRT, or the legacy msvcrt.dll used by 243 // some mingw toolchains) provide different stat function implementations, 244 // with a number of limitations with respect to what we want from the 245 // stat function. Instead provide our own (in the anonymous detail namespace 246 // in posix_compat.h) which does exactly what we want, along with our own 247 // stat structure and flag macros. 248 249 struct TimeSpec { 250 int64_t tv_sec; 251 int64_t tv_nsec; 252 }; 253 struct StatT { 254 unsigned st_mode; 255 TimeSpec st_atim; 256 TimeSpec st_mtim; 257 uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber 258 struct FileIdStruct { 259 unsigned char id[16]; // FILE_ID_INFO::FileId 260 bool operator==(const FileIdStruct &other) const { 261 for (int i = 0; i < 16; i++) 262 if (id[i] != other.id[i]) 263 return false; 264 return true; 265 } 266 } st_ino; 267 uint32_t st_nlink; 268 uintmax_t st_size; 269 }; 270 271 #else 272 using TimeSpec = struct timespec; 273 using TimeVal = struct timeval; 274 using StatT = struct stat; 275 #endif 276 277 template <class FileTimeT, class TimeT, 278 bool IsFloat = is_floating_point<typename FileTimeT::rep>::value> 279 struct time_util_base { 280 using rep = typename FileTimeT::rep; 281 using fs_duration = typename FileTimeT::duration; 282 using fs_seconds = duration<rep>; 283 using fs_nanoseconds = duration<rep, nano>; 284 using fs_microseconds = duration<rep, micro>; 285 286 static constexpr rep max_seconds = 287 duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); 288 289 static constexpr rep max_nsec = 290 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - 291 fs_seconds(max_seconds)) 292 .count(); 293 294 static constexpr rep min_seconds = 295 duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); 296 297 static constexpr rep min_nsec_timespec = 298 duration_cast<fs_nanoseconds>( 299 (FileTimeT::duration::min() - fs_seconds(min_seconds)) + 300 fs_seconds(1)) 301 .count(); 302 303 private: 304 static _LIBCPP_CONSTEXPR_AFTER_CXX11 fs_duration get_min_nsecs() { 305 return duration_cast<fs_duration>( 306 fs_nanoseconds(min_nsec_timespec) - 307 duration_cast<fs_nanoseconds>(fs_seconds(1))); 308 } 309 // Static assert that these values properly round trip. 310 static_assert(fs_seconds(min_seconds) + get_min_nsecs() == 311 FileTimeT::duration::min(), 312 "value doesn't roundtrip"); 313 314 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool check_range() { 315 // This kinda sucks, but it's what happens when we don't have __int128_t. 316 if (sizeof(TimeT) == sizeof(rep)) { 317 typedef duration<long long, ratio<3600 * 24 * 365> > Years; 318 return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) && 319 duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250); 320 } 321 return max_seconds >= numeric_limits<TimeT>::max() && 322 min_seconds <= numeric_limits<TimeT>::min(); 323 } 324 static_assert(check_range(), "the representable range is unacceptable small"); 325 }; 326 327 template <class FileTimeT, class TimeT> 328 struct time_util_base<FileTimeT, TimeT, true> { 329 using rep = typename FileTimeT::rep; 330 using fs_duration = typename FileTimeT::duration; 331 using fs_seconds = duration<rep>; 332 using fs_nanoseconds = duration<rep, nano>; 333 using fs_microseconds = duration<rep, micro>; 334 335 static const rep max_seconds; 336 static const rep max_nsec; 337 static const rep min_seconds; 338 static const rep min_nsec_timespec; 339 }; 340 341 template <class FileTimeT, class TimeT> 342 const typename FileTimeT::rep 343 time_util_base<FileTimeT, TimeT, true>::max_seconds = 344 duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); 345 346 template <class FileTimeT, class TimeT> 347 const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec = 348 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - 349 fs_seconds(max_seconds)) 350 .count(); 351 352 template <class FileTimeT, class TimeT> 353 const typename FileTimeT::rep 354 time_util_base<FileTimeT, TimeT, true>::min_seconds = 355 duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); 356 357 template <class FileTimeT, class TimeT> 358 const typename FileTimeT::rep 359 time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec = 360 duration_cast<fs_nanoseconds>((FileTimeT::duration::min() - 361 fs_seconds(min_seconds)) + 362 fs_seconds(1)) 363 .count(); 364 365 template <class FileTimeT, class TimeT, class TimeSpecT> 366 struct time_util : time_util_base<FileTimeT, TimeT> { 367 using Base = time_util_base<FileTimeT, TimeT>; 368 using Base::max_nsec; 369 using Base::max_seconds; 370 using Base::min_nsec_timespec; 371 using Base::min_seconds; 372 373 using typename Base::fs_duration; 374 using typename Base::fs_microseconds; 375 using typename Base::fs_nanoseconds; 376 using typename Base::fs_seconds; 377 378 public: 379 template <class CType, class ChronoType> 380 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out, 381 ChronoType time) { 382 using Lim = numeric_limits<CType>; 383 if (time > Lim::max() || time < Lim::min()) 384 return false; 385 *out = static_cast<CType>(time); 386 return true; 387 } 388 389 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) { 390 if (tm.tv_sec >= 0) { 391 return tm.tv_sec < max_seconds || 392 (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); 393 } else if (tm.tv_sec == (min_seconds - 1)) { 394 return tm.tv_nsec >= min_nsec_timespec; 395 } else { 396 return tm.tv_sec >= min_seconds; 397 } 398 } 399 400 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) { 401 auto secs = duration_cast<fs_seconds>(tm.time_since_epoch()); 402 auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs); 403 if (nsecs.count() < 0) { 404 secs = secs + fs_seconds(1); 405 nsecs = nsecs + fs_seconds(1); 406 } 407 using TLim = numeric_limits<TimeT>; 408 if (secs.count() >= 0) 409 return secs.count() <= TLim::max(); 410 return secs.count() >= TLim::min(); 411 } 412 413 static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT 414 convert_from_timespec(TimeSpecT tm) { 415 if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { 416 return FileTimeT(fs_seconds(tm.tv_sec) + 417 duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec))); 418 } else { // tm.tv_sec < 0 419 auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) - 420 fs_nanoseconds(tm.tv_nsec)); 421 auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; 422 return FileTimeT(Dur); 423 } 424 } 425 426 template <class SubSecT> 427 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool 428 set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { 429 auto dur = tp.time_since_epoch(); 430 auto sec_dur = duration_cast<fs_seconds>(dur); 431 auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur); 432 // The tv_nsec and tv_usec fields must not be negative so adjust accordingly 433 if (subsec_dur.count() < 0) { 434 if (sec_dur.count() > min_seconds) { 435 sec_dur = sec_dur - fs_seconds(1); 436 subsec_dur = subsec_dur + fs_seconds(1); 437 } else { 438 subsec_dur = fs_nanoseconds::zero(); 439 } 440 } 441 return checked_set(sec_out, sec_dur.count()) && 442 checked_set(subsec_out, subsec_dur.count()); 443 } 444 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest, 445 FileTimeT tp) { 446 if (!is_representable(tp)) 447 return false; 448 return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); 449 } 450 }; 451 452 #if defined(_LIBCPP_WIN32API) 453 using fs_time = time_util<file_time_type, int64_t, TimeSpec>; 454 #else 455 using fs_time = time_util<file_time_type, time_t, TimeSpec>; 456 #endif 457 458 #if defined(__APPLE__) 459 inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } 460 inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } 461 #elif defined(__MVS__) 462 inline TimeSpec extract_mtime(StatT const& st) { 463 TimeSpec TS = {st.st_mtime, 0}; 464 return TS; 465 } 466 inline TimeSpec extract_atime(StatT const& st) { 467 TimeSpec TS = {st.st_atime, 0}; 468 return TS; 469 } 470 #elif defined(_AIX) 471 inline TimeSpec extract_mtime(StatT const& st) { 472 TimeSpec TS = {st.st_mtime, st.st_mtime_n}; 473 return TS; 474 } 475 inline TimeSpec extract_atime(StatT const& st) { 476 TimeSpec TS = {st.st_atime, st.st_atime_n}; 477 return TS; 478 } 479 #else 480 inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } 481 inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } 482 #endif 483 484 #if !defined(_LIBCPP_WIN32API) 485 inline TimeVal make_timeval(TimeSpec const& ts) { 486 using namespace chrono; 487 auto Convert = [](long nsec) { 488 using int_type = decltype(std::declval<TimeVal>().tv_usec); 489 auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count(); 490 return static_cast<int_type>(dur); 491 }; 492 TimeVal TV = {}; 493 TV.tv_sec = ts.tv_sec; 494 TV.tv_usec = Convert(ts.tv_nsec); 495 return TV; 496 } 497 498 inline bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS, 499 error_code& ec) { 500 TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; 501 if (::utimes(p.c_str(), ConvertedTS) == -1) { 502 ec = capture_errno(); 503 return true; 504 } 505 return false; 506 } 507 508 #if defined(_LIBCPP_USE_UTIMENSAT) 509 bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS, 510 error_code& ec) { 511 if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) { 512 ec = capture_errno(); 513 return true; 514 } 515 return false; 516 } 517 #endif 518 519 bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS, 520 error_code& ec) { 521 #if !defined(_LIBCPP_USE_UTIMENSAT) 522 return posix_utimes(p, TS, ec); 523 #else 524 return posix_utimensat(p, TS, ec); 525 #endif 526 } 527 #endif /* !_LIBCPP_WIN32API */ 528 529 } // namespace 530 } // end namespace detail 531 532 _LIBCPP_END_NAMESPACE_FILESYSTEM 533 534 #endif // FILESYSTEM_COMMON_H 535