mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-04 01:53:57 +08:00
Check for overflow in filesystem::last_write_time
* include/experimental/bits/fs_fwd.h (file_time_type): Simplify definition. * src/filesystem/ops.cc (file_time): Take error_code parameter and check for overflow. (do_copy_file, last_write_time): Pass error_code in file_time calls. * testsuite/experimental/filesystem/operations/last_write_time.cc: New. * testsuite/util/testsuite_fs.h (scoped_file): Define RAII helper. From-SVN: r240587
This commit is contained in:
parent
93c9b105be
commit
fd5effb17e
@ -1,5 +1,14 @@
|
||||
2016-09-28 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* include/experimental/bits/fs_fwd.h (file_time_type): Simplify
|
||||
definition.
|
||||
* src/filesystem/ops.cc (file_time): Take error_code parameter and
|
||||
check for overflow.
|
||||
(do_copy_file, last_write_time): Pass error_code in file_time calls.
|
||||
* testsuite/experimental/filesystem/operations/last_write_time.cc:
|
||||
New.
|
||||
* testsuite/util/testsuite_fs.h (scoped_file): Define RAII helper.
|
||||
|
||||
PR libstdc++/77686
|
||||
* include/std/functional (_Any_data): Add may_alias attribute.
|
||||
|
||||
|
@ -253,7 +253,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
|
||||
operator^=(directory_options& __x, directory_options __y) noexcept
|
||||
{ return __x = __x ^ __y; }
|
||||
|
||||
typedef chrono::time_point<chrono::system_clock> file_time_type;
|
||||
using file_time_type = std::chrono::system_clock::time_point;
|
||||
|
||||
// operational functions
|
||||
|
||||
|
@ -288,16 +288,24 @@ namespace
|
||||
}
|
||||
|
||||
inline fs::file_time_type
|
||||
file_time(const stat_type& st) noexcept
|
||||
file_time(const stat_type& st, std::error_code& ec) noexcept
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return fs::file_time_type{
|
||||
#ifdef _GLIBCXX_USE_ST_MTIM
|
||||
seconds{st.st_mtim.tv_sec} + nanoseconds{st.st_mtim.tv_nsec}
|
||||
time_t s = st.st_mtim.tv_sec;
|
||||
nanoseconds ns{st.st_mtim.tv_nsec};
|
||||
#else
|
||||
seconds{st.st_mtime}
|
||||
time_t s = st.st_mtime;
|
||||
nanoseconds ns{};
|
||||
#endif
|
||||
};
|
||||
|
||||
if (s >= (nanoseconds::max().count() / 1e9))
|
||||
{
|
||||
ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
|
||||
return fs::file_time_type::min();
|
||||
}
|
||||
ec.clear();
|
||||
return fs::file_time_type{seconds{s} + ns};
|
||||
}
|
||||
|
||||
// Returns true if the file descriptor was successfully closed,
|
||||
@ -373,11 +381,11 @@ namespace
|
||||
}
|
||||
else if (is_set(option, opts::update_existing))
|
||||
{
|
||||
if (file_time(*from_st) <= file_time(*to_st))
|
||||
{
|
||||
ec.clear();
|
||||
return false;
|
||||
}
|
||||
const auto from_mtime = file_time(*from_st, ec);
|
||||
if (ec)
|
||||
return false;
|
||||
if ((from_mtime <= file_time(*to_st, ec)) || ec)
|
||||
return false;
|
||||
}
|
||||
else if (!is_set(option, opts::overwrite_existing))
|
||||
{
|
||||
@ -1036,7 +1044,7 @@ fs::last_write_time(const path& p)
|
||||
fs::file_time_type
|
||||
fs::last_write_time(const path& p, error_code& ec) noexcept
|
||||
{
|
||||
return do_stat(p, ec, [](const auto& st) { return file_time(st); },
|
||||
return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
|
||||
file_time_type::min());
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-lstdc++fs" }
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-require-filesystem-ts "" }
|
||||
|
||||
// 15.25 Permissions [fs.op.last_write_time]
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <testsuite_fs.h>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
#ifdef _GLIBCXX_HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
#if _GLIBCXX_HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
using time_type = std::experimental::filesystem::file_time_type;
|
||||
|
||||
auto p = __gnu_test::nonexistent_path();
|
||||
std::error_code ec;
|
||||
time_type mtime = last_write_time(p, ec);
|
||||
VERIFY( ec );
|
||||
VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
|
||||
#if __cpp_exceptions
|
||||
bool caught = false;
|
||||
try {
|
||||
mtime = last_write_time(p);
|
||||
} catch (std::system_error const& e) {
|
||||
caught = true;
|
||||
ec = e.code();
|
||||
}
|
||||
VERIFY( caught );
|
||||
VERIFY( ec );
|
||||
VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
|
||||
#endif
|
||||
|
||||
__gnu_test::scoped_file file(p);
|
||||
VERIFY( exists(p) );
|
||||
mtime = last_write_time(p, ec);
|
||||
VERIFY( !ec );
|
||||
VERIFY( mtime <= time_type::clock::now() );
|
||||
VERIFY( mtime == last_write_time(p) );
|
||||
|
||||
auto end_of_time = time_type::duration::max();
|
||||
auto last_second
|
||||
= std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
|
||||
if (last_second > std::numeric_limits<std::time_t>::max())
|
||||
return; // can't test overflow
|
||||
|
||||
#if _GLIBCXX_USE_UTIMENSAT
|
||||
struct ::timespec ts[2];
|
||||
ts[0].tv_sec = 0;
|
||||
ts[0].tv_nsec = UTIME_NOW;
|
||||
ts[1].tv_sec = std::numeric_limits<std::time_t>::max() - 1;
|
||||
ts[1].tv_nsec = 0;
|
||||
VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) );
|
||||
#elif _GLIBCXX_HAVE_UTIME_H
|
||||
::utimbuf times;
|
||||
times.modtime = std::numeric_limits<std::time_t>::max() - 1;
|
||||
times.actime = std::numeric_limits<std::time_t>::max() - 1;
|
||||
VERIFY( !::utime(p.c_str(), ×) );
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
mtime = last_write_time(p, ec);
|
||||
VERIFY( ec );
|
||||
VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
|
||||
VERIFY( mtime == time_type::min() );
|
||||
|
||||
#if __cpp_exceptions
|
||||
caught = false;
|
||||
try {
|
||||
mtime = last_write_time(p);
|
||||
} catch (std::system_error const& e) {
|
||||
caught = true;
|
||||
ec = e.code();
|
||||
}
|
||||
VERIFY( caught );
|
||||
VERIFY( ec );
|
||||
VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
#define _TESTSUITE_FS_H 1
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <stdlib.h>
|
||||
@ -40,7 +40,6 @@ namespace __gnu_test
|
||||
compare_paths(const std::experimental::filesystem::path& p1,
|
||||
const std::experimental::filesystem::path& p2)
|
||||
{
|
||||
// std::cout << "Comparing " << p1 << " and " << p2 << std::endl;
|
||||
PATH_CHK( p1, p2, string );
|
||||
PATH_CHK( p1, p2, empty );
|
||||
PATH_CHK( p1, p2, has_root_path );
|
||||
@ -95,5 +94,23 @@ namespace __gnu_test
|
||||
return p;
|
||||
}
|
||||
|
||||
// RAII helper to remove a file on scope exit.
|
||||
struct scoped_file
|
||||
{
|
||||
using path_type = std::experimental::filesystem::path;
|
||||
|
||||
enum adopt_file_t { adopt_file };
|
||||
|
||||
explicit
|
||||
scoped_file(const path_type& p = nonexistent_path()) : path(p)
|
||||
{ std::ofstream{p.native()}; }
|
||||
|
||||
scoped_file(path_type p, adopt_file_t) : path(p) { }
|
||||
|
||||
~scoped_file() { remove(path); }
|
||||
|
||||
path_type path;
|
||||
};
|
||||
|
||||
} // namespace __gnu_test
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user