X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Futimens.c;h=10d2c8246ffecfc9b6d9d3776db97efbd095a6cc;hb=35335a0a3c4bd5c973962212601eb60fc1964698;hp=1489df05caeb0752acdf92a4cafef59aa56ae51f;hpb=85a134e9fd9e77af75684abdc9819171c754fb47;p=gnulib.git diff --git a/lib/utimens.c b/lib/utimens.c index 1489df05c..10d2c8246 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -1,10 +1,11 @@ /* Set file access and modification times. - Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free + Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify it + 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 - Free Software Foundation; either version 2, or (at your option) any + Free Software Foundation; either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, @@ -13,21 +14,20 @@ GNU General Public License for more details. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* Written by Paul Eggert. */ /* derived from a function in touch.c */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include #include "utimens.h" #include #include +#include +#include #include #if HAVE_UTIME_H @@ -44,26 +44,6 @@ struct utimbuf }; #endif -/* 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 - -#ifndef __attribute__ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ -# define __attribute__(x) -# endif -#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 -- @@ -75,92 +55,147 @@ struct utimbuf Return 0 on success, -1 (setting errno) on failure. */ int -futimens (int fd ATTRIBUTE_UNUSED, - char const *file, struct timespec const timespec[2]) +gl_futimens (int fd _UNUSED_PARAMETER_, + 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_FUTIMESAT || HAVE_WORKING_UTIMES - struct timeval timeval[2]; - 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; - } + /* Some Linux-based NFS clients are buggy, and mishandle time stamps + of files in NFS file systems in some cases. We have no + configure-time test for this, but please see + for references to + some of the problems with Linux 2.6.16. If this affects you, + compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to + help in some cases, albeit at a cost in performance. But you + really should upgrade your kernel to a fixed version, since the + problem affects many applications. */ + +#if HAVE_BUGGY_NFS_TIME_STAMPS + if (fd < 0) + sync (); else - t = NULL; - + fsync (fd); +#endif + /* POSIX 200x added two interfaces to set file timestamps with + nanosecond resolution. We provide a fallback for ENOSYS (for + example, compiling against Linux 2.6.25 kernel headers and glibc + 2.7, but running on Linux 2.6.18 kernel). */ +#if HAVE_UTIMENSAT if (fd < 0) { -# if HAVE_FUTIMESAT - return futimesat (AT_FDCWD, file, t); -# endif - } - else - { - /* If futimesat or futimes fails here, don't try to speed things - up by returning right away. glibc 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 incorrectly fails with errno == EACCES. - If 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. */ -# if HAVE_FUTIMESAT - if (futimesat (fd, NULL, t) == 0) - return 0; -# elif HAVE_FUTIMES - if (futimes (fd, t) == 0) - return 0; + int result = utimensat (AT_FDCWD, file, timespec, 0); +# ifdef __linux__ + /* Work around what might be a kernel bug: + http://bugzilla.redhat.com/442352 + http://bugzilla.redhat.com/449910 + It appears that utimensat can mistakenly return 280 rather + than -1 upon failure. + FIXME: remove in 2010 or whenever the offending kernels + are no longer in common use. */ + if (0 < result) + errno = ENOSYS; # endif + + if (result == 0 || errno != ENOSYS) + return result; } #endif - - if (!file) - { -#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) +#if HAVE_FUTIMENS + { + int result = futimens (fd, timespec); +# ifdef __linux__ + /* Work around the same bug as above. */ + if (0 < result) errno = ENOSYS; +# endif + if (result == 0 || errno != ENOSYS) + return result; + } #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 + /* The platform lacks an interface to set file timestamps with + nanosecond resolution, so do the best we can, discarding any + fractional part of the timestamp. */ { - struct utimbuf utimbuf; - struct utimbuf const *ut; +#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES + struct timeval timeval[2]; + struct timeval const *t; if (timespec) { - utimbuf.actime = timespec[0].tv_sec; - utimbuf.modtime = timespec[1].tv_sec; - ut = &utimbuf; + 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 - ut = NULL; + t = NULL; - return utime (file, ut); - } + if (fd < 0) + { +# if HAVE_FUTIMESAT + return futimesat (AT_FDCWD, file, t); +# endif + } + else + { + /* If futimesat or futimes fails here, don't try to speed things + up by returning right away. glibc 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 incorrectly fails with errno == EACCES. + If 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. */ +# if HAVE_FUTIMESAT + if (futimesat (fd, NULL, t) == 0) + return 0; +# elif HAVE_FUTIMES + if (futimes (fd, t) == 0) + return 0; +# endif + } +#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */ + + if (!file) + { +#if ! (HAVE_FUTIMESAT || (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 /* !HAVE_WORKING_UTIMES */ + } } /* Set the access and modification time stamps of FILE to be @@ -168,5 +203,5 @@ futimens (int fd ATTRIBUTE_UNUSED, int utimens (char const *file, struct timespec const timespec[2]) { - return futimens (-1, file, timespec); + return gl_futimens (-1, file, timespec); }