X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Futimens.c;h=bca3685be001bc25ccd25d0a65e14819600abec9;hb=681a475b43655abc79b81c4bf01e79a227ed6755;hp=4448f19f4777b1f57be7c56e9bf3d1e0ac505c05;hpb=321b14a2a9726a7cf0e4c9dbdaede314cc2be4f5;p=gnulib.git diff --git a/lib/utimens.c b/lib/utimens.c index 4448f19f4..bca3685be 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -1,8 +1,11 @@ -/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +/* Set file access and modification times. - This program is free software; you can redistribute it and/or modify it + Copyright (C) 2003, 2004, 2005, 2006, 2007 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 - 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, @@ -11,20 +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 #if HAVE_UTIME_H # include @@ -40,8 +43,20 @@ struct utimbuf }; #endif -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ -# define __attribute__(x) +/* 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 @@ -52,16 +67,37 @@ struct utimbuf 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 TIMESPEC is null, set the time stamps to the current time. */ + 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 -futimens (int fd ATTRIBUTE_UNUSED, - char const *file, struct timespec const timespec[2]) +gl_futimens (int fd ATTRIBUTE_UNUSED, + char const *file, struct timespec const timespec[2]) { + /* 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 + fsync (fd); +#endif + /* 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]; struct timeval const *t; if (timespec) @@ -74,41 +110,72 @@ futimens (int fd ATTRIBUTE_UNUSED, } else t = NULL; -# if HAVE_FUTIMES - if (0 <= fd) + + + 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 + + if (!file) + { +#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) + errno = ENOSYS; +#endif - /* On GNU/Linux without the futimes syscall and without /proc - mounted, glibc futimes fails with errno == ENOENT. Fall back - on utimes if we get a weird error number like that. */ - switch (errno) + /* Prefer EBADF to ENOSYS if both error numbers apply. */ + if (errno == ENOSYS) { - case EACCES: - case EIO: - case EPERM: - case EROFS: - return -1; + int fd2 = dup (fd); + int dup_errno = errno; + if (0 <= fd2) + close (fd2); + errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS); } - } -# endif - return utimes (file, t); -#else - - struct utimbuf utimbuf; - struct utimbuf const *t; - if (timespec) - { - utimbuf.actime = timespec[0].tv_sec; - utimbuf.modtime = timespec[1].tv_sec; - t = &utimbuf; + return -1; } - else - t = NULL; - return utime (file, t); +#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 } @@ -117,5 +184,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); }