1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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&TV_TOUCH_CREATE)
74 * symlink not followed if (flags&TV_TOUCH_PHYSICAL)
75 * cv most likely ignored on most implementations
76 *
77 * NOTE: when *at() calls are integrated TV_TOUCH_* should be advertized!
78 */
79
80 #define TV_TOUCH_CREATE 1
81 #define TV_TOUCH_PHYSICAL 2
82
83 #if !defined(UTIME_NOW) || !defined(UTIME_OMIT) || defined(__stub_utimensat)
84 #undef _lib_utimensat
85 #endif
86
87 int
tvtouch(const char * path,register const Tv_t * av,register const Tv_t * mv,const Tv_t * cv,int flags)88 tvtouch(const char* path, register const Tv_t* av, register const Tv_t* mv, const Tv_t* cv, int flags)
89 {
90 int fd;
91 int mode;
92 int oerrno;
93 struct stat st;
94 Tv_t now;
95 #if _lib_utimets || _lib_utimensat
96 struct timespec ts[2];
97 #endif
98 #if _lib_utimes
99 struct timeval am[2];
100 #else
101 #if _hdr_utime
102 struct utimbuf am;
103 #else
104 time_t am[2];
105 #endif
106 #endif
107
108 oerrno = errno;
109 #if _lib_utimensat
110 if (!av)
111 {
112 ts[0].tv_sec = 0;
113 ts[0].tv_nsec = UTIME_NOW;
114 }
115 else if (av == TV_TOUCH_RETAIN)
116 {
117 ts[0].tv_sec = 0;
118 ts[0].tv_nsec = UTIME_OMIT;
119 }
120 else
121 {
122 ts[0].tv_sec = av->tv_sec;
123 ts[0].tv_nsec = NS(av->tv_nsec);
124 }
125 if (!mv)
126 {
127 ts[1].tv_sec = 0;
128 ts[1].tv_nsec = UTIME_NOW;
129 }
130 else if (mv == TV_TOUCH_RETAIN)
131 {
132 ts[1].tv_sec = 0;
133 ts[1].tv_nsec = UTIME_OMIT;
134 }
135 else
136 {
137 ts[1].tv_sec = mv->tv_sec;
138 ts[1].tv_nsec = NS(mv->tv_nsec);
139 }
140 if (!cv && av == TV_TOUCH_RETAIN && mv == TV_TOUCH_RETAIN && !stat(path, &st) && !chmod(path, st.st_mode & S_IPERM))
141 return 0;
142 if (!utimensat(AT_FDCWD, path, ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW ? (struct timespec*)0 : ts, (flags & TV_TOUCH_PHYSICAL) ? AT_SYMLINK_NOFOLLOW : 0))
143 return 0;
144 if (errno != ENOSYS)
145 {
146 if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
147 return -1;
148 umask(mode = umask(0));
149 mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
150 if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, mode)) < 0)
151 return -1;
152 close(fd);
153 errno = oerrno;
154 if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) && utimensat(AT_FDCWD, path, ts, (flags & TV_TOUCH_PHYSICAL) ? AT_SYMLINK_NOFOLLOW : 0))
155 return -1;
156 return 0;
157 }
158 #endif
159 if ((av == TV_TOUCH_RETAIN || mv == TV_TOUCH_RETAIN) && stat(path, &st))
160 {
161 errno = oerrno;
162 if (av == TV_TOUCH_RETAIN)
163 av = 0;
164 if (mv == TV_TOUCH_RETAIN)
165 mv = 0;
166 }
167 if (!av || !mv)
168 {
169 tvgettime(&now);
170 if (!av)
171 av = (const Tv_t*)&now;
172 if (!mv)
173 mv = (const Tv_t*)&now;
174 }
175 #if _lib_utimets
176 if (av == TV_TOUCH_RETAIN)
177 {
178 ts[0].tv_sec = st.st_atime;
179 ts[0].tv_nsec = ST_ATIME_NSEC_GET(&st);
180 }
181 else
182 {
183 ts[0].tv_sec = av->tv_sec;
184 ts[0].tv_nsec = NS(av->tv_nsec);
185 }
186 if (mv == TV_TOUCH_RETAIN)
187 {
188 ts[1].tv_sec = st.st_mtime;
189 ts[1].tv_nsec = ST_MTIME_NSEC_GET(&st);
190 }
191 else
192 {
193 ts[1].tv_sec = mv->tv_sec;
194 ts[1].tv_nsec = NS(mv->tv_nsec);
195 }
196 if (!utimets(path, ts))
197 return 0;
198 if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimets(path, NiL))
199 {
200 errno = oerrno;
201 return 0;
202 }
203 #else
204 #if _lib_utimes
205 if (av == TV_TOUCH_RETAIN)
206 {
207 am[0].tv_sec = st.st_atime;
208 am[0].tv_usec = ST_ATIME_NSEC_GET(&st) / 1000;
209 }
210 else
211 {
212 am[0].tv_sec = av->tv_sec;
213 am[0].tv_usec = NS(av->tv_nsec) / 1000;
214 }
215 if (mv == TV_TOUCH_RETAIN)
216 {
217 am[1].tv_sec = st.st_mtime;
218 am[1].tv_usec = ST_MTIME_NSEC_GET(&st) / 1000;
219 }
220 else
221 {
222 am[1].tv_sec = mv->tv_sec;
223 am[1].tv_usec = NS(mv->tv_nsec) / 1000;
224 }
225 if (!utimes(path, am))
226 return 0;
227 if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimes(path, NiL))
228 {
229 errno = oerrno;
230 return 0;
231 }
232 #else
233 #if _lib_utime
234 am.actime = (av == TV_TOUCH_RETAIN) ? st.st_atime : av->tv_sec;
235 am.modtime = (mv == TV_TOUCH_RETAIN) ? st.st_mtime : mv->tv_sec;
236 if (!utime(path, &am))
237 return 0;
238 #if _lib_utime_now
239 if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utime(path, NiL))
240 {
241 errno = oerrno;
242 return 0;
243 }
244 #endif
245 #endif
246 #endif
247 if (!access(path, F_OK))
248 {
249 if (av != (const Tv_t*)&now || mv != (const Tv_t*)&now)
250 {
251 errno = EINVAL;
252 return -1;
253 }
254 if ((fd = open(path, O_RDWR|O_cloexec)) >= 0)
255 {
256 char c;
257
258 if (read(fd, &c, 1) == 1)
259 {
260 if (c = (lseek(fd, 0L, 0) == 0L && write(fd, &c, 1) == 1))
261 errno = oerrno;
262 close(fd);
263 if (c)
264 return 0;
265 }
266 close(fd);
267 }
268 }
269 #endif
270 if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
271 return -1;
272 umask(mode = umask(0));
273 mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
274 if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, mode)) < 0)
275 return -1;
276 close(fd);
277 errno = oerrno;
278 if (av == (const Tv_t*)&now && mv == (const Tv_t*)&now)
279 return 0;
280 #if _lib_utimets
281 return utimets(path, ts);
282 #else
283 #if _lib_utimes
284 return utimes(path, am);
285 #else
286 #if _lib_utime
287 return utime(path, &am);
288 #else
289 errno = EINVAL;
290 return -1;
291 #endif
292 #endif
293 #endif
294
295 }
296