]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_ceph: Handle the special case of UTIME_NOW
authorAnoop C S <anoopcs@samba.org>
Sat, 14 Jun 2025 09:24:52 +0000 (14:54 +0530)
committerRalph Boehme <slow@samba.org>
Mon, 30 Jun 2025 13:15:37 +0000 (13:15 +0000)
As per utimensat(2)[1]:
. . .
If the tv_nsec field of one of the timespec structures has the special
value UTIME_NOW, then the corresponding file timestamp is set to the
current time.
. . .

Instead of utimes() or futimes() we make use of ceph_setattrx() with
appropriate mask to update timsestamps. It is also important to note
that ceph_setattrx() does not handle timestamps in pairs of timespec
structs. This had a shortcoming that the special consideration for the
magic value UTIME_NOW was left unattended resulting in epoch timestamps.
Therefore we reset those timestamps where UTIME_NOW is set in tv_nsec
with the current time.

[1] https://www.man7.org/linux/man-pages/man2/utimensat.2.html

Signed-off-by: Anoop C S <anoopcs@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/modules/vfs_ceph.c

index 7b9b2ec363867829fd9ea601426bed1cee44f7c7..8ea7eb09099f1b0b1928f9e9302a835b3bd6461d 100644 (file)
@@ -954,20 +954,33 @@ static int cephwrap_fntimes(struct vfs_handle_struct *handle,
        struct ceph_statx stx = { 0 };
        int result;
        int mask = 0;
+       struct timespec time_now = timespec_current();
 
        if (!is_omit_timespec(&ft->atime)) {
+               if (ft->atime.tv_nsec == UTIME_NOW) {
+                       ft->atime = time_now;
+               }
                stx.stx_atime = ft->atime;
                mask |= CEPH_SETATTR_ATIME;
        }
        if (!is_omit_timespec(&ft->mtime)) {
+               if (ft->mtime.tv_nsec == UTIME_NOW) {
+                       ft->mtime = time_now;
+               }
                stx.stx_mtime = ft->mtime;
                mask |= CEPH_SETATTR_MTIME;
        }
        if (!is_omit_timespec(&ft->ctime)) {
+               if (ft->ctime.tv_nsec == UTIME_NOW) {
+                       ft->ctime = time_now;
+               }
                stx.stx_ctime = ft->ctime;
                mask |= CEPH_SETATTR_CTIME;
        }
        if (!is_omit_timespec(&ft->create_time)) {
+               if (ft->create_time.tv_nsec == UTIME_NOW) {
+                       ft->create_time = time_now;
+               }
                stx.stx_btime = ft->create_time;
                mask |= CEPH_SETATTR_BTIME;
        }