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 2010 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 (AU_AUDITING()) 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 static int 119 get_timespec_vattr(timespec_t *tsptr, struct vattr *vattr, int *flags) 120 { 121 timespec_t ts[2]; 122 timespec_t now; 123 uint_t mask; 124 125 if (tsptr != NULL) { 126 if (get_udatamodel() == DATAMODEL_NATIVE) { 127 if (copyin(tsptr, ts, sizeof (ts))) 128 return (EFAULT); 129 } else { 130 timespec32_t ts32[2]; 131 132 if (copyin(tsptr, ts32, sizeof (ts32))) 133 return (EFAULT); 134 TIMESPEC32_TO_TIMESPEC(&ts[0], &ts32[0]); 135 TIMESPEC32_TO_TIMESPEC(&ts[1], &ts32[1]); 136 } 137 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) 138 gethrestime(&now); 139 mask = 0; 140 if (ts[0].tv_nsec == UTIME_OMIT) { 141 ts[0].tv_nsec = 0; 142 } else { 143 mask |= AT_ATIME; 144 if (ts[0].tv_nsec == UTIME_NOW) 145 ts[0] = now; 146 else if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= NANOSEC) 147 return (EINVAL); 148 } 149 if (ts[1].tv_nsec == UTIME_OMIT) { 150 ts[1].tv_nsec = 0; 151 } else { 152 mask |= AT_MTIME; 153 if (ts[1].tv_nsec == UTIME_NOW) 154 ts[1] = now; 155 else if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= NANOSEC) 156 return (EINVAL); 157 } 158 vattr->va_atime = ts[0]; 159 vattr->va_mtime = ts[1]; 160 vattr->va_mask = mask; 161 *flags = ATTR_UTIME; 162 } else { 163 gethrestime(&now); 164 vattr->va_atime = now; 165 vattr->va_mtime = now; 166 vattr->va_mask = AT_ATIME | AT_MTIME; 167 *flags = 0; 168 } 169 170 return (0); 171 } 172 173 int 174 futimens(int fd, timespec_t *tsptr) 175 { 176 struct vattr vattr; 177 int flags; 178 int error; 179 180 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 181 return (set_errno(error)); 182 183 return (cfutimesat(fd, NULL, 2, &vattr, flags, FOLLOW)); 184 } 185 186 int 187 utimensat(int fd, char *fname, timespec_t *tsptr, int flag) 188 { 189 struct vattr vattr; 190 int flags; 191 int error; 192 193 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 194 return (set_errno(error)); 195 196 return (cfutimesat(fd, fname, 1, &vattr, flags, 197 (flag & AT_SYMLINK_NOFOLLOW)? NO_FOLLOW : FOLLOW)); 198 } 199 200 int 201 utimesys(int code, 202 uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) 203 { 204 switch (code) { 205 case 0: 206 return (futimens((int)arg1, (timespec_t *)arg2)); 207 case 1: 208 return (utimensat((int)arg1, (char *)arg2, 209 (timespec_t *)arg3, (int)arg4)); 210 default: 211 return (set_errno(EINVAL)); 212 } 213 } 214