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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/isa_defs.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/sysmacros.h> 40 #include <sys/systm.h> 41 #include <sys/errno.h> 42 #include <sys/vnode.h> 43 #include <sys/vfs.h> 44 #include <sys/time.h> 45 #include <sys/debug.h> 46 #include <sys/model.h> 47 #include <sys/fcntl.h> 48 #include <sys/file.h> 49 #include <sys/pathname.h> 50 #include <c2/audit.h> 51 52 static int 53 cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags, int follow) 54 { 55 file_t *fp; 56 vnode_t *startvp, *vp; 57 int error; 58 char startchar; 59 60 if (fd == AT_FDCWD && fname == NULL) 61 return (set_errno(EFAULT)); 62 63 if (nmflag == 1 || (nmflag == 2 && fname != NULL)) { 64 if (copyin(fname, &startchar, sizeof (char))) 65 return (set_errno(EFAULT)); 66 } else { 67 startchar = '\0'; 68 } 69 70 if (fd == AT_FDCWD) { 71 startvp = NULL; 72 } else { 73 /* 74 * is this absolute path? 75 */ 76 if (startchar != '/') { 77 if ((fp = getf(fd)) == NULL) 78 return (set_errno(EBADF)); 79 startvp = fp->f_vnode; 80 VN_HOLD(startvp); 81 releasef(fd); 82 } else { 83 startvp = NULL; 84 } 85 } 86 87 if (audit_active) 88 audit_setfsat_path(1); 89 90 if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) { 91 if ((error = lookupnameat(fname, UIO_USERSPACE, 92 follow, NULLVPP, &vp, startvp)) != 0) { 93 if (startvp != NULL) 94 VN_RELE(startvp); 95 return (set_errno(error)); 96 } 97 } else { 98 vp = startvp; 99 VN_HOLD(vp); 100 } 101 102 if (startvp != NULL) { 103 VN_RELE(startvp); 104 } 105 106 if (vn_is_readonly(vp)) { 107 error = EROFS; 108 } else { 109 error = VOP_SETATTR(vp, vap, flags, CRED(), NULL); 110 } 111 112 VN_RELE(vp); 113 if (error != 0) 114 return (set_errno(error)); 115 return (0); 116 } 117 118 /* 119 * Expunge this function when futimesat() and utimes() 120 * are expunged from the kernel. 121 */ 122 static int 123 get_timeval_vattr(struct timeval *tvptr, struct vattr *vattr, int *flags) 124 { 125 struct timeval tv[2]; 126 127 if (tvptr != NULL) { 128 if (get_udatamodel() == DATAMODEL_NATIVE) { 129 if (copyin(tvptr, tv, sizeof (tv))) 130 return (EFAULT); 131 } else { 132 struct timeval32 tv32[2]; 133 134 if (copyin(tvptr, tv32, sizeof (tv32))) 135 return (EFAULT); 136 137 TIMEVAL32_TO_TIMEVAL(&tv[0], &tv32[0]); 138 TIMEVAL32_TO_TIMEVAL(&tv[1], &tv32[1]); 139 } 140 141 if (tv[0].tv_usec < 0 || tv[0].tv_usec >= MICROSEC || 142 tv[1].tv_usec < 0 || tv[1].tv_usec >= MICROSEC) 143 return (EINVAL); 144 145 vattr->va_atime.tv_sec = tv[0].tv_sec; 146 vattr->va_atime.tv_nsec = tv[0].tv_usec * 1000; 147 vattr->va_mtime.tv_sec = tv[1].tv_sec; 148 vattr->va_mtime.tv_nsec = tv[1].tv_usec * 1000; 149 *flags = ATTR_UTIME; 150 } else { 151 gethrestime(&vattr->va_atime); 152 vattr->va_mtime = vattr->va_atime; 153 *flags = 0; 154 } 155 vattr->va_mask = AT_ATIME | AT_MTIME; 156 157 return (0); 158 } 159 160 static int 161 get_timespec_vattr(timespec_t *tsptr, struct vattr *vattr, int *flags) 162 { 163 timespec_t ts[2]; 164 timespec_t now; 165 uint_t mask; 166 167 if (tsptr != NULL) { 168 if (get_udatamodel() == DATAMODEL_NATIVE) { 169 if (copyin(tsptr, ts, sizeof (ts))) 170 return (EFAULT); 171 } else { 172 timespec32_t ts32[2]; 173 174 if (copyin(tsptr, ts32, sizeof (ts32))) 175 return (EFAULT); 176 TIMESPEC32_TO_TIMESPEC(&ts[0], &ts32[0]); 177 TIMESPEC32_TO_TIMESPEC(&ts[1], &ts32[1]); 178 } 179 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) 180 gethrestime(&now); 181 mask = 0; 182 if (ts[0].tv_nsec == UTIME_OMIT) { 183 ts[0].tv_nsec = 0; 184 } else { 185 mask |= AT_ATIME; 186 if (ts[0].tv_nsec == UTIME_NOW) 187 ts[0] = now; 188 else if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= NANOSEC) 189 return (EINVAL); 190 } 191 if (ts[1].tv_nsec == UTIME_OMIT) { 192 ts[1].tv_nsec = 0; 193 } else { 194 mask |= AT_MTIME; 195 if (ts[1].tv_nsec == UTIME_NOW) 196 ts[1] = now; 197 else if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= NANOSEC) 198 return (EINVAL); 199 } 200 vattr->va_atime = ts[0]; 201 vattr->va_mtime = ts[1]; 202 vattr->va_mask = mask; 203 *flags = ATTR_UTIME; 204 } else { 205 gethrestime(&now); 206 vattr->va_atime = now; 207 vattr->va_mtime = now; 208 vattr->va_mask = AT_ATIME | AT_MTIME; 209 *flags = 0; 210 } 211 212 return (0); 213 } 214 215 /* 216 * The futimesat() system call is no longer invoked from libc. 217 * The futimesat() function has been implemented in libc using calls 218 * to futimens() and utimensat(). The kernel code for futimesat() 219 * should be expunged as soon as there is no longer a need 220 * to run Solaris 10 and prior versions of libc on the system. 221 * This includes the calls to futimesat in common/syscall/fsat.c 222 */ 223 int 224 futimesat(int fd, char *fname, struct timeval *tvptr) 225 { 226 struct vattr vattr; 227 int flags; 228 int error; 229 230 if ((error = get_timeval_vattr(tvptr, &vattr, &flags)) != 0) 231 return (set_errno(error)); 232 233 return (cfutimesat(fd, fname, 2, &vattr, flags, FOLLOW)); 234 } 235 236 /* 237 * The utime() system call is no longer invoked from libc. 238 * The utime() function has been implemented in libc using 239 * a call to utimensat(). The kernel code for utime() 240 * should be expunged as soon as there is no longer a need 241 * to run Solaris 10 and prior versions of libc on the system. 242 */ 243 int 244 utime(char *fname, time_t *tptr) 245 { 246 time_t tv[2]; 247 struct vattr vattr; 248 int flags; 249 250 if (tptr != NULL) { 251 if (get_udatamodel() == DATAMODEL_NATIVE) { 252 if (copyin(tptr, tv, sizeof (tv))) 253 return (set_errno(EFAULT)); 254 } else { 255 time32_t tv32[2]; 256 257 if (copyin(tptr, &tv32, sizeof (tv32))) 258 return (set_errno(EFAULT)); 259 260 tv[0] = (time_t)tv32[0]; 261 tv[1] = (time_t)tv32[1]; 262 } 263 264 vattr.va_atime.tv_sec = tv[0]; 265 vattr.va_atime.tv_nsec = 0; 266 vattr.va_mtime.tv_sec = tv[1]; 267 vattr.va_mtime.tv_nsec = 0; 268 flags = ATTR_UTIME; 269 } else { 270 gethrestime(&vattr.va_atime); 271 vattr.va_mtime = vattr.va_atime; 272 flags = 0; 273 } 274 275 vattr.va_mask = AT_ATIME|AT_MTIME; 276 return (cfutimesat(AT_FDCWD, fname, 1, &vattr, flags, FOLLOW)); 277 } 278 279 /* 280 * The utimes() system call is no longer invoked from libc. 281 * The utimes() function has been implemented in libc using 282 * a call to utimensat(). The kernel code for utimes() 283 * should be expunged as soon as there is no longer a need 284 * to run Solaris 10 and prior versions of libc on the system. 285 */ 286 int 287 utimes(char *fname, struct timeval *tvptr) 288 { 289 struct vattr vattr; 290 int flags; 291 int error; 292 293 if ((error = get_timeval_vattr(tvptr, &vattr, &flags)) != 0) 294 return (set_errno(error)); 295 296 return (cfutimesat(AT_FDCWD, fname, 1, &vattr, flags, FOLLOW)); 297 } 298 299 int 300 futimens(int fd, timespec_t *tsptr) 301 { 302 struct vattr vattr; 303 int flags; 304 int error; 305 306 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 307 return (set_errno(error)); 308 309 return (cfutimesat(fd, NULL, 2, &vattr, flags, FOLLOW)); 310 } 311 312 int 313 utimensat(int fd, char *fname, timespec_t *tsptr, int flag) 314 { 315 struct vattr vattr; 316 int flags; 317 int error; 318 319 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 320 return (set_errno(error)); 321 322 return (cfutimesat(fd, fname, 1, &vattr, flags, 323 (flag & AT_SYMLINK_NOFOLLOW)? NO_FOLLOW : FOLLOW)); 324 } 325 326 int 327 utimesys(int code, 328 uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) 329 { 330 switch (code) { 331 case 0: 332 return (futimens((int)arg1, (timespec_t *)arg2)); 333 case 1: 334 return (utimensat((int)arg1, (char *)arg2, 335 (timespec_t *)arg3, (int)arg4)); 336 default: 337 return (set_errno(EINVAL)); 338 } 339 } 340