From: Anoop C S Date: Sat, 14 Jun 2025 09:02:28 +0000 (+0530) Subject: vfs_ceph_new: Handle the special case of UTIME_NOW X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a9fc256afa387eb72dad9bace20950fe3b0a06d0;p=thirdparty%2Fsamba.git vfs_ceph_new: Handle the special case of UTIME_NOW 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_ll_setattr() with appropriate mask to update timsestamps. It is also important to note that ceph_ll_setattr() 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 Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Jun 30 14:16:52 UTC 2025 on atb-devel-224 --- diff --git a/source3/modules/vfs_ceph_new.c b/source3/modules/vfs_ceph_new.c index 04694d56baf..caafdad12af 100644 --- a/source3/modules/vfs_ceph_new.c +++ b/source3/modules/vfs_ceph_new.c @@ -1031,23 +1031,37 @@ static int vfs_ceph_ll_fchmod(struct vfs_handle_struct *handle, cfh->uperm); } -static void vfs_ceph_fill_statx_mask_from_ft(const struct smb_file_time *ft, +static void vfs_ceph_fill_statx_mask_from_ft(struct smb_file_time *ft, struct ceph_statx *stx, int *mask) { + 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; } @@ -1055,7 +1069,7 @@ static void vfs_ceph_fill_statx_mask_from_ft(const struct smb_file_time *ft, static int vfs_ceph_ll_utimes(struct vfs_handle_struct *handle, const struct vfs_ceph_iref *iref, - const struct smb_file_time *ft) + struct smb_file_time *ft) { struct ceph_statx stx = {0}; struct UserPerm *uperm = NULL; @@ -1094,7 +1108,7 @@ static int vfs_ceph_ll_utimes(struct vfs_handle_struct *handle, static int vfs_ceph_ll_futimes(struct vfs_handle_struct *handle, const struct vfs_ceph_fh *cfh, - const struct smb_file_time *ft) + struct smb_file_time *ft) { struct ceph_statx stx = {0}; int mask = 0;