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 (AU_AUDITING() && (startvp != NULL)) 87 audit_setfsat_path(1); 88 89 if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) { 90 if ((error = lookupnameat(fname, UIO_USERSPACE, 91 follow, NULLVPP, &vp, startvp)) != 0) { 92 if (startvp != NULL) 93 VN_RELE(startvp); 94 return (set_errno(error)); 95 } 96 } else { 97 vp = startvp; 98 VN_HOLD(vp); 99 } 100 101 if (startvp != NULL) { 102 VN_RELE(startvp); 103 } 104 105 if (vn_is_readonly(vp)) { 106 error = EROFS; 107 } else { 108 error = VOP_SETATTR(vp, vap, flags, CRED(), NULL); 109 } 110 111 VN_RELE(vp); 112 if (error != 0) 113 return (set_errno(error)); 114 return (0); 115 } 116 117 static int 118 get_timespec_vattr(timespec_t *tsptr, struct vattr *vattr, int *flags) 119 { 120 timespec_t ts[2]; 121 timespec_t now; 122 uint_t mask; 123 124 if (tsptr != NULL) { 125 if (get_udatamodel() == DATAMODEL_NATIVE) { 126 if (copyin(tsptr, ts, sizeof (ts))) 127 return (EFAULT); 128 } else { 129 timespec32_t ts32[2]; 130 131 if (copyin(tsptr, ts32, sizeof (ts32))) 132 return (EFAULT); 133 TIMESPEC32_TO_TIMESPEC(&ts[0], &ts32[0]); 134 TIMESPEC32_TO_TIMESPEC(&ts[1], &ts32[1]); 135 } 136 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) 137 gethrestime(&now); 138 mask = 0; 139 if (ts[0].tv_nsec == UTIME_OMIT) { 140 ts[0].tv_nsec = 0; 141 } else { 142 mask |= AT_ATIME; 143 if (ts[0].tv_nsec == UTIME_NOW) 144 ts[0] = now; 145 else if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= NANOSEC) 146 return (EINVAL); 147 } 148 if (ts[1].tv_nsec == UTIME_OMIT) { 149 ts[1].tv_nsec = 0; 150 } else { 151 mask |= AT_MTIME; 152 if (ts[1].tv_nsec == UTIME_NOW) 153 ts[1] = now; 154 else if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= NANOSEC) 155 return (EINVAL); 156 } 157 vattr->va_atime = ts[0]; 158 vattr->va_mtime = ts[1]; 159 vattr->va_mask = mask; 160 *flags = ATTR_UTIME; 161 } else { 162 gethrestime(&now); 163 vattr->va_atime = now; 164 vattr->va_mtime = now; 165 vattr->va_mask = AT_ATIME | AT_MTIME; 166 *flags = 0; 167 } 168 169 return (0); 170 } 171 172 int 173 futimens(int fd, timespec_t *tsptr) 174 { 175 struct vattr vattr; 176 int flags; 177 int error; 178 179 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 180 return (set_errno(error)); 181 182 return (cfutimesat(fd, NULL, 2, &vattr, flags, FOLLOW)); 183 } 184 185 int 186 utimensat(int fd, char *fname, timespec_t *tsptr, int flag) 187 { 188 struct vattr vattr; 189 int flags; 190 int error; 191 192 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0) 193 return (set_errno(error)); 194 195 return (cfutimesat(fd, fname, 1, &vattr, flags, 196 (flag & AT_SYMLINK_NOFOLLOW)? NO_FOLLOW : FOLLOW)); 197 } 198 199 int 200 utimesys(int code, 201 uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) 202 { 203 switch (code) { 204 case 0: 205 return (futimens((int)arg1, (timespec_t *)arg2)); 206 case 1: 207 return (utimensat((int)arg1, (char *)arg2, 208 (timespec_t *)arg3, (int)arg4)); 209 default: 210 return (set_errno(EINVAL)); 211 } 212 } 213