1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * Glenn Fowler
25da2e3ebdSchin  * AT&T Research
26da2e3ebdSchin  *
27da2e3ebdSchin  * Tv_t conversion support
28da2e3ebdSchin  */
29da2e3ebdSchin 
30da2e3ebdSchin #if defined(__STDPP__directive) && defined(__STDPP__hide)
31da2e3ebdSchin __STDPP__directive pragma pp:hide utime
32da2e3ebdSchin #else
33da2e3ebdSchin #define utime		______utime
34da2e3ebdSchin #endif
35da2e3ebdSchin 
367c2fbfb3SApril Chin #ifndef _ATFILE_SOURCE
377c2fbfb3SApril Chin #define _ATFILE_SOURCE	1
387c2fbfb3SApril Chin #endif
397c2fbfb3SApril Chin 
40da2e3ebdSchin #include <ast.h>
41da2e3ebdSchin #include <ls.h>
42da2e3ebdSchin #include <tv.h>
43da2e3ebdSchin #include <times.h>
44da2e3ebdSchin #include <error.h>
45da2e3ebdSchin 
46da2e3ebdSchin #include "FEATURE/tvlib"
47da2e3ebdSchin 
48da2e3ebdSchin #if _hdr_utime && _lib_utime
49da2e3ebdSchin #include <utime.h>
50da2e3ebdSchin #endif
51da2e3ebdSchin 
52da2e3ebdSchin #if defined(__STDPP__directive) && defined(__STDPP__hide)
53da2e3ebdSchin __STDPP__directive pragma pp:nohide utime
54da2e3ebdSchin #else
55da2e3ebdSchin #undef	utime
56da2e3ebdSchin #endif
57da2e3ebdSchin 
58da2e3ebdSchin #if _lib_utime
59da2e3ebdSchin #if _hdr_utime
60da2e3ebdSchin extern int	utime(const char*, const struct utimbuf*);
61da2e3ebdSchin #else
62da2e3ebdSchin extern int	utime(const char*, const time_t*);
63da2e3ebdSchin #endif
64da2e3ebdSchin #endif
65da2e3ebdSchin 
66da2e3ebdSchin #define NS(n)		(((uint32_t)(n))<1000000000L?(n):0)
67da2e3ebdSchin 
68da2e3ebdSchin /*
69da2e3ebdSchin  * touch path <atime,mtime,ctime>
70da2e3ebdSchin  * Tv_t==0 uses current time
71da2e3ebdSchin  * Tv_t==TV_TOUCH_RETAIN retains path value if it exists, current time otherwise
72da2e3ebdSchin  * otherwise it is exact time
733e14f97fSRoger A. Faulkner  * file created if it doesn't exist and (flags&TV_TOUCH_CREATE)
743e14f97fSRoger A. Faulkner  * symlink not followed if (flags&TV_TOUCH_PHYSICAL)
75da2e3ebdSchin  * cv most likely ignored on most implementations
767c2fbfb3SApril Chin  *
773e14f97fSRoger A. Faulkner  * NOTE: when *at() calls are integrated TV_TOUCH_* should be advertized!
78da2e3ebdSchin  */
79da2e3ebdSchin 
803e14f97fSRoger A. Faulkner #define TV_TOUCH_CREATE		1
813e14f97fSRoger A. Faulkner #define TV_TOUCH_PHYSICAL	2
823e14f97fSRoger A. Faulkner 
833e14f97fSRoger A. Faulkner #if !defined(UTIME_NOW) || !defined(UTIME_OMIT) || defined(__stub_utimensat)
843e14f97fSRoger A. Faulkner #undef	_lib_utimensat
853e14f97fSRoger A. Faulkner #endif
863e14f97fSRoger A. Faulkner 
87da2e3ebdSchin int
tvtouch(const char * path,register const Tv_t * av,register const Tv_t * mv,const Tv_t * cv,int flags)88da2e3ebdSchin tvtouch(const char* path, register const Tv_t* av, register const Tv_t* mv, const Tv_t* cv, int flags)
89da2e3ebdSchin {
90da2e3ebdSchin 	int		fd;
91da2e3ebdSchin 	int		mode;
92da2e3ebdSchin 	int		oerrno;
937c2fbfb3SApril Chin 	struct stat	st;
943e14f97fSRoger A. Faulkner 	Tv_t		now;
953e14f97fSRoger A. Faulkner #if _lib_utimets || _lib_utimensat
967c2fbfb3SApril Chin 	struct timespec	ts[2];
973e14f97fSRoger A. Faulkner #endif
983e14f97fSRoger A. Faulkner #if _lib_utimes
993e14f97fSRoger A. Faulkner 	struct timeval	am[2];
1003e14f97fSRoger A. Faulkner #else
1013e14f97fSRoger A. Faulkner #if _hdr_utime
1023e14f97fSRoger A. Faulkner 	struct utimbuf	am;
1033e14f97fSRoger A. Faulkner #else
1043e14f97fSRoger A. Faulkner 	time_t		am[2];
1053e14f97fSRoger A. Faulkner #endif
1063e14f97fSRoger A. Faulkner #endif
1077c2fbfb3SApril Chin 
1083e14f97fSRoger A. Faulkner 	oerrno = errno;
1093e14f97fSRoger A. Faulkner #if _lib_utimensat
1107c2fbfb3SApril Chin 	if (!av)
1117c2fbfb3SApril Chin 	{
1127c2fbfb3SApril Chin 		ts[0].tv_sec = 0;
1137c2fbfb3SApril Chin 		ts[0].tv_nsec = UTIME_NOW;
1147c2fbfb3SApril Chin 	}
1157c2fbfb3SApril Chin 	else if (av == TV_TOUCH_RETAIN)
1167c2fbfb3SApril Chin 	{
1177c2fbfb3SApril Chin 		ts[0].tv_sec = 0;
1187c2fbfb3SApril Chin 		ts[0].tv_nsec = UTIME_OMIT;
1197c2fbfb3SApril Chin 	}
1207c2fbfb3SApril Chin 	else
1217c2fbfb3SApril Chin 	{
1227c2fbfb3SApril Chin 		ts[0].tv_sec = av->tv_sec;
1237c2fbfb3SApril Chin 		ts[0].tv_nsec = NS(av->tv_nsec);
1247c2fbfb3SApril Chin 	}
1257c2fbfb3SApril Chin 	if (!mv)
1267c2fbfb3SApril Chin 	{
1277c2fbfb3SApril Chin 		ts[1].tv_sec = 0;
1287c2fbfb3SApril Chin 		ts[1].tv_nsec = UTIME_NOW;
1297c2fbfb3SApril Chin 	}
1307c2fbfb3SApril Chin 	else if (mv == TV_TOUCH_RETAIN)
1317c2fbfb3SApril Chin 	{
1327c2fbfb3SApril Chin 		ts[1].tv_sec = 0;
1337c2fbfb3SApril Chin 		ts[1].tv_nsec = UTIME_OMIT;
1347c2fbfb3SApril Chin 	}
1357c2fbfb3SApril Chin 	else
1367c2fbfb3SApril Chin 	{
1377c2fbfb3SApril Chin 		ts[1].tv_sec = mv->tv_sec;
1387c2fbfb3SApril Chin 		ts[1].tv_nsec = NS(mv->tv_nsec);
1397c2fbfb3SApril Chin 	}
1407c2fbfb3SApril Chin 	if (!cv && av == TV_TOUCH_RETAIN && mv == TV_TOUCH_RETAIN && !stat(path, &st) && !chmod(path, st.st_mode & S_IPERM))
1417c2fbfb3SApril Chin 		return 0;
1423e14f97fSRoger A. Faulkner 	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))
1437c2fbfb3SApril Chin 		return 0;
1443e14f97fSRoger A. Faulkner 	if (errno != ENOSYS)
1453e14f97fSRoger A. Faulkner 	{
1463e14f97fSRoger A. Faulkner 		if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
1473e14f97fSRoger A. Faulkner 			return -1;
1483e14f97fSRoger A. Faulkner 		umask(mode = umask(0));
1493e14f97fSRoger A. Faulkner 		mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
150*b30d1939SAndy Fiddaman 		if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, mode)) < 0)
1513e14f97fSRoger A. Faulkner 			return -1;
1523e14f97fSRoger A. Faulkner 		close(fd);
1533e14f97fSRoger A. Faulkner 		errno = oerrno;
1543e14f97fSRoger A. Faulkner 		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))
1553e14f97fSRoger A. Faulkner 			return -1;
1563e14f97fSRoger A. Faulkner 		return 0;
1573e14f97fSRoger A. Faulkner 	}
158da2e3ebdSchin #endif
159da2e3ebdSchin 	if ((av == TV_TOUCH_RETAIN || mv == TV_TOUCH_RETAIN) && stat(path, &st))
160da2e3ebdSchin 	{
161da2e3ebdSchin 		errno = oerrno;
162da2e3ebdSchin 		if (av == TV_TOUCH_RETAIN)
163da2e3ebdSchin 			av = 0;
164da2e3ebdSchin 		if (mv == TV_TOUCH_RETAIN)
165da2e3ebdSchin 			mv = 0;
166da2e3ebdSchin 	}
167da2e3ebdSchin 	if (!av || !mv)
168da2e3ebdSchin 	{
169da2e3ebdSchin 		tvgettime(&now);
170da2e3ebdSchin 		if (!av)
171da2e3ebdSchin 			av = (const Tv_t*)&now;
172da2e3ebdSchin 		if (!mv)
173da2e3ebdSchin 			mv = (const Tv_t*)&now;
174da2e3ebdSchin 	}
175da2e3ebdSchin #if _lib_utimets
176da2e3ebdSchin 	if (av == TV_TOUCH_RETAIN)
177da2e3ebdSchin 	{
1783e14f97fSRoger A. Faulkner 		ts[0].tv_sec = st.st_atime;
1793e14f97fSRoger A. Faulkner 		ts[0].tv_nsec = ST_ATIME_NSEC_GET(&st);
180da2e3ebdSchin 	}
181da2e3ebdSchin 	else
182da2e3ebdSchin 	{
1833e14f97fSRoger A. Faulkner 		ts[0].tv_sec = av->tv_sec;
1843e14f97fSRoger A. Faulkner 		ts[0].tv_nsec = NS(av->tv_nsec);
185da2e3ebdSchin 	}
186da2e3ebdSchin 	if (mv == TV_TOUCH_RETAIN)
187da2e3ebdSchin 	{
1883e14f97fSRoger A. Faulkner 		ts[1].tv_sec = st.st_mtime;
1893e14f97fSRoger A. Faulkner 		ts[1].tv_nsec = ST_MTIME_NSEC_GET(&st);
190da2e3ebdSchin 	}
191da2e3ebdSchin 	else
192da2e3ebdSchin 	{
1933e14f97fSRoger A. Faulkner 		ts[1].tv_sec = mv->tv_sec;
1943e14f97fSRoger A. Faulkner 		ts[1].tv_nsec = NS(mv->tv_nsec);
195da2e3ebdSchin 	}
1963e14f97fSRoger A. Faulkner 	if (!utimets(path, ts))
197da2e3ebdSchin 		return 0;
198da2e3ebdSchin 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimets(path, NiL))
199da2e3ebdSchin 	{
200da2e3ebdSchin 		errno = oerrno;
201da2e3ebdSchin 		return 0;
202da2e3ebdSchin 	}
203da2e3ebdSchin #else
204da2e3ebdSchin #if _lib_utimes
205da2e3ebdSchin 	if (av == TV_TOUCH_RETAIN)
206da2e3ebdSchin 	{
207da2e3ebdSchin 		am[0].tv_sec = st.st_atime;
208da2e3ebdSchin 		am[0].tv_usec = ST_ATIME_NSEC_GET(&st) / 1000;
209da2e3ebdSchin 	}
210da2e3ebdSchin 	else
211da2e3ebdSchin 	{
212da2e3ebdSchin 		am[0].tv_sec = av->tv_sec;
213da2e3ebdSchin 		am[0].tv_usec = NS(av->tv_nsec) / 1000;
214da2e3ebdSchin 	}
215da2e3ebdSchin 	if (mv == TV_TOUCH_RETAIN)
216da2e3ebdSchin 	{
217da2e3ebdSchin 		am[1].tv_sec = st.st_mtime;
218da2e3ebdSchin 		am[1].tv_usec = ST_MTIME_NSEC_GET(&st) / 1000;
219da2e3ebdSchin 	}
220da2e3ebdSchin 	else
221da2e3ebdSchin 	{
222da2e3ebdSchin 		am[1].tv_sec = mv->tv_sec;
223da2e3ebdSchin 		am[1].tv_usec = NS(mv->tv_nsec) / 1000;
224da2e3ebdSchin 	}
225da2e3ebdSchin 	if (!utimes(path, am))
226da2e3ebdSchin 		return 0;
227da2e3ebdSchin 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimes(path, NiL))
228da2e3ebdSchin 	{
229da2e3ebdSchin 		errno = oerrno;
230da2e3ebdSchin 		return 0;
231da2e3ebdSchin 	}
232da2e3ebdSchin #else
233da2e3ebdSchin #if _lib_utime
234da2e3ebdSchin 	am.actime = (av == TV_TOUCH_RETAIN) ? st.st_atime : av->tv_sec;
235da2e3ebdSchin 	am.modtime = (mv == TV_TOUCH_RETAIN) ? st.st_mtime : mv->tv_sec;
236da2e3ebdSchin 	if (!utime(path, &am))
237da2e3ebdSchin 		return 0;
238da2e3ebdSchin #if _lib_utime_now
239da2e3ebdSchin 	if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utime(path, NiL))
240da2e3ebdSchin 	{
241da2e3ebdSchin 		errno = oerrno;
242da2e3ebdSchin 		return 0;
243da2e3ebdSchin 	}
244da2e3ebdSchin #endif
245da2e3ebdSchin #endif
246da2e3ebdSchin #endif
247da2e3ebdSchin 	if (!access(path, F_OK))
248da2e3ebdSchin 	{
249da2e3ebdSchin 		if (av != (const Tv_t*)&now || mv != (const Tv_t*)&now)
250da2e3ebdSchin 		{
251da2e3ebdSchin 			errno = EINVAL;
252da2e3ebdSchin 			return -1;
253da2e3ebdSchin 		}
254*b30d1939SAndy Fiddaman 		if ((fd = open(path, O_RDWR|O_cloexec)) >= 0)
255da2e3ebdSchin 		{
256da2e3ebdSchin 			char	c;
257da2e3ebdSchin 
258da2e3ebdSchin 			if (read(fd, &c, 1) == 1)
259da2e3ebdSchin 			{
260da2e3ebdSchin 				if (c = (lseek(fd, 0L, 0) == 0L && write(fd, &c, 1) == 1))
261da2e3ebdSchin 					errno = oerrno;
262da2e3ebdSchin 				close(fd);
263da2e3ebdSchin 				if (c)
264da2e3ebdSchin 					return 0;
265da2e3ebdSchin 			}
266da2e3ebdSchin 			close(fd);
267da2e3ebdSchin 		}
268da2e3ebdSchin 	}
269da2e3ebdSchin #endif
2703e14f97fSRoger A. Faulkner 	if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
271da2e3ebdSchin 		return -1;
272da2e3ebdSchin 	umask(mode = umask(0));
273da2e3ebdSchin 	mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
274*b30d1939SAndy Fiddaman 	if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, mode)) < 0)
275da2e3ebdSchin 		return -1;
276da2e3ebdSchin 	close(fd);
277da2e3ebdSchin 	errno = oerrno;
278da2e3ebdSchin 	if (av == (const Tv_t*)&now && mv == (const Tv_t*)&now)
279da2e3ebdSchin 		return 0;
280da2e3ebdSchin #if _lib_utimets
281*b30d1939SAndy Fiddaman 	return utimets(path, ts);
282da2e3ebdSchin #else
283da2e3ebdSchin #if _lib_utimes
284da2e3ebdSchin 	return utimes(path, am);
285da2e3ebdSchin #else
286da2e3ebdSchin #if _lib_utime
287da2e3ebdSchin 	return utime(path, &am);
288da2e3ebdSchin #else
289da2e3ebdSchin 	errno = EINVAL;
290da2e3ebdSchin 	return -1;
291da2e3ebdSchin #endif
292da2e3ebdSchin #endif
293da2e3ebdSchin #endif
294da2e3ebdSchin 
295da2e3ebdSchin }
296