From d23dbe914d68c21f67e2fd75243ae72314295e62 Mon Sep 17 00:00:00 2001 From: cptpcrd <31829097+cptpcrd@users.noreply.github.com> Date: Tue, 13 Apr 2021 20:52:11 -0400 Subject: [PATCH 1/2] main: tv_sec -> tv_nsec As specified in utimensat(2), *tv_nsec*, not *tv_sec*, should be set to UTIME_NOW or UTIME_OMIT. The way this bug manifests is that if utimensat() is called with one of the timestamps set to UTIME_OMIT, fuse-overlayfs will accidentally reset the timestamp to 1073741822, which is 2004-01-10 13:37:02 UTC. --- main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index 14ac260..6936894 100644 --- a/main.c +++ b/main.c @@ -3947,19 +3947,19 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru l = release_big_lock (); memset (times, 0, sizeof (times)); - times[0].tv_sec = UTIME_OMIT; - times[1].tv_sec = UTIME_OMIT; + times[0].tv_nsec = UTIME_OMIT; + times[1].tv_nsec = UTIME_OMIT; if (to_set & FUSE_SET_ATTR_ATIME) times[0] = attr->st_atim; else if (to_set & FUSE_SET_ATTR_ATIME_NOW) - times[0].tv_sec = UTIME_NOW; + times[0].tv_nsec = UTIME_NOW; if (to_set & FUSE_SET_ATTR_MTIME) times[1] = attr->st_mtim; else if (to_set & FUSE_SET_ATTR_MTIME_NOW) - times[1].tv_sec = UTIME_NOW; + times[1].tv_nsec = UTIME_NOW; - if (times[0].tv_sec != UTIME_OMIT || times[1].tv_sec != UTIME_OMIT) + if (times[0].tv_nsec != UTIME_OMIT || times[1].tv_nsec != UTIME_OMIT) { if (fd >= 0) ret = futimens (fd, times); From defd480c0ef020f83338a2214b80efa0d29bdc70 Mon Sep 17 00:00:00 2001 From: cptpcrd <31829097+cptpcrd@users.noreply.github.com> Date: Tue, 13 Apr 2021 20:58:48 -0400 Subject: [PATCH 2/2] main: improve UTIME_NOW special-casing FUSE never passes FUSE_SET_ATTR_ATIME_NOW without also passing FUSE_SET_ATTR_ATIME. Since FUSE_SET_ATTR_ATIME_NOW was only checked if FUSE_SET_ATTR_ATIME was not set, it would never be triggered. Note that this is an *improvement*, not a *fix*, because FUSE always passes the current time in st_atim whenever it sets FUSE_SET_ATTR_ATIME_NOW. As a result, the previous code works properly, but it does so differently from the way it was intended to. (All of the above descriptions of st_atim handling also applies to st_mtim.) --- main.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 6936894..4be2c9e 100644 --- a/main.c +++ b/main.c @@ -3950,14 +3950,18 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru times[0].tv_nsec = UTIME_OMIT; times[1].tv_nsec = UTIME_OMIT; if (to_set & FUSE_SET_ATTR_ATIME) - times[0] = attr->st_atim; - else if (to_set & FUSE_SET_ATTR_ATIME_NOW) - times[0].tv_nsec = UTIME_NOW; + { + times[0] = attr->st_atim; + if (to_set & FUSE_SET_ATTR_ATIME_NOW) + times[0].tv_nsec = UTIME_NOW; + } if (to_set & FUSE_SET_ATTR_MTIME) - times[1] = attr->st_mtim; - else if (to_set & FUSE_SET_ATTR_MTIME_NOW) - times[1].tv_nsec = UTIME_NOW; + { + times[1] = attr->st_mtim; + if (to_set & FUSE_SET_ATTR_MTIME_NOW) + times[1].tv_nsec = UTIME_NOW; + } if (times[0].tv_nsec != UTIME_OMIT || times[1].tv_nsec != UTIME_OMIT) {