xref: /illumos-gate/usr/src/uts/common/syscall/utime.c (revision d3e55dcd)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <sys/param.h>
37 #include <sys/isa_defs.h>
38 #include <sys/types.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 extern int	namesetattr(char *, enum symfollow, vattr_t *, int);
53 extern int	fdsetattr(int, vattr_t *);
54 
55 static int
56 cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags)
57 {
58 
59 	file_t *fp;
60 	vnode_t *startvp, *vp;
61 	int error;
62 	char startchar;
63 
64 	if (fd == AT_FDCWD && fname == NULL)
65 		return (set_errno(EFAULT));
66 
67 	if (nmflag == 1 || (nmflag == 2 && fname != NULL)) {
68 		if (copyin(fname, &startchar, sizeof (char)))
69 			return (set_errno(EFAULT));
70 	} else
71 		startchar = '\0';
72 
73 	if (fd == AT_FDCWD)
74 		startvp = NULL;
75 	else {
76 
77 		/*
78 		 * is this absolute path?
79 		 */
80 		if (startchar != '/') {
81 			if ((fp = getf(fd)) == NULL) {
82 				return (set_errno(EBADF));
83 			}
84 			startvp = fp->f_vnode;
85 			VN_HOLD(startvp);
86 			releasef(fd);
87 		} else {
88 			startvp = NULL;
89 		}
90 	}
91 
92 	if (audit_active)
93 		audit_setfsat_path(1);
94 
95 	if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) {
96 		if (error = lookupnameat(fname, UIO_USERSPACE, FOLLOW,
97 		    NULLVPP, &vp, startvp)) {
98 			if (startvp != NULL)
99 				VN_RELE(startvp);
100 			return (set_errno(error));
101 		}
102 	} else {
103 		vp = startvp;
104 		VN_HOLD(vp);
105 	}
106 
107 	if (startvp != NULL) {
108 		VN_RELE(startvp);
109 	}
110 
111 	if (vn_is_readonly(vp)) {
112 		error = EROFS;
113 	} else {
114 		error = VOP_SETATTR(vp, vap, flags, CRED(), NULL);
115 	}
116 
117 	VN_RELE(vp);
118 	if (error != 0)
119 		return (set_errno(error));
120 	else
121 		return (0);
122 }
123 
124 static int
125 get_utimesvattr(struct timeval *tvptr, struct vattr *vattr, int *flags)
126 {
127 	struct timeval tv[2];
128 
129 	*flags = 0;
130 
131 	if (tvptr != NULL) {
132 		if (get_udatamodel() == DATAMODEL_NATIVE) {
133 			if (copyin(tvptr, tv, sizeof (tv)))
134 				return (EFAULT);
135 		} else {
136 			struct timeval32 tv32[2];
137 
138 			if (copyin(tvptr, tv32, sizeof (tv32)))
139 				return (EFAULT);
140 
141 			TIMEVAL32_TO_TIMEVAL(&tv[0], &tv32[0]);
142 			TIMEVAL32_TO_TIMEVAL(&tv[1], &tv32[1]);
143 		}
144 
145 		if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 ||
146 		    tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000)
147 			return (EINVAL);
148 
149 		vattr->va_atime.tv_sec = tv[0].tv_sec;
150 		vattr->va_atime.tv_nsec = tv[0].tv_usec * 1000;
151 		vattr->va_mtime.tv_sec = tv[1].tv_sec;
152 		vattr->va_mtime.tv_nsec = tv[1].tv_usec * 1000;
153 		*flags |= ATTR_UTIME;
154 	} else {
155 		gethrestime(&vattr->va_atime);
156 		vattr->va_mtime = vattr->va_atime;
157 	}
158 	vattr->va_mask = AT_ATIME | AT_MTIME;
159 
160 	return (0);
161 }
162 int
163 futimesat(int fd, char *fname, struct timeval *tvptr)
164 {
165 	struct vattr vattr;
166 	int flags = 0;
167 	int error;
168 
169 	if ((error = get_utimesvattr(tvptr, &vattr, &flags)) != 0)
170 		return (set_errno(error));
171 
172 	return (cfutimesat(fd, fname, 2, &vattr, flags));
173 }
174 /*
175  * Set access/modify times on named file.
176  */
177 int
178 utime(char *fname, time_t *tptr)
179 {
180 	time_t tv[2];
181 	struct vattr vattr;
182 	int flags = 0;
183 
184 	if (tptr != NULL) {
185 		if (get_udatamodel() == DATAMODEL_NATIVE) {
186 			if (copyin(tptr, tv, sizeof (tv)))
187 				return (set_errno(EFAULT));
188 		} else {
189 			time32_t tv32[2];
190 
191 			if (copyin(tptr, &tv32, sizeof (tv32)))
192 				return (set_errno(EFAULT));
193 
194 			tv[0] = (time_t)tv32[0];
195 			tv[1] = (time_t)tv32[1];
196 		}
197 
198 		vattr.va_atime.tv_sec = tv[0];
199 		vattr.va_atime.tv_nsec = 0;
200 		vattr.va_mtime.tv_sec = tv[1];
201 		vattr.va_mtime.tv_nsec = 0;
202 		flags |= ATTR_UTIME;
203 	} else {
204 		gethrestime(&vattr.va_atime);
205 		vattr.va_mtime = vattr.va_atime;
206 	}
207 
208 	vattr.va_mask = AT_ATIME|AT_MTIME;
209 	return (cfutimesat(AT_FDCWD, fname, 1, &vattr, flags));
210 }
211 
212 /*
213  * SunOS4.1 Buyback:
214  * Set access/modify time on named file, with hi res timer
215  */
216 int
217 utimes(char *fname, struct timeval *tvptr)
218 {
219 	struct vattr vattr;
220 	int flags = 0;
221 	int error;
222 
223 	if ((error = get_utimesvattr(tvptr, &vattr, &flags)) != 0)
224 		return (set_errno(error));
225 
226 	return (cfutimesat(AT_FDCWD, fname, 1, &vattr, flags));
227 }
228