summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrzemyslaw Pawelczyk <przemoc@gmail.com>2022-05-21 16:01:23 +0200
committerPrzemyslaw Pawelczyk <przemoc@gmail.com>2022-05-21 16:01:23 +0200
commita20cb5571cf8271a52344c0320e65bc2369ecddd (patch)
treedcedd5e84c4e032ffb1fc297a6b3abfa73241d65
parent72c21c112b209b2d092de2fd1750b6741bb187e3 (diff)
metastore.c: Do not skip nanoseconds when applying mtime.
Apply mtime using utimensat() instead of utime(), which not only supports setting nanoseconds, but also omitting atime change (last access time), and working on symlinks - we use all of that. Reported-by: Björn Haßler <bjohas@users.noreply.github.com>
-rw-r--r--src/metastore.c22
1 files changed, 10 insertions, 12 deletions
diff --git a/src/metastore.c b/src/metastore.c
index c6f48cf..bf6f416 100644
--- a/src/metastore.c
+++ b/src/metastore.c
@@ -24,7 +24,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
-#include <utime.h>
+#include <fcntl.h>
#if !defined(NO_XATTR) || !(NO_XATTR+0)
# include <sys/xattr.h>
@@ -144,7 +144,7 @@ compare_fix(struct metaentry *real, struct metaentry *stored, int cmp)
struct passwd *owner;
gid_t gid = -1;
uid_t uid = -1;
- struct utimbuf tbuf;
+ struct timespec times[2];
unsigned i;
if (!real && !stored) {
@@ -222,16 +222,14 @@ compare_fix(struct metaentry *real, struct metaentry *stored, int cmp)
msg(MSG_DEBUG, "\tchmod failed: %s\n", strerror(errno));
}
- /* FIXME: Use utimensat here, or even better - lutimensat */
- if ((cmp & DIFF_MTIME) && S_ISLNK(real->mode)) {
- msg(MSG_NORMAL, "%s:\tsymlink, not changing mtime\n", real->path);
- } else if (cmp & DIFF_MTIME) {
- msg(MSG_NORMAL, "%s:\tchanging mtime from %ld to %ld\n",
- real->path, real->mtime, stored->mtime);
- tbuf.actime = stored->mtime;
- tbuf.modtime = stored->mtime;
- if (utime(real->path, &tbuf)) {
- msg(MSG_DEBUG, "\tutime failed: %s\n", strerror(errno));
+ if (cmp & DIFF_MTIME) {
+ msg(MSG_NORMAL, "%s:\tchanging mtime from %ld.%09d to %ld.%09d\n",
+ real->path, real->mtime, real->mtimensec, stored->mtime, stored->mtimensec);
+ times[0].tv_nsec = UTIME_OMIT; // atime (last access time)
+ times[1].tv_sec = stored->mtime; // mtime (last modification time)
+ times[1].tv_nsec = stored->mtimensec;
+ if (utimensat(AT_FDCWD, real->path, times, AT_SYMLINK_NOFOLLOW)) {
+ msg(MSG_DEBUG, "\tutimensat failed: %s\n", strerror(errno));
return;
}
}