aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar David Leverton <levertond@googlemail.com> 2010-02-10 18:52:11 +0000
committerAvatar David Leverton <levertond@googlemail.com> 2010-02-13 12:05:08 +0000
commit990c3d22ab79a76d6610f65df63efc14a1167300 (patch)
treefccdc2b58b4c896bf4b10f25fa546b9432754150
parentf9d42cd1deff8a2a8fb2d175f6f1d914e73505b3 (diff)
downloadpaludis-990c3d22ab79a76d6610f65df63efc14a1167300.tar.gz
paludis-990c3d22ab79a76d6610f65df63efc14a1167300.tar.xz
Fall back to utimes(2) if utimensat(2) isn't available
-rw-r--r--configure.ac4
-rw-r--r--paludis/merger_TEST.cc25
-rw-r--r--paludis/util/fs_entry.cc36
-rw-r--r--paludis/util/timestamp.cc7
-rw-r--r--paludis/util/timestamp.hh2
5 files changed, 60 insertions, 14 deletions
diff --git a/configure.ac b/configure.ac
index 3c92779..b39cef6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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([
diff --git a/paludis/merger_TEST.cc b/paludis/merger_TEST.cc
index e10884d..f035b88 100644
--- a/paludis/merger_TEST.cc
+++ b/paludis/merger_TEST.cc
@@ -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;
}
diff --git a/paludis/util/fs_entry.cc b/paludis/util/fs_entry.cc
index 1ada08a..abd3da6 100644
--- a/paludis/util/fs_entry.cc
+++ b/paludis/util/fs_entry.cc
@@ -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
diff --git a/paludis/util/timestamp.cc b/paludis/util/timestamp.cc
index 95553b2..314bb07 100644
--- a/paludis/util/timestamp.cc
+++ b/paludis/util/timestamp.cc
@@ -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()
{
diff --git a/paludis/util/timestamp.hh b/paludis/util/timestamp.hh
index 2e3fd84..8a3cbc0 100644
--- a/paludis/util/timestamp.hh
+++ b/paludis/util/timestamp.hh
@@ -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));
};