Merge illumos-gate
[unleashed.git] / kernel / syscall / utime.c
blob0633e5ca92a8b89534ff35a430fff5b41e6f58e9
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
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>
50 static int
51 cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags, int follow)
53 file_t *fp;
54 vnode_t *startvp, *vp;
55 int error;
56 char startchar;
58 if (fd == AT_FDCWD && fname == NULL)
59 return (set_errno(EFAULT));
61 if (nmflag == 1 || (nmflag == 2 && fname != NULL)) {
62 if (copyin(fname, &startchar, sizeof (char)))
63 return (set_errno(EFAULT));
64 } else {
65 startchar = '\0';
68 if (fd == AT_FDCWD) {
69 startvp = NULL;
70 } else {
72 * is this absolute path?
74 if (startchar != '/') {
75 if ((fp = getf(fd)) == NULL)
76 return (set_errno(EBADF));
77 startvp = fp->f_vnode;
78 VN_HOLD(startvp);
79 releasef(fd);
80 } else {
81 startvp = NULL;
85 if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) {
86 if ((error = lookupnameat(fname, UIO_USERSPACE,
87 follow, NULLVPP, &vp, startvp)) != 0) {
88 if (startvp != NULL)
89 VN_RELE(startvp);
90 return (set_errno(error));
92 } else {
93 vp = startvp;
94 VN_HOLD(vp);
97 if (startvp != NULL) {
98 VN_RELE(startvp);
101 if (vn_is_readonly(vp)) {
102 error = EROFS;
103 } else {
104 error = fop_setattr(vp, vap, flags, CRED(), NULL);
107 VN_RELE(vp);
108 if (error != 0)
109 return (set_errno(error));
110 return (0);
113 static int
114 get_timespec_vattr(timespec_t *tsptr, struct vattr *vattr, int *flags)
116 timespec_t ts[2];
117 timespec_t now;
118 uint_t mask;
120 if (tsptr != NULL) {
121 if (get_udatamodel() == DATAMODEL_NATIVE) {
122 if (copyin(tsptr, ts, sizeof (ts)))
123 return (EFAULT);
124 } else {
125 timespec32_t ts32[2];
127 if (copyin(tsptr, ts32, sizeof (ts32)))
128 return (EFAULT);
129 TIMESPEC32_TO_TIMESPEC(&ts[0], &ts32[0]);
130 TIMESPEC32_TO_TIMESPEC(&ts[1], &ts32[1]);
132 if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
133 gethrestime(&now);
134 mask = 0;
135 if (ts[0].tv_nsec == UTIME_OMIT) {
136 ts[0].tv_nsec = 0;
137 } else {
138 mask |= VATTR_ATIME;
139 if (ts[0].tv_nsec == UTIME_NOW)
140 ts[0] = now;
141 else if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= NANOSEC)
142 return (EINVAL);
144 if (ts[1].tv_nsec == UTIME_OMIT) {
145 ts[1].tv_nsec = 0;
146 } else {
147 mask |= VATTR_MTIME;
148 if (ts[1].tv_nsec == UTIME_NOW)
149 ts[1] = now;
150 else if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= NANOSEC)
151 return (EINVAL);
153 vattr->va_atime = ts[0];
154 vattr->va_mtime = ts[1];
155 vattr->va_mask = mask;
156 *flags = ATTR_UTIME;
157 } else {
158 gethrestime(&now);
159 vattr->va_atime = now;
160 vattr->va_mtime = now;
161 vattr->va_mask = VATTR_ATIME | VATTR_MTIME;
162 *flags = 0;
165 return (0);
169 futimens(int fd, timespec_t *tsptr)
171 struct vattr vattr;
172 int flags;
173 int error;
175 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0)
176 return (set_errno(error));
178 return (cfutimesat(fd, NULL, 2, &vattr, flags, FOLLOW));
182 utimensat(int fd, char *fname, timespec_t *tsptr, int flag)
184 struct vattr vattr;
185 int flags;
186 int error;
188 if ((error = get_timespec_vattr(tsptr, &vattr, &flags)) != 0)
189 return (set_errno(error));
191 return (cfutimesat(fd, fname, 1, &vattr, flags,
192 (flag & AT_SYMLINK_NOFOLLOW)? NO_FOLLOW : FOLLOW));
196 utimesys(int code,
197 uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
199 switch (code) {
200 case 0:
201 return (futimens((int)arg1, (timespec_t *)arg2));
202 case 1:
203 return (utimensat((int)arg1, (char *)arg2,
204 (timespec_t *)arg3, (int)arg4));
205 default:
206 return (set_errno(EINVAL));