diff options
-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); |