aboutsummaryrefslogtreecommitdiff
path: root/src/experimental/filesystem/operations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/experimental/filesystem/operations.cpp')
-rw-r--r--src/experimental/filesystem/operations.cpp167
1 files changed, 17 insertions, 150 deletions
diff --git a/src/experimental/filesystem/operations.cpp b/src/experimental/filesystem/operations.cpp
index e9bc0eb6e30e..641a3c53636d 100644
--- a/src/experimental/filesystem/operations.cpp
+++ b/src/experimental/filesystem/operations.cpp
@@ -15,6 +15,8 @@
#include "cstdlib"
#include "climits"
+#include "filesystem_time_helper.h"
+
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -426,17 +428,20 @@ void __current_path(const path& p, std::error_code *ec) {
bool __equivalent(const path& p1, const path& p2, std::error_code *ec)
{
+ auto make_unsupported_error = [&]() {
+ set_or_throw(make_error_code(errc::not_supported), ec,
+ "equivalent", p1, p2);
+ return false;
+ };
std::error_code ec1, ec2;
struct ::stat st1 = {};
struct ::stat st2 = {};
auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
+ if (!exists(s1))
+ return make_unsupported_error();
auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
-
- if ((!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2))) {
- set_or_throw(make_error_code(errc::not_supported), ec,
- "equivalent", p1, p2);
- return false;
- }
+ if (!exists(s2))
+ return make_unsupported_error();
if (ec) ec->clear();
return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
}
@@ -502,17 +507,6 @@ bool __fs_is_empty(const path& p, std::error_code *ec)
namespace detail { namespace {
-using namespace std::chrono;
-
-template <class CType, class ChronoType>
-bool checked_set(CType* out, ChronoType time) {
- using Lim = numeric_limits<CType>;
- if (time > Lim::max() || time < Lim::min())
- return false;
- *out = static_cast<CType>(time);
- return true;
-}
-
using TimeSpec = struct timespec;
using StatT = struct stat;
@@ -525,137 +519,10 @@ __attribute__((unused)) // Suppress warning
TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
#endif
-constexpr auto max_seconds = duration_cast<seconds>(
- file_time_type::duration::max()).count();
-
-constexpr auto max_nsec = duration_cast<nanoseconds>(
- file_time_type::duration::max() - seconds(max_seconds)).count();
-
-constexpr auto min_seconds = duration_cast<seconds>(
- file_time_type::duration::min()).count();
-
-constexpr auto min_nsec_timespec = duration_cast<nanoseconds>(
- (file_time_type::duration::min() - seconds(min_seconds)) + seconds(1)).count();
-
-// 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))
- == file_time_type::duration::min(), "");
-
-constexpr auto max_time_t = numeric_limits<time_t>::max();
-constexpr auto min_time_t = numeric_limits<time_t>::min();
-
-#if !defined(__LP64__) && defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-bool is_representable(TimeSpec const& tm) {
- if (tm.tv_sec >= 0) {
- 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);
- }
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(is_representable({max_seconds, max_nsec}), "");
-static_assert(!is_representable({max_seconds + 1, 0}), "");
-static_assert(!is_representable({max_seconds, max_nsec + 1}), "");
-static_assert(!is_representable({max_time_t, 0}), "");
-static_assert(is_representable({min_seconds, 0}), "");
-static_assert(is_representable({min_seconds - 1, min_nsec_timespec}), "");
-static_assert(is_representable({min_seconds - 1, min_nsec_timespec + 1}), "");
-static_assert(!is_representable({min_seconds - 1, min_nsec_timespec - 1}), "");
-static_assert(!is_representable({min_time_t, 999999999}), "");
-#else
-static_assert(is_representable({max_time_t, 999999999}), "");
-static_assert(is_representable({max_time_t, 1000000000}), "");
-static_assert(is_representable({min_time_t, 0}), "");
-#endif
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-bool is_representable(file_time_type const& tm) {
- auto secs = duration_cast<seconds>(tm.time_since_epoch());
- auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs);
- if (nsecs.count() < 0) {
- secs = secs + seconds(1);
- nsecs = nsecs + seconds(1);
- }
- using TLim = numeric_limits<time_t>;
- if (secs.count() >= 0)
- return secs.count() <= TLim::max();
- return secs.count() >= TLim::min();
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(is_representable(file_time_type::max()), "");
-static_assert(is_representable(file_time_type::min()), "");
-#else
-static_assert(!is_representable(file_time_type::max()), "");
-static_assert(!is_representable(file_time_type::min()), "");
-static_assert(is_representable(file_time_type(seconds(max_time_t))), "");
-static_assert(is_representable(file_time_type(seconds(min_time_t))), "");
-#endif
-#endif
-
-_LIBCPP_CONSTEXPR_AFTER_CXX11
-file_time_type convert_timespec(TimeSpec const& 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 file_time_type(Dur);
- } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() == 0) {
- return file_time_type(seconds(tm.tv_sec));
- } 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;
- return file_time_type(Dur);
- }
-}
-#ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
-#if defined(__LP64__)
-static_assert(convert_timespec({max_seconds, max_nsec}) == file_time_type::max(), "");
-static_assert(convert_timespec({max_seconds, max_nsec - 1}) < file_time_type::max(), "");
-static_assert(convert_timespec({max_seconds - 1, 999999999}) < file_time_type::max(), "");
-static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec}) == file_time_type::min(), "");
-static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec + 1}) > file_time_type::min(), "");
-static_assert(convert_timespec({min_seconds , 0}) > file_time_type::min(), "");
-#else
-// FIXME add tests for 32 bit builds
-#endif
-#endif
-
-#if !defined(__LP64__) && defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-template <class SubSecDurT, class SubSecT>
-bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) {
- using namespace chrono;
- auto dur = tp.time_since_epoch();
- auto sec_dur = duration_cast<seconds>(dur);
- auto subsec_dur = duration_cast<SubSecDurT>(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);
- } else {
- subsec_dur = SubSecDurT::zero();
- }
- }
- return checked_set(sec_out, sec_dur.count())
- && checked_set(subsec_out, subsec_dur.count());
-}
-
}} // end namespace detail
+using FSTime = fs_time_util<file_time_type, time_t, struct timespec>;
+
file_time_type __last_write_time(const path& p, std::error_code *ec)
{
using namespace ::std::chrono;
@@ -668,12 +535,12 @@ file_time_type __last_write_time(const path& p, std::error_code *ec)
}
if (ec) ec->clear();
auto ts = detail::extract_mtime(st);
- if (!detail::is_representable(ts)) {
+ if (!FSTime::is_representable(ts)) {
set_or_throw(error_code(EOVERFLOW, generic_category()), ec,
"last_write_time", p);
return file_time_type::min();
}
- return detail::convert_timespec(ts);
+ return FSTime::convert_timespec(ts);
}
void __last_write_time(const path& p, file_time_type new_time,
@@ -698,7 +565,7 @@ void __last_write_time(const path& p, file_time_type new_time,
struct ::timeval tbuf[2];
tbuf[0].tv_sec = atime.tv_sec;
tbuf[0].tv_usec = duration_cast<microseconds>(nanoseconds(atime.tv_nsec)).count();
- const bool overflowed = !detail::set_times_checked<microseconds>(
+ const bool overflowed = !FSTime::set_times_checked<microseconds>(
&tbuf[1].tv_sec, &tbuf[1].tv_usec, new_time);
if (overflowed) {
@@ -714,7 +581,7 @@ void __last_write_time(const path& p, file_time_type new_time,
tbuf[0].tv_sec = 0;
tbuf[0].tv_nsec = UTIME_OMIT;
- const bool overflowed = !detail::set_times_checked<nanoseconds>(
+ const bool overflowed = !FSTime::set_times_checked<nanoseconds>(
&tbuf[1].tv_sec, &tbuf[1].tv_nsec, new_time);
if (overflowed) {
set_or_throw(make_error_code(errc::invalid_argument),