summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2018-07-25 20:51:49 +0000
committerEric Fiselier <eric@efcs.ca>2018-07-25 20:51:49 +0000
commit81872e95bf6507ac88866b1b0f588416b2b2330c (patch)
treed01675ede0c6b96ea698d5f9d69290c66a89c1fd /src
parenta1ae56c033b41d4eaffb3769f669eadb992ae2e1 (diff)
downloadlibcxx-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.cpp41
-rw-r--r--src/experimental/filesystem/filesystem_common.h263
-rw-r--r--src/experimental/filesystem/operations.cpp82
-rw-r--r--src/include/apple_availability.h52
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