1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * Tv_t conversion support
1N/A */
1N/A
1N/A#if defined(__STDPP__directive) && defined(__STDPP__hide)
1N/A__STDPP__directive pragma pp:hide utime
1N/A#else
1N/A#define utime ______utime
1N/A#endif
1N/A
1N/A#ifndef _ATFILE_SOURCE
1N/A#define _ATFILE_SOURCE 1
1N/A#endif
1N/A
1N/A#include <ast.h>
1N/A#include <ls.h>
1N/A#include <tv.h>
1N/A#include <times.h>
1N/A#include <error.h>
1N/A
1N/A#include "FEATURE/tvlib"
1N/A
1N/A#if _hdr_utime && _lib_utime
1N/A#include <utime.h>
1N/A#endif
1N/A
1N/A#if defined(__STDPP__directive) && defined(__STDPP__hide)
1N/A__STDPP__directive pragma pp:nohide utime
1N/A#else
1N/A#undef utime
1N/A#endif
1N/A
1N/A#if _lib_utime
1N/A#if _hdr_utime
1N/Aextern int utime(const char*, const struct utimbuf*);
1N/A#else
1N/Aextern int utime(const char*, const time_t*);
1N/A#endif
1N/A#endif
1N/A
1N/A#define NS(n) (((uint32_t)(n))<1000000000L?(n):0)
1N/A
1N/A/*
1N/A * touch path <atime,mtime,ctime>
1N/A * Tv_t==0 uses current time
1N/A * Tv_t==TV_TOUCH_RETAIN retains path value if it exists, current time otherwise
1N/A * otherwise it is exact time
1N/A * file created if it doesn't exist and (flags&TV_TOUCH_CREATE)
1N/A * symlink not followed if (flags&TV_TOUCH_PHYSICAL)
1N/A * cv most likely ignored on most implementations
1N/A *
1N/A * NOTE: when *at() calls are integrated TV_TOUCH_* should be advertized!
1N/A */
1N/A
1N/A#define TV_TOUCH_CREATE 1
1N/A#define TV_TOUCH_PHYSICAL 2
1N/A
1N/A#if !defined(UTIME_NOW) || !defined(UTIME_OMIT) || defined(__stub_utimensat)
1N/A#undef _lib_utimensat
1N/A#endif
1N/A
1N/Aint
1N/Atvtouch(const char* path, register const Tv_t* av, register const Tv_t* mv, const Tv_t* cv, int flags)
1N/A{
1N/A int fd;
1N/A int mode;
1N/A int oerrno;
1N/A struct stat st;
1N/A Tv_t now;
1N/A#if _lib_utimets || _lib_utimensat
1N/A struct timespec ts[2];
1N/A#endif
1N/A#if _lib_utimes
1N/A struct timeval am[2];
1N/A#else
1N/A#if _hdr_utime
1N/A struct utimbuf am;
1N/A#else
1N/A time_t am[2];
1N/A#endif
1N/A#endif
1N/A
1N/A oerrno = errno;
1N/A#if _lib_utimensat
1N/A if (!av)
1N/A {
1N/A ts[0].tv_sec = 0;
1N/A ts[0].tv_nsec = UTIME_NOW;
1N/A }
1N/A else if (av == TV_TOUCH_RETAIN)
1N/A {
1N/A ts[0].tv_sec = 0;
1N/A ts[0].tv_nsec = UTIME_OMIT;
1N/A }
1N/A else
1N/A {
1N/A ts[0].tv_sec = av->tv_sec;
1N/A ts[0].tv_nsec = NS(av->tv_nsec);
1N/A }
1N/A if (!mv)
1N/A {
1N/A ts[1].tv_sec = 0;
1N/A ts[1].tv_nsec = UTIME_NOW;
1N/A }
1N/A else if (mv == TV_TOUCH_RETAIN)
1N/A {
1N/A ts[1].tv_sec = 0;
1N/A ts[1].tv_nsec = UTIME_OMIT;
1N/A }
1N/A else
1N/A {
1N/A ts[1].tv_sec = mv->tv_sec;
1N/A ts[1].tv_nsec = NS(mv->tv_nsec);
1N/A }
1N/A if (!cv && av == TV_TOUCH_RETAIN && mv == TV_TOUCH_RETAIN && !stat(path, &st) && !chmod(path, st.st_mode & S_IPERM))
1N/A return 0;
1N/A 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))
1N/A return 0;
1N/A if (errno != ENOSYS)
1N/A {
1N/A if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
1N/A return -1;
1N/A umask(mode = umask(0));
1N/A mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1N/A if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
1N/A return -1;
1N/A close(fd);
1N/A errno = oerrno;
1N/A 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))
1N/A return -1;
1N/A return 0;
1N/A }
1N/A#endif
1N/A if ((av == TV_TOUCH_RETAIN || mv == TV_TOUCH_RETAIN) && stat(path, &st))
1N/A {
1N/A errno = oerrno;
1N/A if (av == TV_TOUCH_RETAIN)
1N/A av = 0;
1N/A if (mv == TV_TOUCH_RETAIN)
1N/A mv = 0;
1N/A }
1N/A if (!av || !mv)
1N/A {
1N/A tvgettime(&now);
1N/A if (!av)
1N/A av = (const Tv_t*)&now;
1N/A if (!mv)
1N/A mv = (const Tv_t*)&now;
1N/A }
1N/A#if _lib_utimets
1N/A if (av == TV_TOUCH_RETAIN)
1N/A {
1N/A ts[0].tv_sec = st.st_atime;
1N/A ts[0].tv_nsec = ST_ATIME_NSEC_GET(&st);
1N/A }
1N/A else
1N/A {
1N/A ts[0].tv_sec = av->tv_sec;
1N/A ts[0].tv_nsec = NS(av->tv_nsec);
1N/A }
1N/A if (mv == TV_TOUCH_RETAIN)
1N/A {
1N/A ts[1].tv_sec = st.st_mtime;
1N/A ts[1].tv_nsec = ST_MTIME_NSEC_GET(&st);
1N/A }
1N/A else
1N/A {
1N/A ts[1].tv_sec = mv->tv_sec;
1N/A ts[1].tv_nsec = NS(mv->tv_nsec);
1N/A }
1N/A if (!utimets(path, ts))
1N/A return 0;
1N/A if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimets(path, NiL))
1N/A {
1N/A errno = oerrno;
1N/A return 0;
1N/A }
1N/A#else
1N/A#if _lib_utimes
1N/A if (av == TV_TOUCH_RETAIN)
1N/A {
1N/A am[0].tv_sec = st.st_atime;
1N/A am[0].tv_usec = ST_ATIME_NSEC_GET(&st) / 1000;
1N/A }
1N/A else
1N/A {
1N/A am[0].tv_sec = av->tv_sec;
1N/A am[0].tv_usec = NS(av->tv_nsec) / 1000;
1N/A }
1N/A if (mv == TV_TOUCH_RETAIN)
1N/A {
1N/A am[1].tv_sec = st.st_mtime;
1N/A am[1].tv_usec = ST_MTIME_NSEC_GET(&st) / 1000;
1N/A }
1N/A else
1N/A {
1N/A am[1].tv_sec = mv->tv_sec;
1N/A am[1].tv_usec = NS(mv->tv_nsec) / 1000;
1N/A }
1N/A if (!utimes(path, am))
1N/A return 0;
1N/A if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimes(path, NiL))
1N/A {
1N/A errno = oerrno;
1N/A return 0;
1N/A }
1N/A#else
1N/A#if _lib_utime
1N/A am.actime = (av == TV_TOUCH_RETAIN) ? st.st_atime : av->tv_sec;
1N/A am.modtime = (mv == TV_TOUCH_RETAIN) ? st.st_mtime : mv->tv_sec;
1N/A if (!utime(path, &am))
1N/A return 0;
1N/A#if _lib_utime_now
1N/A if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utime(path, NiL))
1N/A {
1N/A errno = oerrno;
1N/A return 0;
1N/A }
1N/A#endif
1N/A#endif
1N/A#endif
1N/A if (!access(path, F_OK))
1N/A {
1N/A if (av != (const Tv_t*)&now || mv != (const Tv_t*)&now)
1N/A {
1N/A errno = EINVAL;
1N/A return -1;
1N/A }
1N/A if ((fd = open(path, O_RDWR)) >= 0)
1N/A {
1N/A char c;
1N/A
1N/A if (read(fd, &c, 1) == 1)
1N/A {
1N/A if (c = (lseek(fd, 0L, 0) == 0L && write(fd, &c, 1) == 1))
1N/A errno = oerrno;
1N/A close(fd);
1N/A if (c)
1N/A return 0;
1N/A }
1N/A close(fd);
1N/A }
1N/A }
1N/A#endif
1N/A if (errno != ENOENT || !(flags & TV_TOUCH_CREATE))
1N/A return -1;
1N/A umask(mode = umask(0));
1N/A mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1N/A if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
1N/A return -1;
1N/A close(fd);
1N/A errno = oerrno;
1N/A if (av == (const Tv_t*)&now && mv == (const Tv_t*)&now)
1N/A return 0;
1N/A#if _lib_utimets
1N/A return utimets(path, am);
1N/A#else
1N/A#if _lib_utimes
1N/A return utimes(path, am);
1N/A#else
1N/A#if _lib_utime
1N/A return utime(path, &am);
1N/A#else
1N/A errno = EINVAL;
1N/A return -1;
1N/A#endif
1N/A#endif
1N/A#endif
1N/A
1N/A}