Tweaks utimensat/futimens handling to always update ctime, even when both
authorguenther <guenther@openbsd.org>
Fri, 17 Apr 2015 04:43:20 +0000 (04:43 +0000)
committerguenther <guenther@openbsd.org>
Fri, 17 Apr 2015 04:43:20 +0000 (04:43 +0000)
atime and mtime are UTIME_OMIT (at least for ufs, tmpfs, and ext2fs), and
to correctly handle a timestamp of -1.

ok millert@

13 files changed:
lib/libc/sys/utimes.2
sys/isofs/cd9660/cd9660_vnops.c
sys/kern/vfs_syscalls.c
sys/miscfs/fuse/fuse_vnops.c
sys/msdosfs/msdosfs_vnops.c
sys/nfs/nfs_subs.c
sys/nfs/nfs_vnops.c
sys/nfs/xdr_subs.h
sys/sys/vnode.h
sys/tmpfs/tmpfs_subr.c
sys/tmpfs/tmpfs_vnops.c
sys/ufs/ext2fs/ext2fs_vnops.c
sys/ufs/ufs/ufs_vnops.c

index 5dce000..f3d15d5 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: utimes.2,v 1.24 2015/02/27 23:56:03 millert Exp $
+.\"    $OpenBSD: utimes.2,v 1.25 2015/04/17 04:43:20 guenther Exp $
 .\"    $NetBSD: utimes.2,v 1.9 1996/04/23 10:34:16 mycroft Exp $
 .\"
 .\" Copyright (c) 1990, 1993
@@ -30,7 +30,7 @@
 .\"
 .\"     @(#)utimes.2   8.1 (Berkeley) 6/4/93
 .\"
-.Dd $Mdocdate: February 27 2015 $
+.Dd $Mdocdate: April 17 2015 $
 .Dt UTIMES 2
 .Os
 .Sh NAME
@@ -75,8 +75,7 @@ The access time is set to the value of the first element, and the
 modification time is set to the value of the second element.
 The caller must be the owner of the file or be the superuser.
 .Pp
-In either case, the inode-change-time of the file is set to the current
-time.
+In either case, the file status change time is set to the current time.
 .Pp
 The
 .Fn utimensat
@@ -294,15 +293,13 @@ and
 function calls appeared in
 .Ox 5.0 .
 .Sh CAVEATS
-.St -p1003.1-2008
-specifies that
-.Fn utimensat
-and
-.Fn futimens
-shall mark the last file status change timestamp (i.e.\&
-.Fa st_ctim )
-for update upon successful completion.
-However, currently some filesystems (e.g. UFS)
-will not do so if
+Some filesystems, such as FAT, use the same timestamp for both
+modification and file status change;
+on those filesystems, the file status change timestamp will not be
+updated if
 .Dv UTIME_OMIT
 is specified for the modification timestamp argument.
+Similarly, on NFS the file status change timestamp will not be
+updated if
+.Dv UTIME_OMIT
+is specified for both the access and the modification timestamp arguments.
index 07ea253..ce9d1c4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cd9660_vnops.c,v 1.71 2015/03/14 03:38:50 jsg Exp $   */
+/*     $OpenBSD: cd9660_vnops.c,v 1.72 2015/04/17 04:43:20 guenther Exp $      */
 /*     $NetBSD: cd9660_vnops.c,v 1.42 1997/10/16 23:56:57 christos Exp $       */
 
 /*-
@@ -94,8 +94,9 @@ cd9660_setattr(void *v)
        struct vattr *vap = ap->a_vap;
 
        if (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
-           vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
-           vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
+           vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_nsec != VNOVAL ||
+           vap->va_mtime.tv_nsec != VNOVAL || vap->va_mode != (mode_t)VNOVAL ||
+           (vap->va_vaflags & VA_UTIMES_CHANGE))
                return (EROFS);
        if (vap->va_size != VNOVAL) {
                switch (vp->v_type) {
index 99d45da..7cac013 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vfs_syscalls.c,v 1.217 2015/03/14 03:38:51 jsg Exp $  */
+/*     $OpenBSD: vfs_syscalls.c,v 1.218 2015/04/17 04:43:20 guenther Exp $     */
 /*     $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $        */
 
 /*
@@ -2283,6 +2283,10 @@ dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2])
 #endif
 
        VATTR_NULL(&vattr);
+
+       /*  make sure ctime is updated even if neither mtime nor atime is */
+       vattr.va_vaflags = VA_UTIMES_CHANGE;
+
        if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
                if (ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW)
                        vattr.va_vaflags |= VA_UTIMES_NULL;
@@ -2294,29 +2298,22 @@ dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2])
                        ts[1] = now;
        }
 
-       /*
-        * XXX: Ideally the filesystem code would check tv_nsec ==
-        * UTIME_OMIT instead of tv_sec == VNOVAL, but until then we
-        * need to fudge tv_sec if it happens to equal VNOVAL.
-        */
-       if (ts[0].tv_nsec == UTIME_OMIT)
-               ts[0].tv_sec = VNOVAL;
-       else if (ts[0].tv_sec == VNOVAL)
-               ts[0].tv_sec = VNOVAL - 1;
-
-       if (ts[1].tv_nsec == UTIME_OMIT)
-               ts[1].tv_sec = VNOVAL;
-       else if (ts[1].tv_sec == VNOVAL)
-               ts[1].tv_sec = VNOVAL - 1;
+       if (ts[0].tv_nsec != UTIME_OMIT) {
+               if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= 1000000000)
+                       return (EINVAL);
+               vattr.va_atime = ts[0];
+       }
+       if (ts[1].tv_nsec != UTIME_OMIT) {
+               if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= 1000000000)
+                       return (EINVAL);
+               vattr.va_mtime = ts[1];
+       }
 
        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                error = EROFS;
-       else {
-               vattr.va_atime = ts[0];
-               vattr.va_mtime = ts[1];
+       else
                error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
-       }
        vput(vp);
        return (error);
 }
index f680764..8ab7140 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_vnops.c,v 1.23 2015/02/19 10:22:20 tedu Exp $ */
+/* $OpenBSD: fuse_vnops.c,v 1.24 2015/04/17 04:43:21 guenther Exp $ */
 /*
  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -478,7 +478,7 @@ fusefs_setattr(void *v)
                io->fi_flags |= FUSE_FATTR_SIZE;
        }
 
-       if (vap->va_atime.tv_sec != VNOVAL) {
+       if (vap->va_atime.tv_nsec != VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                        error = EROFS;
                        goto out;
@@ -488,7 +488,7 @@ fusefs_setattr(void *v)
                io->fi_flags |= FUSE_FATTR_ATIME;
        }
 
-       if (vap->va_mtime.tv_sec != VNOVAL) {
+       if (vap->va_mtime.tv_nsec != VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                        error = EROFS;
                        goto out;
@@ -497,6 +497,7 @@ fusefs_setattr(void *v)
                fbuf->fb_vattr.va_mtime.tv_nsec = vap->va_mtime.tv_nsec;
                io->fi_flags |= FUSE_FATTR_MTIME;
        }
+       /* XXX should set a flag if (vap->va_vaflags & VA_UTIMES_CHANGE) */
 
        if (vap->va_mode != (mode_t)VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
index 3f16460..723f110 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: msdosfs_vnops.c,v 1.99 2015/03/14 03:38:51 jsg Exp $  */
+/*     $OpenBSD: msdosfs_vnops.c,v 1.100 2015/04/17 04:43:21 guenther Exp $    */
 /*     $NetBSD: msdosfs_vnops.c,v 1.63 1997/10/17 11:24:19 ws Exp $    */
 
 /*-
@@ -451,7 +451,9 @@ msdosfs_setattr(void *v)
                if (error)
                        return error;
        }
-       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+       if ((vap->va_vaflags & VA_UTIMES_CHANGE) ||
+           vap->va_atime.tv_nsec != VNOVAL ||
+           vap->va_mtime.tv_nsec != VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                        return (EINVAL);
                if (cred->cr_uid != pmp->pm_uid &&
@@ -461,12 +463,12 @@ msdosfs_setattr(void *v)
                        return (error);
                if (vp->v_type != VDIR) {
                        if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
-                           vap->va_atime.tv_sec != VNOVAL) {
+                           vap->va_atime.tv_nsec != VNOVAL) {
                                dep->de_flag &= ~DE_ACCESS;
                                unix2dostime(&vap->va_atime, &dep->de_ADate,
                                    NULL, NULL);
                        }
-                       if (vap->va_mtime.tv_sec != VNOVAL) {
+                       if (vap->va_mtime.tv_nsec != VNOVAL) {
                                dep->de_flag &= ~DE_UPDATE;
                                unix2dostime(&vap->va_mtime, &dep->de_MDate,
                                    &dep->de_MTime, NULL);
index ac27c29..7fb7eb5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nfs_subs.c,v 1.126 2015/03/14 03:38:52 jsg Exp $      */
+/*     $OpenBSD: nfs_subs.c,v 1.127 2015/04/17 04:43:21 guenther Exp $ */
 /*     $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $    */
 
 /*
@@ -1751,7 +1751,7 @@ nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full)
                tl = nfsm_build(&mb, NFSX_UNSIGNED);
                *tl = nfs_false;
        }
-       if (a->va_atime.tv_sec != VNOVAL) {
+       if (a->va_atime.tv_nsec != VNOVAL) {
                if (a->va_atime.tv_sec != time_second) {
                        tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
                        *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
@@ -1764,7 +1764,7 @@ nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full)
                tl = nfsm_build(&mb, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
        }
-       if (a->va_mtime.tv_sec != VNOVAL) {
+       if (a->va_mtime.tv_nsec != VNOVAL) {
                if (a->va_mtime.tv_sec != time_second) {
                        tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
                        *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
@@ -1870,11 +1870,13 @@ nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
        nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
        switch (fxdr_unsigned(int, *tl)) {
        case NFSV3SATTRTIME_TOCLIENT:
+               va->va_vaflags |= VA_UTIMES_CHANGE;
                va->va_vaflags &= ~VA_UTIMES_NULL;
                nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                fxdr_nfsv3time(tl, &va->va_atime);
                break;
        case NFSV3SATTRTIME_TOSERVER:
+               va->va_vaflags |= VA_UTIMES_CHANGE;
                getnanotime(&va->va_atime);
                break;
        };
@@ -1882,11 +1884,13 @@ nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
        nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
        switch (fxdr_unsigned(int, *tl)) {
        case NFSV3SATTRTIME_TOCLIENT:
+               va->va_vaflags |= VA_UTIMES_CHANGE;
                va->va_vaflags &= ~VA_UTIMES_NULL;
                nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                fxdr_nfsv3time(tl, &va->va_mtime);
                break;
        case NFSV3SATTRTIME_TOSERVER:
+               va->va_vaflags |= VA_UTIMES_CHANGE;
                getnanotime(&va->va_mtime);
                break;
        };
@@ -1896,3 +1900,22 @@ nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
 nfsmout:
        return (error);
 }
+
+void
+txdr_nfsv2time(const struct timespec *from, struct nfsv2_time *to)
+{
+       if (from->tv_nsec == VNOVAL) {
+               to->nfsv2_sec = nfs_xdrneg1;
+               to->nfsv2_usec = nfs_xdrneg1;
+       } else if (from->tv_sec == -1) {
+               /*
+                * can't request a time of -1; send
+                * -1.000001 == {-2,999999} instead
+                */
+               to->nfsv2_sec = htonl(-2);
+               to->nfsv2_usec = htonl(999999);
+       } else {
+               to->nfsv2_sec = htonl(from->tv_sec);
+               to->nfsv2_usec = htonl(from->tv_nsec / 1000);
+       }
+}
index 8569053..8396249 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nfs_vnops.c,v 1.162 2015/03/14 03:38:52 jsg Exp $     */
+/*     $OpenBSD: nfs_vnops.c,v 1.163 2015/04/17 04:43:21 guenther Exp $        */
 /*     $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $   */
 
 /*
@@ -565,8 +565,10 @@ nfs_setattr(void *v)
         * Disallow write attempts if the filesystem is mounted read-only.
         */
        if ((vap->va_uid != (uid_t)VNOVAL ||
-           vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
-           vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
+           vap->va_gid != (gid_t)VNOVAL ||
+           vap->va_atime.tv_nsec != VNOVAL ||
+           vap->va_mtime.tv_nsec != VNOVAL ||
+           vap->va_mode != (mode_t)VNOVAL) &&
            (vp->v_mount->mnt_flag & MNT_RDONLY))
                return (EROFS);
        if (vap->va_size != VNOVAL) {
@@ -577,8 +579,8 @@ nfs_setattr(void *v)
                case VBLK:
                case VSOCK:
                case VFIFO:
-                       if (vap->va_mtime.tv_sec == VNOVAL &&
-                           vap->va_atime.tv_sec == VNOVAL &&
+                       if (vap->va_mtime.tv_nsec == VNOVAL &&
+                           vap->va_atime.tv_nsec == VNOVAL &&
                            vap->va_mode == (mode_t)VNOVAL &&
                            vap->va_uid == (uid_t)VNOVAL &&
                            vap->va_gid == (gid_t)VNOVAL)
@@ -604,8 +606,8 @@ nfs_setattr(void *v)
                        np->n_size = np->n_vattr.va_size = vap->va_size;
                        uvm_vnp_setsize(vp, np->n_size);
                };
-       } else if ((vap->va_mtime.tv_sec != VNOVAL ||
-               vap->va_atime.tv_sec != VNOVAL) &&
+       } else if ((vap->va_mtime.tv_nsec != VNOVAL ||
+               vap->va_atime.tv_nsec != VNOVAL) &&
                vp->v_type == VREG &&
                (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
                    ap->a_p)) == EINTR)
@@ -2172,6 +2174,7 @@ nfs_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
                                ndp = (struct nfs_dirent *)
                                    uiop->uio_iov->iov_base;
                                dp = &ndp->dirent;
+                               memset(dp, 0, sizeof(dp));
                                dp->d_fileno = fileno;
                                dp->d_namlen = len;
                                dp->d_reclen = tlen;
index 80b8b2a..0532428 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: xdr_subs.h,v 1.9 2013/08/13 05:52:25 guenther Exp $   */
+/*     $OpenBSD: xdr_subs.h,v 1.10 2015/04/17 04:43:21 guenther Exp $  */
 /*     $NetBSD: xdr_subs.h,v 1.11 1996/02/18 11:54:12 fvdl Exp $       */
 
 /*
        else \
                (t)->tv_nsec = 0; \
 } while (0)
-#define        txdr_nfsv2time(f, t) do { \
-       ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->tv_sec); \
-       if ((f)->tv_nsec != -1) \
-               ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->tv_nsec / 1000); \
-       else \
-               ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \
-} while (0)
+
+struct nfsv2_time;
+void txdr_nfsv2time(const struct timespec *_from, struct nfsv2_time *_to);
 
 #define        fxdr_nfsv3time(f, t) do { \
        (t)->tv_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \
index b9dc772..85727da 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vnode.h,v 1.129 2015/01/09 05:01:57 tedu Exp $        */
+/*     $OpenBSD: vnode.h,v 1.130 2015/04/17 04:43:20 guenther Exp $    */
 /*     $NetBSD: vnode.h,v 1.38 1996/02/29 20:59:05 cgd Exp $   */
 
 /*
@@ -150,7 +150,9 @@ struct vnode {
 
 /*
  * Vnode attributes.  A field value of VNOVAL represents a field whose value
- * is unavailable (getattr) or which is not to be changed (setattr).
+ * is unavailable (getattr) or which is not to be changed (setattr).  For
+ * the timespec fields, only the tv_nsec member needs to be set to VNOVAL:
+ * if tv_nsec != VNOVAL then both tv_sec and tv_nsec are valid.
  */
 struct vattr {
        enum vtype      va_type;        /* vnode type (for create) */
@@ -177,8 +179,9 @@ struct vattr {
 /*
  * Flags for va_vaflags.
  */
-#define        VA_UTIMES_NULL  0x01            /* utimes argument was NULL */
-#define VA_EXCLUSIVE    0x02           /* exclusive create request */
+#define        VA_UTIMES_NULL          0x01    /* utimes argument was NULL */
+#define        VA_EXCLUSIVE            0x02    /* exclusive create request */
+#define        VA_UTIMES_CHANGE        0x04    /* ctime should be updated */
 /*
  * Flags for ioflag.
  */
index a36eb21..ce21637 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tmpfs_subr.c,v 1.13 2015/02/10 21:56:10 miod Exp $    */
+/*     $OpenBSD: tmpfs_subr.c,v 1.14 2015/04/17 04:43:21 guenther Exp $        */
 /*     $NetBSD: tmpfs_subr.c,v 1.79 2012/03/13 18:40:50 elad Exp $     */
 
 /*
@@ -1112,12 +1112,17 @@ tmpfs_chtimes(struct vnode *vp, const struct timespec *atime,
            (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                return error;
 
-       if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL)
+       if (atime->tv_nsec != VNOVAL)
                node->tn_atime = *atime;
  
-       if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL)
+       if (mtime->tv_nsec != VNOVAL)
                node->tn_mtime = *mtime;
+
+       if (mtime->tv_nsec != VNOVAL || (vaflags & VA_UTIMES_CHANGE))
+               tmpfs_update(VP_TO_TMPFS_NODE(vp), TMPFS_NODE_CHANGED);
+
        VN_KNOTE(vp, NOTE_ATTRIB);
+
        return 0;
 }
 
index 4da35bf..518d799 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tmpfs_vnops.c,v 1.21 2015/03/14 03:38:52 jsg Exp $    */
+/*     $OpenBSD: tmpfs_vnops.c,v 1.22 2015/04/17 04:43:21 guenther Exp $       */
 /*     $NetBSD: tmpfs_vnops.c,v 1.100 2012/11/05 17:27:39 dholland Exp $       */
 
 /*
@@ -480,7 +480,7 @@ tmpfs_getattr(void *v)
        return 0;
 }
 
-#define GOODTIME(tv)   ((tv)->tv_sec != VNOVAL || (tv)->tv_nsec != VNOVAL)
+#define GOODTIME(tv)   ((tv)->tv_nsec != VNOVAL)
 /* XXX Should this operation be atomic?  I think it should, but code in
  * XXX other places (e.g., ufs) doesn't seem to be... */
 int
@@ -519,13 +519,12 @@ tmpfs_setattr(void *v)
        if (error == 0 && (vap->va_mode != VNOVAL))
                error = tmpfs_chmod(vp, vap->va_mode, cred, p);
 
-       if (error == 0 && (GOODTIME(&vap->va_atime)
-           || GOODTIME(&vap->va_mtime))) {
+       if (error == 0 && ((vap->va_vaflags & VA_UTIMES_CHANGE)
+           || GOODTIME(&vap->va_atime)
+           || GOODTIME(&vap->va_mtime)))
                error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
                    vap->va_vaflags, cred, p);
-               if (error == 0)
-                       return 0;
-       }
+
        return error;
 }
 
index c88e6f4..13c3356 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_vnops.c,v 1.72 2015/03/14 03:38:52 jsg Exp $   */
+/*     $OpenBSD: ext2fs_vnops.c,v 1.73 2015/04/17 04:43:21 guenther Exp $      */
 /*     $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $  */
 
 /*
@@ -290,7 +290,9 @@ ext2fs_setattr(void *v)
                if (error)
                        return (error);
        }
-       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+       if ((vap->va_vaflags & VA_UTIMES_CHANGE) ||
+           vap->va_atime.tv_nsec != VNOVAL ||
+           vap->va_mtime.tv_nsec != VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                        return (EROFS);
                if (cred->cr_uid != ip->i_e2fs_uid &&
@@ -298,17 +300,19 @@ ext2fs_setattr(void *v)
                        ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
                        (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                        return (error);
-               if (vap->va_mtime.tv_sec != VNOVAL)
+               if (vap->va_mtime.tv_nsec != VNOVAL)
                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
-               if (vap->va_atime.tv_sec != VNOVAL) {
+               else if (vap->va_vaflags & VA_UTIMES_CHANGE)
+                       ip->i_flag |= IN_CHANGE;
+               if (vap->va_atime.tv_nsec != VNOVAL) {
                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME) ||
                            (ip->i_flag & (IN_CHANGE | IN_UPDATE)))
                                ip->i_flag |= IN_ACCESS;
                }
                EXT2FS_ITIMES(ip);
-               if (vap->va_mtime.tv_sec != VNOVAL)
+               if (vap->va_mtime.tv_nsec != VNOVAL)
                        ip->i_e2fs_mtime = vap->va_mtime.tv_sec;
-               if (vap->va_atime.tv_sec != VNOVAL)
+               if (vap->va_atime.tv_nsec != VNOVAL)
                        ip->i_e2fs_atime = vap->va_atime.tv_sec;
                error = ext2fs_update(ip, 1);
                if (error)
index 1376113..e6f543b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ufs_vnops.c,v 1.120 2015/03/14 03:38:53 jsg Exp $     */
+/*     $OpenBSD: ufs_vnops.c,v 1.121 2015/04/17 04:43:21 guenther Exp $        */
 /*     $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $   */
 
 /*
@@ -420,7 +420,9 @@ ufs_setattr(void *v)
                if (vap->va_size < oldsize)
                        hint |= NOTE_TRUNCATE;
        }
-       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+       if ((vap->va_vaflags & VA_UTIMES_CHANGE) ||
+           vap->va_atime.tv_nsec != VNOVAL ||
+           vap->va_mtime.tv_nsec != VNOVAL) {
                if (vp->v_mount->mnt_flag & MNT_RDONLY)
                        return (EROFS);
                if (cred->cr_uid != DIP(ip, uid) &&
@@ -428,19 +430,21 @@ ufs_setattr(void *v)
                    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
                    (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                        return (error);
-               if (vap->va_mtime.tv_sec != VNOVAL)
+               if (vap->va_mtime.tv_nsec != VNOVAL)
                        ip->i_flag |= IN_CHANGE | IN_UPDATE;
-               if (vap->va_atime.tv_sec != VNOVAL) {
+               else if (vap->va_vaflags & VA_UTIMES_CHANGE)
+                       ip->i_flag |= IN_CHANGE;
+               if (vap->va_atime.tv_nsec != VNOVAL) {
                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME) ||
                            (ip->i_flag & (IN_CHANGE | IN_UPDATE)))
                                ip->i_flag |= IN_ACCESS;
                }
                ufs_itimes(vp);
-               if (vap->va_mtime.tv_sec != VNOVAL) {
+               if (vap->va_mtime.tv_nsec != VNOVAL) {
                        DIP_ASSIGN(ip, mtime, vap->va_mtime.tv_sec);
                        DIP_ASSIGN(ip, mtimensec, vap->va_mtime.tv_nsec);
                }
-               if (vap->va_atime.tv_sec != VNOVAL) {
+               if (vap->va_atime.tv_nsec != VNOVAL) {
                        DIP_ASSIGN(ip, atime, vap->va_atime.tv_sec);
                        DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec);
                }