X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Futimens.c;h=8d8bef468ecdef2f444f2434d20cdbdbe3e0a31b;hb=fef71c83bc8291522ae54810ae9b4238ca13cf1a;hp=9f1a0e116e8ba0b7797ffae0877bef844a29def7;hpb=10cf9b5e371bc4927b2b28354c19b62943dfe95e;p=gnulib.git diff --git a/lib/utimens.c b/lib/utimens.c index 9f1a0e116..8d8bef468 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Paul Eggert. */ @@ -24,6 +24,10 @@ #include "utimens.h" +#include +#include +#include + #if HAVE_UTIME_H # include #endif @@ -38,26 +42,123 @@ struct utimbuf }; #endif -/* Set the access and modification time stamps of FILE to be - TIMESPEC[0] and TIMESPEC[1], respectively. */ +/* Some systems don't have ENOSYS. */ +#ifndef ENOSYS +# ifdef ENOTSUP +# define ENOSYS ENOTSUP +# else +/* Some systems don't have ENOTSUP either. */ +# define ENOSYS EINVAL +# endif +#endif + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +/* Set the access and modification time stamps of FD (a.k.a. FILE) to be + TIMESPEC[0] and TIMESPEC[1], respectively. + FD must be either negative -- in which case it is ignored -- + or a file descriptor that is open on FILE. + If FD is nonnegative, then FILE can be NULL, which means + use just futimes (or equivalent) instead of utimes (or equivalent), + and fail if on an old system without futimes (or equivalent). + If TIMESPEC is null, set the time stamps to the current time. + Return 0 on success, -1 (setting errno) on failure. */ int -utimens (char const *file, struct timespec const timespec[2]) +futimens (int fd ATTRIBUTE_UNUSED, + char const *file, struct timespec const timespec[2]) { /* There's currently no interface to set file timestamps with nanosecond resolution, so do the best we can, discarding any fractional part of the timestamp. */ -#if HAVE_WORKING_UTIMES +#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES struct timeval timeval[2]; - timeval[0].tv_sec = timespec[0].tv_sec; - timeval[0].tv_usec = timespec[0].tv_nsec / 1000; - timeval[1].tv_sec = timespec[1].tv_sec; - timeval[1].tv_usec = timespec[1].tv_nsec / 1000; - return utimes (file, timeval); -#else - struct utimbuf utimbuf; - utimbuf.actime = timespec[0].tv_sec; - utimbuf.modtime = timespec[1].tv_sec; - return utime (file, &utimbuf); + struct timeval const *t; + if (timespec) + { + timeval[0].tv_sec = timespec[0].tv_sec; + timeval[0].tv_usec = timespec[0].tv_nsec / 1000; + timeval[1].tv_sec = timespec[1].tv_sec; + timeval[1].tv_usec = timespec[1].tv_nsec / 1000; + t = timeval; + } + else + t = NULL; + +# if HAVE_FUTIMESAT + return fd < 0 ? futimesat (AT_FDCWD, file, t) : futimesat (fd, NULL, t); +# elif HAVE_FUTIMES + if (0 <= fd) + { + if (futimes (fd, t) == 0) + return 0; + + /* Don't worry about trying to speed things up by returning right + away here. glibc futimes can incorrectly fail with errno == + ENOENT if /proc isn't mounted. Also, Mandrake 10.0 in high + security mode doesn't allow ordinary users to read /proc/self, so + glibc futimes incorrectly fails with errno == EACCES. If futimes + fails with errno == EIO, EPERM, or EROFS, it's probably safe to + fail right away, but these cases are rare enough that they're not + worth optimizing, and who knows what other messed-up systems are + out there? So play it safe and fall back on the code below. */ + } +# endif #endif + +#if ! HAVE_FUTIMESAT + + if (!file) + { +# if ! (HAVE_WORKING_UTIMES && HAVE_FUTIMES) + errno = ENOSYS; +# endif + + /* Prefer EBADF to ENOSYS if both error numbers apply. */ + if (errno == ENOSYS) + { + int fd2 = dup (fd); + int dup_errno = errno; + if (0 <= fd2) + close (fd2); + errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS); + } + + return -1; + } + +# if HAVE_WORKING_UTIMES + return utimes (file, t); +# else + { + struct utimbuf utimbuf; + struct utimbuf const *ut; + if (timespec) + { + utimbuf.actime = timespec[0].tv_sec; + utimbuf.modtime = timespec[1].tv_sec; + ut = &utimbuf; + } + else + ut = NULL; + + return utime (file, ut); + } +# endif + +#endif +} + +/* Set the access and modification time stamps of FILE to be + TIMESPEC[0] and TIMESPEC[1], respectively. */ +int +utimens (char const *file, struct timespec const timespec[2]) +{ + return futimens (-1, file, timespec); }