xref: /titanic_51/usr/src/lib/libast/common/tm/tvtouch.c (revision e71ca95ca6de23d33b54cb55cefdef30bc7c969b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * Tv_t conversion support
28  */
29 
30 #if defined(__STDPP__directive) && defined(__STDPP__hide)
31 __STDPP__directive pragma pp:hide utime
32 #else
33 #define utime		______utime
34 #endif
35 
36 #ifndef _ATFILE_SOURCE
37 #define _ATFILE_SOURCE	1
38 #endif
39 
40 #include <ast.h>
41 #include <ls.h>
42 #include <tv.h>
43 #include <times.h>
44 #include <error.h>
45 
46 #include "FEATURE/tvlib"
47 
48 #if _hdr_utime && _lib_utime
49 #include <utime.h>
50 #endif
51 
52 #if defined(__STDPP__directive) && defined(__STDPP__hide)
53 __STDPP__directive pragma pp:nohide utime
54 #else
55 #undef	utime
56 #endif
57 
58 #if _lib_utime
59 #if _hdr_utime
60 extern int	utime(const char*, const struct utimbuf*);
61 #else
62 extern int	utime(const char*, const time_t*);
63 #endif
64 #endif
65 
66 #define NS(n)		(((uint32_t)(n))<1000000000L?(n):0)
67 
68 /*
69  * touch path <atime,mtime,ctime>
70  * Tv_t==0 uses current time
71  * Tv_t==TV_TOUCH_RETAIN retains path value if it exists, current time otherwise
72  * otherwise it is exact time
73  * file created if it doesn't exist and (flags&1)
74  * symlink not followed if (flags&2)
75  * cv most likely ignored on most implementations
76  *
77  * NOTE: when *at() calls are integrated we need macros for the flags!
78  */
79 
80 int
81 tvtouch(const char* path, register const Tv_t* av, register const Tv_t* mv, const Tv_t* cv, int flags)
82 {
83 	int		fd;
84 	int		mode;
85 	int		oerrno;
86 	struct stat	st;
87 
88 #if _lib_utimensat
89 	struct timespec	ts[2];
90 
91 	errno = oerrno;
92 	if (!av)
93 	{
94 		ts[0].tv_sec = 0;
95 		ts[0].tv_nsec = UTIME_NOW;
96 	}
97 	else if (av == TV_TOUCH_RETAIN)
98 	{
99 		ts[0].tv_sec = 0;
100 		ts[0].tv_nsec = UTIME_OMIT;
101 	}
102 	else
103 	{
104 		ts[0].tv_sec = av->tv_sec;
105 		ts[0].tv_nsec = NS(av->tv_nsec);
106 	}
107 	if (!mv)
108 	{
109 		ts[1].tv_sec = 0;
110 		ts[1].tv_nsec = UTIME_NOW;
111 	}
112 	else if (mv == TV_TOUCH_RETAIN)
113 	{
114 		ts[1].tv_sec = 0;
115 		ts[1].tv_nsec = UTIME_OMIT;
116 	}
117 	else
118 	{
119 		ts[1].tv_sec = mv->tv_sec;
120 		ts[1].tv_nsec = NS(mv->tv_nsec);
121 	}
122 	if (!cv && av == TV_TOUCH_RETAIN && mv == TV_TOUCH_RETAIN && !stat(path, &st) && !chmod(path, st.st_mode & S_IPERM))
123 		return 0;
124 	if (!utimensat(AT_FDCWD, path, ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW ? (struct timespec*)0 : ts, (flags & 2) ? AT_SYMLINK_NOFOLLOW : 0))
125 		return 0;
126 	if (errno != ENOENT || !(flags & 1))
127 		return -1;
128 	umask(mode = umask(0));
129 	mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
130 	if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
131 		return -1;
132 	close(fd);
133 	errno = oerrno;
134 	if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) && utimensat(AT_FDCWD, path, ts, (flags & 2) ? AT_SYMLINK_NOFOLLOW : 0))
135 		return -1;
136 	return 0;
137 #else
138 	Tv_t		now;
139 #if _lib_utimets
140 	struct timespec	am[2];
141 #else
142 #if _lib_utimes
143 	struct timeval	am[2];
144 #else
145 #if _hdr_utime
146 	struct utimbuf	am;
147 #else
148 	time_t		am[2];
149 #endif
150 #endif
151 #endif
152 
153 	oerrno = errno;
154 	if ((av == TV_TOUCH_RETAIN || mv == TV_TOUCH_RETAIN) && stat(path, &st))
155 	{
156 		errno = oerrno;
157 		if (av == TV_TOUCH_RETAIN)
158 			av = 0;
159 		if (mv == TV_TOUCH_RETAIN)
160 			mv = 0;
161 	}
162 	if (!av || !mv)
163 	{
164 		tvgettime(&now);
165 		if (!av)
166 			av = (const Tv_t*)&now;
167 		if (!mv)
168 			mv = (const Tv_t*)&now;
169 	}
170 #if _lib_utimets
171 	if (av == TV_TOUCH_RETAIN)
172 	{
173 		am[0].tv_sec = st.st_atime;
174 		am[0].tv_nsec = ST_ATIME_NSEC_GET(&st);
175 	}
176 	else
177 	{
178 		am[0].tv_sec = av->tv_sec;
179 		am[0].tv_nsec = NS(av->tv_nsec);
180 	}
181 	if (mv == TV_TOUCH_RETAIN)
182 	{
183 		am[1].tv_sec = st.st_mtime;
184 		am[1].tv_nsec = ST_MTIME_NSEC_GET(&st);
185 	}
186 	else
187 	{
188 		am[1].tv_sec = mv->tv_sec;
189 		am[1].tv_nsec = NS(mv->tv_nsec);
190 	}
191 	if (!utimets(path, am))
192 		return 0;
193 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimets(path, NiL))
194 	{
195 		errno = oerrno;
196 		return 0;
197 	}
198 #else
199 #if _lib_utimes
200 	if (av == TV_TOUCH_RETAIN)
201 	{
202 		am[0].tv_sec = st.st_atime;
203 		am[0].tv_usec = ST_ATIME_NSEC_GET(&st) / 1000;
204 	}
205 	else
206 	{
207 		am[0].tv_sec = av->tv_sec;
208 		am[0].tv_usec = NS(av->tv_nsec) / 1000;
209 	}
210 	if (mv == TV_TOUCH_RETAIN)
211 	{
212 		am[1].tv_sec = st.st_mtime;
213 		am[1].tv_usec = ST_MTIME_NSEC_GET(&st) / 1000;
214 	}
215 	else
216 	{
217 		am[1].tv_sec = mv->tv_sec;
218 		am[1].tv_usec = NS(mv->tv_nsec) / 1000;
219 	}
220 	if (!utimes(path, am))
221 		return 0;
222 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimes(path, NiL))
223 	{
224 		errno = oerrno;
225 		return 0;
226 	}
227 #else
228 #if _lib_utime
229 	am.actime = (av == TV_TOUCH_RETAIN) ? st.st_atime : av->tv_sec;
230 	am.modtime = (mv == TV_TOUCH_RETAIN) ? st.st_mtime : mv->tv_sec;
231 	if (!utime(path, &am))
232 		return 0;
233 #if _lib_utime_now
234 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utime(path, NiL))
235 	{
236 		errno = oerrno;
237 		return 0;
238 	}
239 #endif
240 #endif
241 #endif
242 	if (!access(path, F_OK))
243 	{
244 		if (av != (const Tv_t*)&now || mv != (const Tv_t*)&now)
245 		{
246 			errno = EINVAL;
247 			return -1;
248 		}
249 		if ((fd = open(path, O_RDWR)) >= 0)
250 		{
251 			char	c;
252 
253 			if (read(fd, &c, 1) == 1)
254 			{
255 				if (c = (lseek(fd, 0L, 0) == 0L && write(fd, &c, 1) == 1))
256 					errno = oerrno;
257 				close(fd);
258 				if (c)
259 					return 0;
260 			}
261 			close(fd);
262 		}
263 	}
264 #endif
265 	if (errno != ENOENT || !(flags & 1))
266 		return -1;
267 	umask(mode = umask(0));
268 	mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
269 	if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
270 		return -1;
271 	close(fd);
272 	errno = oerrno;
273 	if (av == (const Tv_t*)&now && mv == (const Tv_t*)&now)
274 		return 0;
275 #if _lib_utimets
276 	return utimets(path, am);
277 #else
278 #if _lib_utimes
279 	return utimes(path, am);
280 #else
281 #if _lib_utime
282 	return utime(path, &am);
283 #else
284 	errno = EINVAL;
285 	return -1;
286 #endif
287 #endif
288 #endif
289 #endif
290 
291 }
292