Fall back to utimes(2) if utimensat(2) isn't available
This commit is contained in:
parent
f9d42cd1de
commit
990c3d22ab
@ -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));
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user