mirror of git://gcc.gnu.org/git/gcc.git
Define new filesystem::__file_clock type
In C++17 the clock used for filesystem::file_time_type is unspecified, allowing it to be chrono::system_clock. The C++2a draft requires it to be a distinct type, with additional member functions to convert to/from other clocks (either the system clock or UTC). In order to avoid an ABI change later, this patch defines a new distinct type now, which will be used for std::chrono::file_clock later. * include/bits/fs_fwd.h (__file_clock): Define new clock. (file_time_type): Redefine in terms of __file_clock. * src/filesystem/ops-common.h (file_time): Add FIXME comment about overflow. * src/filesystem/std-ops.cc (is_set(perm_options, perm_options)): Give internal linkage. (internal_file_lock): New helper type for accessing __file_clock. (do_copy_file): Use internal_file_lock to convert system time to file_time_type. (last_write_time(const path&, error_code&)): Likewise. (last_write_time(const path&, file_time_type, error_code&)): Likewise. From-SVN: r267602
This commit is contained in:
parent
d06f73a387
commit
beb04ce9d4
|
|
@ -1,3 +1,17 @@
|
||||||
|
2019-01-05 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
* include/bits/fs_fwd.h (__file_clock): Define new clock.
|
||||||
|
(file_time_type): Redefine in terms of __file_clock.
|
||||||
|
* src/filesystem/ops-common.h (file_time): Add FIXME comment about
|
||||||
|
overflow.
|
||||||
|
* src/filesystem/std-ops.cc (is_set(perm_options, perm_options)): Give
|
||||||
|
internal linkage.
|
||||||
|
(internal_file_lock): New helper type for accessing __file_clock.
|
||||||
|
(do_copy_file): Use internal_file_lock to convert system time to
|
||||||
|
file_time_type.
|
||||||
|
(last_write_time(const path&, error_code&)): Likewise.
|
||||||
|
(last_write_time(const path&, file_time_type, error_code&)): Likewise.
|
||||||
|
|
||||||
2019-01-04 Jonathan Wakely <jwakely@redhat.com>
|
2019-01-04 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* config/abi/pre/gnu.ver (GLIBCXX_3.4.21): Make patterns less greedy
|
* config/abi/pre/gnu.ver (GLIBCXX_3.4.21): Make patterns less greedy
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,49 @@ _GLIBCXX_END_NAMESPACE_CXX11
|
||||||
operator^=(directory_options& __x, directory_options __y) noexcept
|
operator^=(directory_options& __x, directory_options __y) noexcept
|
||||||
{ return __x = __x ^ __y; }
|
{ return __x = __x ^ __y; }
|
||||||
|
|
||||||
using file_time_type = std::chrono::system_clock::time_point;
|
struct __file_clock
|
||||||
|
{
|
||||||
|
using duration = chrono::nanoseconds;
|
||||||
|
using rep = duration::rep;
|
||||||
|
using period = duration::period;
|
||||||
|
using time_point = chrono::time_point<__file_clock>;
|
||||||
|
static constexpr bool is_steady = false;
|
||||||
|
|
||||||
|
static time_point
|
||||||
|
now() noexcept
|
||||||
|
{ return _S_from_sys(chrono::system_clock::now()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
using __sys_clock = chrono::system_clock;
|
||||||
|
|
||||||
|
// This clock's (unspecified) epoch is 2174-01-01 00:00:00 UTC.
|
||||||
|
// A signed 64-bit duration with nanosecond resolution gives roughly
|
||||||
|
// +/- 292 years, which covers the 1901-2446 date range for ext4.
|
||||||
|
static constexpr chrono::seconds _S_epoch_diff{6437664000};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// For internal use only
|
||||||
|
template<typename _Dur>
|
||||||
|
static
|
||||||
|
chrono::time_point<__file_clock, _Dur>
|
||||||
|
_S_from_sys(const chrono::time_point<__sys_clock, _Dur>& __t) noexcept
|
||||||
|
{
|
||||||
|
using __file_time = chrono::time_point<__file_clock, _Dur>;
|
||||||
|
return __file_time{__t.time_since_epoch()} - _S_epoch_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For internal use only
|
||||||
|
template<typename _Dur>
|
||||||
|
static
|
||||||
|
chrono::time_point<__sys_clock, _Dur>
|
||||||
|
_S_to_sys(const chrono::time_point<__file_clock, _Dur>& __t) noexcept
|
||||||
|
{
|
||||||
|
using __sys_time = chrono::time_point<__sys_clock, _Dur>;
|
||||||
|
return __sys_time{__t.time_since_epoch()} + _S_epoch_diff;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using file_time_type = __file_clock::time_point;
|
||||||
|
|
||||||
// operational functions
|
// operational functions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,24 @@ namespace __gnu_posix
|
||||||
nanoseconds ns{};
|
nanoseconds ns{};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
// There are possible timespec values which will overflow
|
||||||
|
// chrono::system_clock::time_point but would not overflow
|
||||||
|
// __file_clock::time_point, due to its different epoch.
|
||||||
|
//
|
||||||
|
// By checking for overflow of the intermediate system_clock::duration
|
||||||
|
// type, we report an error for values which are actually representable
|
||||||
|
// in the file_time_type result type.
|
||||||
|
//
|
||||||
|
// Howard Hinnant's solution for this problem is to use
|
||||||
|
// duration<__int128>{s} + ns, which doesn't overflow.
|
||||||
|
// An alternative would be to do the epoch correction on s before
|
||||||
|
// the addition, and then go straight to file_time_type instead of
|
||||||
|
// going via chrono::system_clock::time_point.
|
||||||
|
//
|
||||||
|
// (This only applies to the C++17 Filesystem library, because for the
|
||||||
|
// Filesystem TS we don't have a distinct __file_clock, we just use the
|
||||||
|
// system clock for file timestamps).
|
||||||
if (s >= (nanoseconds::max().count() / 1e9))
|
if (s >= (nanoseconds::max().count() / 1e9))
|
||||||
{
|
{
|
||||||
ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
|
ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
|
||||||
|
|
|
||||||
|
|
@ -268,13 +268,32 @@ fs::copy(const path& from, const path& to, copy_options options)
|
||||||
namespace std::filesystem
|
namespace std::filesystem
|
||||||
{
|
{
|
||||||
// Need this as there's no 'perm_options::none' enumerator.
|
// Need this as there's no 'perm_options::none' enumerator.
|
||||||
inline bool is_set(fs::perm_options obj, fs::perm_options bits)
|
static inline bool is_set(fs::perm_options obj, fs::perm_options bits)
|
||||||
{
|
{
|
||||||
return (obj & bits) != fs::perm_options{};
|
return (obj & bits) != fs::perm_options{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct internal_file_clock : fs::__file_clock
|
||||||
|
{
|
||||||
|
using __file_clock::_S_to_sys;
|
||||||
|
using __file_clock::_S_from_sys;
|
||||||
|
|
||||||
|
static fs::file_time_type
|
||||||
|
from_stat(const fs::stat_type& st, std::error_code& ec) noexcept
|
||||||
|
{
|
||||||
|
const auto sys_time = fs::file_time(st, ec);
|
||||||
|
if (sys_time == sys_time.min())
|
||||||
|
return fs::file_time_type::min();
|
||||||
|
return _S_from_sys(sys_time);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NEED_DO_COPY_FILE
|
#ifdef NEED_DO_COPY_FILE
|
||||||
bool
|
bool
|
||||||
fs::do_copy_file(const path::value_type* from, const path::value_type* to,
|
fs::do_copy_file(const path::value_type* from, const path::value_type* to,
|
||||||
|
|
@ -348,10 +367,10 @@ fs::do_copy_file(const path::value_type* from, const path::value_type* to,
|
||||||
}
|
}
|
||||||
else if (options.update)
|
else if (options.update)
|
||||||
{
|
{
|
||||||
const auto from_mtime = file_time(*from_st, ec);
|
const auto from_mtime = internal_file_clock::from_stat(*from_st, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
return false;
|
return false;
|
||||||
if ((from_mtime <= file_time(*to_st, ec)) || ec)
|
if ((from_mtime <= internal_file_clock::from_stat(*to_st, ec)) || ec)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!options.overwrite)
|
else if (!options.overwrite)
|
||||||
|
|
@ -1122,7 +1141,10 @@ fs::last_write_time(const path& p)
|
||||||
fs::file_time_type
|
fs::file_time_type
|
||||||
fs::last_write_time(const path& p, error_code& ec) noexcept
|
fs::last_write_time(const path& p, error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
|
return do_stat(p, ec,
|
||||||
|
[&ec](const auto& st) {
|
||||||
|
return internal_file_clock::from_stat(st, ec);
|
||||||
|
},
|
||||||
file_time_type::min());
|
file_time_type::min());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1139,7 +1161,7 @@ void
|
||||||
fs::last_write_time(const path& p __attribute__((__unused__)),
|
fs::last_write_time(const path& p __attribute__((__unused__)),
|
||||||
file_time_type new_time, error_code& ec) noexcept
|
file_time_type new_time, error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
auto d = new_time.time_since_epoch();
|
auto d = internal_file_clock::_S_to_sys(new_time).time_since_epoch();
|
||||||
auto s = chrono::duration_cast<chrono::seconds>(d);
|
auto s = chrono::duration_cast<chrono::seconds>(d);
|
||||||
#if _GLIBCXX_USE_UTIMENSAT
|
#if _GLIBCXX_USE_UTIMENSAT
|
||||||
auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
|
auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue