1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/isa_defs.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/sysmacros.h> 39 #include <sys/systm.h> 40 #include <sys/errno.h> 41 #include <sys/vnode.h> 42 #include <sys/vfs.h> 43 #include <sys/time.h> 44 #include <sys/debug.h> 45 #include <sys/model.h> 46 #include <sys/fcntl.h> 47 #include <sys/file.h> 48 #include <sys/pathname.h> 49 #include <c2/audit.h> 50 51 static int 52 cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags, int follow) 53 { 54 file_t *fp; 55 vnode_t *startvp, *vp; 56 int error; 57 char startchar; 58 59 if (fd == AT_FDCWD && fname == NULL) 60 return (set_errno(EFAULT)); 61 62 if (nmflag == 1 || (nmflag == 2 && fname != NULL)) { 63 if (copyin(fname, &startchar, sizeof (char))) 64 return (set_errno(EFAULT)); 65 } else { 66 startchar = '\0'; 67 } 68 69 if (fd == AT_FDCWD) { 70 startvp = NULL; 71 } else { 72 /* 73 * is this absolute path? 74 */ 75 if (startchar != '/') { 76 if ((fp = getf(fd)) == NULL) 77 return (set_errno(EBADF)); 78 startvp = fp->f_vnode; 79 VN_HOLD(startvp); 80 releasef(fd); 81 } else { 82 startvp = NULL; 83 } 84 } 85 86 if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) { 87 if (AU_AUDITING() && startvp != NULL) 88 audit_setfsat_path(1); 89 if ((error = lookupnameat(fname, UIO_USERSPACE, 90 follow, NULLVPP, &vp, startvp)) != 0) { 91 if (startvp != NULL) 92 VN_RELE(startvp); 93 return (set_errno(error)); 94 } 95 } else { 96 vp = startvp; 97 VN_HOLD(vp); 98 } 99 100 if (startvp != NULL) { 101 VN_RELE(startvp); 102 } 103 104 if (vn_is_readonly(vp)) { 105 error = EROFS; 106 } else { 107 error = VOP_SETATTR(vp, vap, flags, CRED(), NULL); 108 } 109 110 VN_RELE(vp); 111 if (error != 0) 112 return (set_errno(error)); 113 return (0); 114 } 115 116 static int 117 get_timespec_vattr(timespec_t *tsptr, struct vattr *vattr, int *flags) 118 { 119 timespec_t ts[2]; 120 timespec_t now; 121 uint_t mask; 122 123 if (tsptr != NULL) { 124 if (get_udatamodel() == DATAMODEL_NATIVE) { 125 if (copyin(tsptr, ts, sizeof (ts))) 126 return (EFAULT); 127 } else { 128 timespec32_t ts32[2]; 129 130 if (copyin(tsptr, ts32, sizeof (ts32))) 131 return (EFAULT); 132 TIMESPEC32_TO_TIMESPEC(&ts[0], &ts32[0]); 133 TIMESPEC32_TO_TIMESPEC(&ts[1], &ts32[1]); 134 } 135 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) 136 gethrestime(&now); 137 mask = 0; 138 if (ts[0].tv_nsec == UTIME_OMIT) { 139 ts[0].tv_nsec = 0; 140 } else { 141 mask |= AT_ATIME; 142 if (ts[0].tv_nsec == UTIME_NOW) 143 ts[0] = now; 144 else if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= NANOSEC) 145 return (EINVAL); 146 } 147 if (ts[1].tv_nsec == UTIME_OMIT) { 148 ts[1].tv_nsec = 0; 149 } else { 150 mask |= AT_MTIME; 151 if (ts[1].tv_nsec == UTIME_NOW) 152 ts[1] = now; 153 else if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= NANOSEC) 154 return (EINVAL); 155 } 156 vattr->va_atime = ts[0]; 157 vattr->va_mtime = ts[1]; 158 vattr->va_mask = mask; 159 *flags = ATTR_UTIME; 160 } else { 161 gethrestime(&now); 162 vattr->va_atime = now; 163 vattr->va_mtime = now; 164 vattr->va_mask = AT_ATIME | AT_MTIME; 165 *flags = 0; 166 } 167 168 return (0); 169 } 170 171 int 172 futimens(int fd, timespec_t *tsptr) 173 { 174 struct vattr vattr; 175 int flags; 176 int error; 177 178 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 179 return (set_errno(error)); 180 181 return (cfutimesat(fd, NULL, 2, &vattr, flags, FOLLOW)); 182 } 183 184 int 185 utimensat(int fd, char *fname, timespec_t *tsptr, int flag) 186 { 187 struct vattr vattr; 188 int flags; 189 int error; 190 191 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 192 return (set_errno(error)); 193 194 return (cfutimesat(fd, fname, 1, &vattr, flags, 195 (flag & AT_SYMLINK_NOFOLLOW)? NO_FOLLOW : FOLLOW)); 196 } 197 198 int 199 utimesys(int code, 200 uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) 201 { 202 switch (code) { 203 case 0: 204 return (futimens((int)arg1, (timespec_t *)arg2)); 205 case 1: 206 return (utimensat((int)arg1, (char *)arg2, 207 (timespec_t *)arg3, (int)arg4)); 208 default: 209 return (set_errno(EINVAL)); 210 } 211 } 212