diff options
author | Eric Fiselier <eric@efcs.ca> | 2018-07-25 20:51:49 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2018-07-25 20:51:49 +0000 |
commit | 81872e95bf6507ac88866b1b0f588416b2b2330c (patch) | |
tree | d01675ede0c6b96ea698d5f9d69290c66a89c1fd /src | |
parent | a1ae56c033b41d4eaffb3769f669eadb992ae2e1 (diff) | |
download | libcxx-81872e95bf6507ac88866b1b0f588416b2b2330c.tar.gz |
[libc++] Use __int128_t to represent file_time_type.
Summary:
The ``file_time_type`` time point is used to represent the write times for files.
Its job is to act as part of a C++ wrapper for less ideal system interfaces. The
underlying filesystem uses the ``timespec`` struct for the same purpose.
However, the initial implementation of ``file_time_type`` could not represent
either the range or resolution of ``timespec``, making it unsuitable. Fixing
this requires an implementation which uses more than 64 bits to store the
time point.
I primarily considered two solutions: Using ``__int128_t`` and using a
arithmetic emulation of ``timespec``. Each has its pros and cons, and both
come with more than one complication.
However, after a lot of consideration, I decided on using `__int128_t`. This patch implements that change.
Please see the [FileTimeType Design Document](http://libcxx.llvm.org/docs/DesignDocs/FileTimeType.html) for more information.
Reviewers: mclow.lists, ldionne, joerg, arthur.j.odwyer, EricWF
Reviewed By: EricWF
Subscribers: christof, K-ballo, cfe-commits, BillyONeal
Differential Revision: https://reviews.llvm.org/D49774
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@337960 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'src')
-rw-r--r-- | src/chrono.cpp | 41 | ||||
-rw-r--r-- | src/experimental/filesystem/filesystem_common.h | 263 | ||||
-rw-r--r-- | src/experimental/filesystem/operations.cpp | 82 | ||||
-rw-r--r-- | src/include/apple_availability.h | 52 |
4 files changed, 250 insertions, 188 deletions
diff --git a/src/chrono.cpp b/src/chrono.cpp index d0e184ad3..882d50b9d 100644 --- a/src/chrono.cpp +++ b/src/chrono.cpp @@ -11,27 +11,10 @@ #include "cerrno" // errno #include "system_error" // __throw_system_error #include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME +#include "include/apple_availability.h" -#if (__APPLE__) -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200 -#define _LIBCXX_USE_CLOCK_GETTIME -#endif -#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000 -#define _LIBCXX_USE_CLOCK_GETTIME -#endif -#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000 -#define _LIBCXX_USE_CLOCK_GETTIME -#endif -#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000 -#define _LIBCXX_USE_CLOCK_GETTIME -#endif -#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__ -#else -#define _LIBCXX_USE_CLOCK_GETTIME +#if !defined(__APPLE__) +#define _LIBCPP_USE_CLOCK_GETTIME #endif // __APPLE__ #if defined(_LIBCPP_WIN32API) @@ -42,7 +25,7 @@ #include <winapifamily.h> #endif #else -#if !defined(CLOCK_REALTIME) || !defined(_LIBCXX_USE_CLOCK_GETTIME) +#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME) #include <sys/time.h> // for gettimeofday and timeval #endif // !defined(CLOCK_REALTIME) #endif // defined(_LIBCPP_WIN32API) @@ -92,16 +75,16 @@ system_clock::now() _NOEXCEPT static_cast<__int64>(ft.dwLowDateTime)}; return time_point(duration_cast<duration>(d - nt_to_unix_epoch)); #else -#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) - struct timespec tp; - if (0 != clock_gettime(CLOCK_REALTIME, &tp)) - __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); - return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000)); +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + struct timespec tp; + if (0 != clock_gettime(CLOCK_REALTIME, &tp)) + __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); + return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000)); #else timeval tv; gettimeofday(&tv, 0); return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); -#endif // _LIBCXX_USE_CLOCK_GETTIME && CLOCK_REALTIME +#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME #endif } @@ -129,7 +112,7 @@ const bool steady_clock::is_steady; #if defined(__APPLE__) // Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW -#if defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) steady_clock::time_point steady_clock::now() _NOEXCEPT { @@ -191,7 +174,7 @@ steady_clock::now() _NOEXCEPT static FP fp = init_steady_clock(); return time_point(duration(fp())); } -#endif // defined(_LIBCXX_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) +#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) #elif defined(_LIBCPP_WIN32API) diff --git a/src/experimental/filesystem/filesystem_common.h b/src/experimental/filesystem/filesystem_common.h index 104d0aa7b..7be167460 100644 --- a/src/experimental/filesystem/filesystem_common.h +++ b/src/experimental/filesystem/filesystem_common.h @@ -23,33 +23,17 @@ #include <experimental/filesystem> -#if (__APPLE__) -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300 -#define _LIBCXX_USE_UTIMENSAT -#endif -#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000 -#define _LIBCXX_USE_UTIMENSAT -#endif -#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000 -#define _LIBCXX_USE_UTIMENSAT -#endif -#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) -#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000 -#define _LIBCXX_USE_UTIMENSAT -#endif -#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__ -#else +#include "../../include/apple_availability.h" + +#if !defined(__APPLE__) // We can use the presence of UTIME_OMIT to detect platforms that provide // utimensat. #if defined(UTIME_OMIT) -#define _LIBCXX_USE_UTIMENSAT +#define _LIBCPP_USE_UTIMENSAT +#endif #endif -#endif // __APPLE__ -#if !defined(_LIBCXX_USE_UTIMENSAT) +#if !defined(_LIBCPP_USE_UTIMENSAT) #include <sys/time.h> // for ::utimes as used in __last_write_time #endif @@ -212,76 +196,119 @@ private: ErrorHandler& operator=(ErrorHandler const&) = delete; }; -namespace time_util { +using chrono::duration; +using chrono::duration_cast; -using namespace chrono; +using TimeSpec = struct ::timespec; +using StatT = struct ::stat; -template <class FileTimeT, +template <class FileTimeT, class TimeT, bool IsFloat = is_floating_point<typename FileTimeT::rep>::value> -struct fs_time_util_base { - static constexpr seconds::rep max_seconds = - duration_cast<seconds>(FileTimeT::duration::max()).count(); - - static constexpr nanoseconds::rep max_nsec = - duration_cast<nanoseconds>(FileTimeT::duration::max() - - seconds(max_seconds)) +struct time_util_base { + using rep = typename FileTimeT::rep; + using fs_duration = typename FileTimeT::duration; + using fs_seconds = duration<rep>; + using fs_nanoseconds = duration<rep, nano>; + using fs_microseconds = duration<rep, micro>; + + static constexpr rep max_seconds = + duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); + + static constexpr rep max_nsec = + duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - + fs_seconds(max_seconds)) .count(); - static constexpr seconds::rep min_seconds = - duration_cast<seconds>(FileTimeT::duration::min()).count(); + static constexpr rep min_seconds = + duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); - static constexpr nanoseconds::rep min_nsec_timespec = - duration_cast<nanoseconds>( - (FileTimeT::duration::min() - seconds(min_seconds)) + seconds(1)) + static constexpr rep min_nsec_timespec = + duration_cast<fs_nanoseconds>( + (FileTimeT::duration::min() - fs_seconds(min_seconds)) + + fs_seconds(1)) .count(); +private: +#if _LIBCPP_STD_VER > 11 + static constexpr fs_duration get_min_nsecs() { + return duration_cast<fs_duration>( + fs_nanoseconds(min_nsec_timespec) - + duration_cast<fs_nanoseconds>(fs_seconds(1))); + } // Static assert that these values properly round trip. - static_assert((seconds(min_seconds) + - duration_cast<microseconds>(nanoseconds(min_nsec_timespec))) - - duration_cast<microseconds>(seconds(1)) == + static_assert(fs_seconds(min_seconds) + get_min_nsecs() == FileTimeT::duration::min(), - ""); + "value doesn't roundtrip"); + + static constexpr bool check_range() { + // This kinda sucks, but it's what happens when we don't have __int128_t. + if (sizeof(TimeT) == sizeof(rep)) { + typedef duration<long long, ratio<3600 * 24 * 365> > Years; + return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) && + duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250); + } + return max_seconds >= numeric_limits<TimeT>::max() && + min_seconds <= numeric_limits<TimeT>::min(); + } + static_assert(check_range(), "the representable range is unacceptable small"); +#endif }; -template <class FileTimeT> -struct fs_time_util_base<FileTimeT, true> { - static const long long max_seconds; - static const long long max_nsec; - static const long long min_seconds; - static const long long min_nsec_timespec; +template <class FileTimeT, class TimeT> +struct time_util_base<FileTimeT, TimeT, true> { + using rep = typename FileTimeT::rep; + using fs_duration = typename FileTimeT::duration; + using fs_seconds = duration<rep>; + using fs_nanoseconds = duration<rep, nano>; + using fs_microseconds = duration<rep, micro>; + + static const rep max_seconds; + static const rep max_nsec; + static const rep min_seconds; + static const rep min_nsec_timespec; }; -template <class FileTimeT> -const long long fs_time_util_base<FileTimeT, true>::max_seconds = - duration_cast<seconds>(FileTimeT::duration::max()).count(); +template <class FileTimeT, class TimeT> +const typename FileTimeT::rep + time_util_base<FileTimeT, TimeT, true>::max_seconds = + duration_cast<fs_seconds>(FileTimeT::duration::max()).count(); -template <class FileTimeT> -const long long fs_time_util_base<FileTimeT, true>::max_nsec = - duration_cast<nanoseconds>(FileTimeT::duration::max() - - seconds(max_seconds)) +template <class FileTimeT, class TimeT> +const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec = + duration_cast<fs_nanoseconds>(FileTimeT::duration::max() - + fs_seconds(max_seconds)) .count(); -template <class FileTimeT> -const long long fs_time_util_base<FileTimeT, true>::min_seconds = - duration_cast<seconds>(FileTimeT::duration::min()).count(); +template <class FileTimeT, class TimeT> +const typename FileTimeT::rep + time_util_base<FileTimeT, TimeT, true>::min_seconds = + duration_cast<fs_seconds>(FileTimeT::duration::min()).count(); -template <class FileTimeT> -const long long fs_time_util_base<FileTimeT, true>::min_nsec_timespec = - duration_cast<nanoseconds>( - (FileTimeT::duration::min() - seconds(min_seconds)) + seconds(1)) - .count(); +template <class FileTimeT, class TimeT> +const typename FileTimeT::rep + time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec = + duration_cast<fs_nanoseconds>((FileTimeT::duration::min() - + fs_seconds(min_seconds)) + + fs_seconds(1)) + .count(); template <class FileTimeT, class TimeT, class TimeSpecT> -struct fs_time_util : fs_time_util_base<FileTimeT> { - using Base = fs_time_util_base<FileTimeT>; +struct time_util : time_util_base<FileTimeT, TimeT> { + using Base = time_util_base<FileTimeT, TimeT>; using Base::max_nsec; using Base::max_seconds; using Base::min_nsec_timespec; using Base::min_seconds; + using typename Base::fs_duration; + using typename Base::fs_microseconds; + using typename Base::fs_nanoseconds; + using typename Base::fs_seconds; + public: template <class CType, class ChronoType> - static bool checked_set(CType* out, ChronoType time) { + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out, + ChronoType time) { using Lim = numeric_limits<CType>; if (time > Lim::max() || time < Lim::min()) return false; @@ -291,21 +318,21 @@ public: static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) { if (tm.tv_sec >= 0) { - return (tm.tv_sec < max_seconds) || + return tm.tv_sec < max_seconds || (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec); } else if (tm.tv_sec == (min_seconds - 1)) { return tm.tv_nsec >= min_nsec_timespec; } else { - return (tm.tv_sec >= min_seconds); + return tm.tv_sec >= min_seconds; } } static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) { - auto secs = duration_cast<seconds>(tm.time_since_epoch()); - auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs); + auto secs = duration_cast<fs_seconds>(tm.time_since_epoch()); + auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs); if (nsecs.count() < 0) { - secs = secs + seconds(1); - nsecs = nsecs + seconds(1); + secs = secs + fs_seconds(1); + nsecs = nsecs + fs_seconds(1); } using TLim = numeric_limits<TimeT>; if (secs.count() >= 0) @@ -314,49 +341,45 @@ public: } static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT - convert_timespec(TimeSpecT tm) { - auto adj_msec = duration_cast<microseconds>(nanoseconds(tm.tv_nsec)); - if (tm.tv_sec >= 0) { - auto Dur = seconds(tm.tv_sec) + microseconds(adj_msec); - return FileTimeT(Dur); - } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() == - 0) { - return FileTimeT(seconds(tm.tv_sec)); + convert_from_timespec(TimeSpecT tm) { + if (tm.tv_sec >= 0 || tm.tv_nsec == 0) { + return FileTimeT(fs_seconds(tm.tv_sec) + + duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec))); } else { // tm.tv_sec < 0 - auto adj_subsec = - duration_cast<microseconds>(seconds(1) - nanoseconds(tm.tv_nsec)); - auto Dur = seconds(tm.tv_sec + 1) - adj_subsec; + auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) - + fs_nanoseconds(tm.tv_nsec)); + auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec; return FileTimeT(Dur); } } - template <class SubSecDurT, class SubSecT> - static bool set_times_checked(TimeT* sec_out, SubSecT* subsec_out, - FileTimeT tp) { + template <class SubSecT> + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool + set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) { auto dur = tp.time_since_epoch(); - auto sec_dur = duration_cast<seconds>(dur); - auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur); + auto sec_dur = duration_cast<fs_seconds>(dur); + auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur); // The tv_nsec and tv_usec fields must not be negative so adjust accordingly if (subsec_dur.count() < 0) { if (sec_dur.count() > min_seconds) { - sec_dur -= seconds(1); - subsec_dur += seconds(1); + sec_dur -= fs_seconds(1); + subsec_dur += fs_seconds(1); } else { - subsec_dur = SubSecDurT::zero(); + subsec_dur = fs_nanoseconds::zero(); } } return checked_set(sec_out, sec_dur.count()) && checked_set(subsec_out, subsec_dur.count()); } + static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest, + FileTimeT tp) { + if (!is_representable(tp)) + return false; + return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp); + } }; -} // namespace time_util - - -using TimeSpec = struct ::timespec; -using StatT = struct ::stat; - -using FSTime = time_util::fs_time_util<file_time_type, time_t, struct timespec>; +using fs_time = time_util<file_time_type, time_t, TimeSpec>; #if defined(__APPLE__) TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } @@ -366,20 +389,18 @@ TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } TimeSpec extract_atime(StatT const& st) { return st.st_atim; } #endif -#if !defined(_LIBCXX_USE_UTIMENSAT) -using TimeStruct = struct ::timeval; -using TimeStructArray = TimeStruct[2]; -#else -using TimeStruct = TimeSpec; -using TimeStructArray = TimeStruct[2]; -#endif - -bool SetFileTimes(const path& p, TimeStructArray const& TS, - error_code& ec) { -#if !defined(_LIBCXX_USE_UTIMENSAT) - if (::utimes(p.c_str(), TS) == -1) +bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS, + error_code& ec) { +#if !defined(_LIBCPP_USE_UTIMENSAT) + using namespace chrono; + auto Convert = [](long nsec) { + return duration_cast<microseconds>(nanoseconds(nsec)).count(); + }; + struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)}, + {TS[1].tv_sec, Convert(TS[1].tv_nsec)}}; + if (::utimes(p.c_str(), ConvertedTS) == -1) #else - if (::utimensat(AT_FDCWD, p.c_str(), TS, 0) == -1) + if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) #endif { ec = capture_errno(); @@ -388,25 +409,9 @@ bool SetFileTimes(const path& p, TimeStructArray const& TS, return false; } -void SetTimeStructTo(TimeStruct& TS, TimeSpec ToTS) { - using namespace chrono; - TS.tv_sec = ToTS.tv_sec; -#if !defined(_LIBCXX_USE_UTIMENSAT) - TS.tv_usec = duration_cast<microseconds>(nanoseconds(ToTS.tv_nsec)).count(); -#else - TS.tv_nsec = ToTS.tv_nsec; -#endif -} - -bool SetTimeStructTo(TimeStruct& TS, file_time_type NewTime) { - using namespace chrono; -#if !defined(_LIBCXX_USE_UTIMENSAT) - return !FSTime::set_times_checked<microseconds>(&TS.tv_sec, &TS.tv_usec, - NewTime); -#else - return !FSTime::set_times_checked<nanoseconds>(&TS.tv_sec, &TS.tv_nsec, - NewTime); -#endif +bool set_time_spec_to(TimeSpec& TS, file_time_type NewTime) { + return !fs_time::set_times_checked( + &TS.tv_sec, &TS.tv_nsec, NewTime); } } // namespace diff --git a/src/experimental/filesystem/operations.cpp b/src/experimental/filesystem/operations.cpp index dd8b43477..d57066875 100644 --- a/src/experimental/filesystem/operations.cpp +++ b/src/experimental/filesystem/operations.cpp @@ -23,6 +23,7 @@ #include <unistd.h> #include <sys/stat.h> #include <sys/statvfs.h> +#include <time.h> #include <fcntl.h> /* values for fchmodat */ #if defined(__linux__) @@ -36,6 +37,14 @@ # define _LIBCPP_USE_COPYFILE #endif +#if !defined(__APPLE__) +#define _LIBCPP_USE_CLOCK_GETTIME +#endif + +#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME) +#include <sys/time.h> // for gettimeofday and timeval +#endif // !defined(CLOCK_REALTIME) + #if defined(_LIBCPP_COMPILER_GCC) #if _GNUC_VER < 500 #pragma GCC diagnostic ignored "-Wmissing-field-initializers" @@ -44,9 +53,6 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM -filesystem_error::~filesystem_error() {} - - namespace { namespace parser { @@ -355,7 +361,7 @@ private: explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {} }; -perms posix_get_perms(const struct ::stat& st) noexcept { +perms posix_get_perms(const StatT& st) noexcept { return static_cast<perms>(st.st_mode) & perms::mask; } @@ -364,8 +370,7 @@ perms posix_get_perms(const struct ::stat& st) noexcept { } file_status create_file_status(error_code& m_ec, path const& p, - const struct ::stat& path_stat, - error_code* ec) { + const StatT& path_stat, error_code* ec) { if (ec) *ec = m_ec; if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { @@ -400,8 +405,7 @@ file_status create_file_status(error_code& m_ec, path const& p, return fs_tmp; } -file_status posix_stat(path const& p, struct ::stat& path_stat, - error_code* ec) { +file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { error_code m_ec; if (::stat(p.c_str(), &path_stat) == -1) m_ec = detail::capture_errno(); @@ -409,12 +413,11 @@ file_status posix_stat(path const& p, struct ::stat& path_stat, } file_status posix_stat(path const& p, error_code* ec) { - struct ::stat path_stat; + StatT path_stat; return posix_stat(p, path_stat, ec); } -file_status posix_lstat(path const& p, struct ::stat& path_stat, - error_code* ec) { +file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { error_code m_ec; if (::lstat(p.c_str(), &path_stat) == -1) m_ec = detail::capture_errno(); @@ -422,7 +425,7 @@ file_status posix_lstat(path const& p, struct ::stat& path_stat, } file_status posix_lstat(path const& p, error_code* ec) { - struct ::stat path_stat; + StatT path_stat; return posix_lstat(p, path_stat, ec); } @@ -464,10 +467,32 @@ file_status FileDescriptor::refresh_status(error_code& ec) { using detail::capture_errno; using detail::ErrorHandler; using detail::StatT; +using detail::TimeSpec; using parser::createView; using parser::PathParser; using parser::string_view_t; +const bool _FilesystemClock::is_steady; + +_FilesystemClock::time_point _FilesystemClock::now() noexcept { + typedef chrono::duration<rep> __secs; +#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + typedef chrono::duration<rep, nano> __nsecs; + struct timespec tp; + if (0 != clock_gettime(CLOCK_REALTIME, &tp)) + __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); + return time_point(__secs(tp.tv_sec) + + chrono::duration_cast<duration>(__nsecs(tp.tv_nsec))); +#else + typedef chrono::duration<rep, micro> __microsecs; + timeval tv; + gettimeofday(&tv, 0); + return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec)); +#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME +} + +filesystem_error::~filesystem_error() {} + void filesystem_error::__create_what(int __num_paths) { const char* derived_what = system_error::what(); __storage_->__what_ = [&]() -> string { @@ -525,14 +550,14 @@ void __copy(const path& from, const path& to, copy_options options, const bool sym_status2 = bool(options & copy_options::copy_symlinks); error_code m_ec1; - struct ::stat f_st = {}; + StatT f_st = {}; const file_status f = sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1); if (m_ec1) return err.report(m_ec1); - struct ::stat t_st = {}; + StatT t_st = {}; const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1); @@ -916,7 +941,7 @@ uintmax_t __file_size(const path& p, error_code *ec) ErrorHandler<uintmax_t> err("file_size", ec, &p); error_code m_ec; - struct ::stat st; + StatT st; file_status fst = detail::posix_stat(p, st, &m_ec); if (!exists(fst) || !is_regular_file(fst)) { errc error_kind = @@ -966,14 +991,14 @@ bool __fs_is_empty(const path& p, error_code *ec) static file_time_type __extract_last_write_time(const path& p, const StatT& st, error_code* ec) { - using detail::FSTime; + using detail::fs_time; ErrorHandler<file_time_type> err("last_write_time", ec, &p); auto ts = detail::extract_mtime(st); - if (!FSTime::is_representable(ts)) + if (!fs_time::is_representable(ts)) return err.report(errc::value_too_large); - return FSTime::convert_timespec(ts); + return fs_time::convert_from_timespec(ts); } file_time_type __last_write_time(const path& p, error_code *ec) @@ -992,30 +1017,27 @@ file_time_type __last_write_time(const path& p, error_code *ec) void __last_write_time(const path& p, file_time_type new_time, error_code *ec) { - using namespace chrono; - using namespace detail; - ErrorHandler<void> err("last_write_time", ec, &p); error_code m_ec; - TimeStructArray tbuf; -#if !defined(_LIBCXX_USE_UTIMENSAT) + array<TimeSpec, 2> tbuf; +#if !defined(_LIBCPP_USE_UTIMENSAT) // This implementation has a race condition between determining the // last access time and attempting to set it to the same value using // ::utimes - struct ::stat st; + StatT st; file_status fst = detail::posix_stat(p, st, &m_ec); - if (m_ec && !status_known(fst)) + if (m_ec) return err.report(m_ec); - SetTimeStructTo(tbuf[0], detail::extract_atime(st)); + tbuf[0] = detail::extract_atime(st); #else tbuf[0].tv_sec = 0; tbuf[0].tv_nsec = UTIME_OMIT; #endif - if (SetTimeStructTo(tbuf[1], new_time)) - return err.report(errc::invalid_argument); + if (detail::set_time_spec_to(tbuf[1], new_time)) + return err.report(errc::value_too_large); - SetFileTimes(p, tbuf, m_ec); + detail::set_file_times(p, tbuf, m_ec); if (m_ec) return err.report(m_ec); } @@ -1591,7 +1613,7 @@ error_code directory_entry::__do_refresh() noexcept { __data_.__reset(); error_code failure_ec; - struct ::stat full_st; + StatT full_st; file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); if (!status_known(st)) { __data_.__reset(); diff --git a/src/include/apple_availability.h b/src/include/apple_availability.h new file mode 100644 index 000000000..c12f7325c --- /dev/null +++ b/src/include/apple_availability.h @@ -0,0 +1,52 @@ +//===------------------------ apple_availability.h ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H +#define _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H + +#if defined(__APPLE__) + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300 +#define _LIBCPP_USE_UTIMENSAT +#endif +#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000 +#define _LIBCPP_USE_UTIMENSAT +#endif +#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000 +#define _LIBCPP_USE_UTIMENSAT +#endif +#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000 +#define _LIBCPP_USE_UTIMENSAT +#endif +#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__ + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200 +#define _LIBCPP_USE_CLOCK_GETTIME +#endif +#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000 +#define _LIBCPP_USE_CLOCK_GETTIME +#endif +#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000 +#define _LIBCPP_USE_CLOCK_GETTIME +#endif +#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) +#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000 +#define _LIBCPP_USE_CLOCK_GETTIME +#endif +#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__ + +#endif // __APPLE__ + +#endif // _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H |