-.\" $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
.\"
.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
.\"
-.Dd $Mdocdate: February 27 2015 $
+.Dd $Mdocdate: April 17 2015 $
.Dt UTIMES 2
.Os
.Sh NAME
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
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.
-/* $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 $ */
/*-
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) {
-/* $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 $ */
/*
#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;
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);
}
-/* $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>
*
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;
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;
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) {
-/* $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 $ */
/*-
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 &&
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);
-/* $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 $ */
/*
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);
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);
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;
};
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;
};
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);
+ }
+}
-/* $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 $ */
/*
* 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) {
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)
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)
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;
-/* $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); \
-/* $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 $ */
/*
/*
* 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) */
/*
* 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.
*/
-/* $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 $ */
/*
(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;
}
-/* $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 $ */
/*
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
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;
}
-/* $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 $ */
/*
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 &&
((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)
-/* $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 $ */
/*
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) &&
((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);
}