Fall back to utimes(2) if utimensat(2) isn't available

This commit is contained in:
David Leverton 2010-02-10 18:52:11 +00:00
parent f9d42cd1de
commit 990c3d22ab
5 changed files with 60 additions and 14 deletions

@ -147,6 +147,10 @@ dnl {{{ check for lchflags function
AC_CHECK_FUNCS([lchflags])
dnl }}}
dnl {{{ check for utimensat
AC_CHECK_FUNCS([utimensat])
dnl }}}
dnl {{{ check for listxattrf etc
AC_MSG_CHECKING([for f*xattr function family])
AC_COMPILE_IFELSE([

@ -43,6 +43,15 @@ namespace
{
return std::make_pair(-1, -1);
}
bool
timestamps_nearly_equal(const Timestamp & i_set, const Timestamp & reference)
{
return i_set == reference ||
(i_set.seconds() == reference.seconds() &&
i_set.nanoseconds() % 1000 == 0 &&
i_set.nanoseconds() / 1000 == reference.nanoseconds() / 1000);
}
}
namespace paludis
@ -551,11 +560,11 @@ namespace test_cases
TEST_CHECK(merger.check());
merger.merge();
TEST_CHECK((root_dir / "new_file").mtim() == m_new);
TEST_CHECK((root_dir / "existing_file").mtim() == m_existing);
TEST_CHECK(timestamps_nearly_equal((root_dir / "new_file").mtim(), m_new));
TEST_CHECK(timestamps_nearly_equal((root_dir / "existing_file").mtim(), m_existing));
TEST_CHECK(Timestamp::now().seconds() - (root_dir / "dodgy_file").mtim().seconds() >= (60 * 60 * 24 * 365 * 3) - 1);
TEST_CHECK((root_dir / "dir" / "new_file").mtim() == m_dir_new);
TEST_CHECK(timestamps_nearly_equal((root_dir / "dir" / "new_file").mtim(), m_dir_new));
TEST_CHECK(Timestamp::now().seconds() - (root_dir / "dir" / "dodgy_file").mtim().seconds() >= (60 * 60 * 24 * 365 * 3) - 1);
}
} test_merger_mtimes;
@ -573,12 +582,12 @@ namespace test_cases
TEST_CHECK(merger.check());
merger.merge();
TEST_CHECK((root_dir / "new_file").mtim() == m_new);
TEST_CHECK((root_dir / "existing_file").mtim() == m_existing);
TEST_CHECK((root_dir / "dodgy_file").mtim() == FSEntry("merger_TEST_dir/reference").mtim());
TEST_CHECK(timestamps_nearly_equal((root_dir / "new_file").mtim(), m_new));
TEST_CHECK(timestamps_nearly_equal((root_dir / "existing_file").mtim(), m_existing));
TEST_CHECK(timestamps_nearly_equal((root_dir / "dodgy_file").mtim(), FSEntry("merger_TEST_dir/reference").mtim()));
TEST_CHECK((root_dir / "dir" / "new_file").mtim() == m_dir_new);
TEST_CHECK((root_dir / "dir" / "dodgy_file").mtim() == FSEntry("merger_TEST_dir/reference").mtim());
TEST_CHECK(timestamps_nearly_equal((root_dir / "dir" / "new_file").mtim(), m_dir_new));
TEST_CHECK(timestamps_nearly_equal((root_dir / "dir" / "dodgy_file").mtim(), FSEntry("merger_TEST_dir/reference").mtim()));
}
} test_merger_mtimes_fix;
}

@ -21,6 +21,7 @@
#include <paludis/util/exception.hh>
#include <paludis/util/fs_entry.hh>
#include <paludis/util/log.hh>
#include <paludis/util/mutex.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/sequence.hh>
@ -34,6 +35,7 @@
#include <paludis/util/wrapped_output_iterator-impl.hh>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <utime.h>
#include <dirent.h>
@ -626,18 +628,40 @@ FSEntry::rmdir()
bool
FSEntry::utime(const Timestamp & t)
{
struct timespec ts[2] = { t.as_timespec(), t.as_timespec() };
if (0 == ::utimensat(AT_FDCWD, _imp->path.c_str(), ts, 0))
Context context("When setting utime for '" + stringify(_imp->path) + "':");
#ifdef HAVE_UTIMENSAT
static bool utimensat_works(true);
if (utimensat_works)
{
struct timespec ts[2] = { t.as_timespec(), t.as_timespec() };
if (0 == ::utimensat(AT_FDCWD, _imp->path.c_str(), ts, 0))
return true;
int e(errno);
if (e == ENOENT)
return false;
else if (e == ENOSYS)
{
utimensat_works = false;
Log::get_instance()->message("util.fs_entry.utime.utimensat_unimplemented", ll_debug, lc_context)
<< "utimensat(2) not implemented by this kernel, using utimes(2)";
}
else
throw FSError("utimensat '" + _imp->path + "' failed: " + ::strerror(e));
}
#endif
struct timeval tv[2] = { t.as_timeval(), t.as_timeval() };
if (0 == ::utimes(_imp->path.c_str(), tv))
return true;
int e(errno);
if (e == ENOENT)
return false;
else
{
Context context("When setting utime for '" + stringify(_imp->path) + "':");
throw FSError("utime '" + _imp->path + "' failed: " + ::strerror(e));
}
throw FSError("utimes '" + _imp->path + "' failed: " + ::strerror(e));
}
std::string

@ -81,6 +81,13 @@ Timestamp::as_timespec() const
return result;
}
struct timeval
Timestamp::as_timeval() const
{
struct timeval result = { _s, _ns / 1000 };
return result;
}
Timestamp
Timestamp::now()
{

@ -24,6 +24,7 @@
#include <paludis/util/operators.hh>
#include <paludis/util/attributes.hh>
#include <sys/stat.h>
#include <sys/time.h>
namespace paludis
{
@ -57,6 +58,7 @@ namespace paludis
long nanoseconds() const PALUDIS_ATTRIBUTE((warn_unused_result));
struct timespec as_timespec() const PALUDIS_ATTRIBUTE((warn_unused_result));
struct timeval as_timeval() const PALUDIS_ATTRIBUTE((warn_unused_result));
static Timestamp now() PALUDIS_ATTRIBUTE((warn_unused_result));
};