1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 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&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 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, 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)) >= 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, 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, am); 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