diff options
author | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-07-18 00:16:55 +0000 |
---|---|---|
committer | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-07-18 00:16:55 +0000 |
commit | acae39e1405d6fa9f4948ab6d08831294fb269d6 (patch) | |
tree | 1450eaf0cbe54ea09593312e9138050fbe928aa2 /sys | |
parent | 4af128e42b8c175ba7fbcbffba789a4b05701fb1 (diff) |
Add support for UTIME_OMIT and UTIME_NOW to utimensat(2), add the
futimens(2) system call, and refactor futimes(2) to share the same
code. (As with other openat(2) system call stuff, this is not exposed
to userland yet.)
naddy@ pointed out rsync expects UTIME_* if openat(2) is available
tweaks and ok guenther@; tested by naddy@ in a bulk build
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/syscalls.master | 4 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 166 | ||||
-rw-r--r-- | sys/sys/stat.h | 9 |
3 files changed, 113 insertions, 66 deletions
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 66f9d910907..cd4a7899bcb 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.117 2011/07/09 05:46:26 matthew Exp $ +; $OpenBSD: syscalls.master,v 1.118 2011/07/18 00:16:54 matthew Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -572,3 +572,5 @@ int flag); } 326 STD { int sys_utimensat(int fd, const char *path, \ const struct timespec *times, int flag); } +327 STD { int sys_futimens(int fd, \ + const struct timespec *times); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 933e9b00774..a2b46d8b872 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.176 2011/07/14 18:03:06 matthew Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.177 2011/07/18 00:16:54 matthew Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -90,8 +90,11 @@ int dofchownat(struct proc *, int, const char *, uid_t, gid_t, int, int dorenameat(struct proc *, int, const char *, int, const char *, register_t *); int domkdirat(struct proc *, int, const char *, mode_t, register_t *); -int doutimensat(struct proc *, int, const char *, const struct timeval *, +int doutimensat(struct proc *, int, const char *, struct timespec [2], int, register_t *); +int dovutimens(struct proc *, struct vnode *, struct timespec [2], + register_t *); +int dofutimens(struct proc *, int, struct timespec [2], register_t *); /* * Virtual File System System Calls @@ -2211,6 +2214,7 @@ sys_utimes(struct proc *p, void *v, register_t *retval) syscallarg(const struct timeval *) tptr; } */ *uap = v; + struct timespec ts[2]; struct timeval tv[2]; const struct timeval *tvp; int error; @@ -2220,10 +2224,12 @@ sys_utimes(struct proc *p, void *v, register_t *retval) error = copyin(tvp, tv, sizeof(tv)); if (error) return (error); - tvp = tv; - } + TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]); + TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]); + } else + ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; - return (doutimensat(p, AT_FDCWD, SCARG(uap, path), tvp, 0, retval)); + return (doutimensat(p, AT_FDCWD, SCARG(uap, path), ts, 0, retval)); } int @@ -2236,9 +2242,7 @@ sys_utimensat(struct proc *p, void *v, register_t *retval) syscallarg(int) flag; } */ *uap = v; - struct timeval tv[2]; struct timespec ts[2]; - const struct timeval *tvp = NULL; const struct timespec *tsp; int error; @@ -2247,56 +2251,74 @@ sys_utimensat(struct proc *p, void *v, register_t *retval) error = copyin(tsp, ts, sizeof(ts)); if (error) return (error); - tv[0].tv_sec = ts[0].tv_sec; - tv[0].tv_usec = ts[0].tv_nsec / 1000; - tv[1].tv_sec = ts[1].tv_sec; - tv[1].tv_usec = ts[1].tv_nsec / 1000; - tvp = tv; - } + } else + ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; - return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), tvp, + return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), ts, SCARG(uap, flag), retval)); } int doutimensat(struct proc *p, int fd, const char *path, - const struct timeval *tvp, int flag, register_t *retval) + struct timespec ts[2], int flag, register_t *retval) { struct vnode *vp; - struct timeval tv[2]; - struct vattr vattr; int error, follow; struct nameidata nd; if (flag & ~AT_SYMLINK_NOFOLLOW) return (EINVAL); - VATTR_NULL(&vattr); - if (tvp == NULL) { - getmicrotime(&tv[0]); - tv[1] = tv[0]; - vattr.va_vaflags |= VA_UTIMES_NULL; - } else { - bcopy(tvp, tv, sizeof(tv)); - /* XXX workaround timeval matching the VFS constant VNOVAL */ - if (tv[0].tv_sec == VNOVAL) - tv[0].tv_sec = VNOVAL - 1; - if (tv[1].tv_sec == VNOVAL) - tv[1].tv_sec = VNOVAL - 1; - } follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; + + return (dovutimens(p, vp, ts, retval)); +} + +int +dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2], + register_t *retval) +{ + struct vattr vattr; + struct timespec now; + int error; + + VATTR_NULL(&vattr); + 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; + + getnanotime(&now); + if (ts[0].tv_nsec == UTIME_NOW) + ts[0] = now; + if (ts[1].tv_nsec == UTIME_NOW) + 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; + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else { - vattr.va_atime.tv_sec = tv[0].tv_sec; - vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; - vattr.va_mtime.tv_sec = tv[1].tv_sec; - vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; + vattr.va_atime = ts[0]; + vattr.va_mtime = ts[1]; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); @@ -2314,44 +2336,60 @@ sys_futimes(struct proc *p, void *v, register_t *retval) syscallarg(int) fd; syscallarg(const struct timeval *) tptr; } */ *uap = v; - struct vnode *vp; struct timeval tv[2]; - struct vattr vattr; + struct timespec ts[2]; + const struct timeval *tvp; int error; - struct file *fp; - VATTR_NULL(&vattr); - if (SCARG(uap, tptr) == NULL) { - getmicrotime(&tv[0]); - tv[1] = tv[0]; - vattr.va_vaflags |= VA_UTIMES_NULL; - } else { - error = copyin(SCARG(uap, tptr), tv, - sizeof(tv)); + tvp = SCARG(uap, tptr); + if (tvp != NULL) { + error = copyin(tvp, tv, sizeof(tv)); if (error) return (error); - /* XXX workaround timeval matching the VFS constant VNOVAL */ - if (tv[0].tv_sec == VNOVAL) - tv[0].tv_sec = VNOVAL - 1; - if (tv[1].tv_sec == VNOVAL) - tv[1].tv_sec = VNOVAL - 1; - } - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]); + TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]); + } else + ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; + + return (dofutimens(p, SCARG(uap, fd), ts, retval)); +} + +int +sys_futimens(struct proc *p, void *v, register_t *retval) +{ + struct sys_futimens_args /* { + syscallarg(int) fd; + syscallarg(const struct timespec *) times; + } */ *uap = v; + struct timespec ts[2]; + const struct timespec *tsp; + int error; + + tsp = SCARG(uap, times); + if (tsp != NULL) { + error = copyin(tsp, ts, sizeof(ts)); + if (error) + return (error); + } else + ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; + + return (dofutimens(p, SCARG(uap, fd), ts, retval)); +} + +int +dofutimens(struct proc *p, int fd, struct timespec ts[2], register_t *retval) +{ + struct file *fp; + struct vnode *vp; + int error; + + if ((error = getvnode(p->p_fd, fd, &fp)) != 0) return (error); vp = (struct vnode *)fp->f_data; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY) - error = EROFS; - else { - vattr.va_atime.tv_sec = tv[0].tv_sec; - vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; - vattr.va_mtime.tv_sec = tv[1].tv_sec; - vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - } - VOP_UNLOCK(vp, 0, p); + vref(vp); FRELE(fp); - return (error); + + return (dovutimens(p, vp, ts, retval)); } /* diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 1209dd0b3c3..aceb59d2f3a 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: stat.h,v 1.18 2011/07/14 23:34:37 matthew Exp $ */ +/* $OpenBSD: stat.h,v 1.19 2011/07/18 00:16:54 matthew Exp $ */ /* $NetBSD: stat.h,v 1.20 1996/05/16 22:17:49 cgd Exp $ */ /*- @@ -181,6 +181,13 @@ struct stat { #endif /* _KERNEL */ #endif /* __BSD_VISIBLE */ +#ifdef _KERNEL /* XXX */ +#if __POSIX_VISIBLE >= 200809 +#define UTIME_NOW -2L +#define UTIME_OMIT -1L +#endif /* __POSIX_VISIBLE */ +#endif + #ifndef _KERNEL __BEGIN_DECLS int chmod(const char *, mode_t); |