From faeb3e6b2191565dc3197804cd9ff624f26a1004 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 28 May 2008 21:29:02 -0600 Subject: [PATCH] Prefer new POSIX 200x interfaces over futimesat. * m4/utimens.m4 (gl_UTIMENS): Check for futimens, utimensat. * lib/utimens.c (gl_futimens): Use them for nanosecond resolution when available. [HAVE_BUGGY_NFS_TIME_STAMPS]: Allow C89 compilation. Signed-off-by: Eric Blake --- ChangeLog | 8 +++ lib/utimens.c | 155 +++++++++++++++++++++++++++++++--------------------------- m4/utimens.m4 | 7 ++- 3 files changed, 97 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9644194db..dbabf960e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-05-29 Eric Blake + + Prefer new POSIX 200x interfaces over futimesat. + * m4/utimens.m4 (gl_UTIMENS): Check for futimens, utimensat. + * lib/utimens.c (gl_futimens): Use them for nanosecond resolution + when available. + [HAVE_BUGGY_NFS_TIME_STAMPS]: Allow C89 compilation. + 2008-05-28 Bruno Haible * modules/stpcpy (License): Change to LGPLv2+. diff --git a/lib/utimens.c b/lib/utimens.c index e12821962..25bc96532 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -94,89 +95,101 @@ gl_futimens (int fd ATTRIBUTE_UNUSED, fsync (fd); #endif - /* There's currently no interface to set file timestamps with + /* POSIX 200x added two interfaces to set file timestamps with + nanosecond resolution. */ +#if HAVE_UTIMENSAT + if (fd < 0) + return utimensat (AT_FDCWD, file, timespec, 0); +#endif +#if HAVE_FUTIMENS + return futimens (fd, timespec); +#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. */ -#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; - } - else - t = NULL; + { +# 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; + } + else + t = NULL; + 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 (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; + if (!file) + { +# if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES)) + errno = ENOSYS; # endif - } -#endif - 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; + } - /* Prefer EBADF to ENOSYS if both error numbers apply. */ - if (errno == ENOSYS) +# if HAVE_WORKING_UTIMES + return utimes (file, t); +# else + { + struct utimbuf utimbuf; + struct utimbuf const *ut; + if (timespec) { - int fd2 = dup (fd); - int dup_errno = errno; - if (0 <= fd2) - close (fd2); - errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS); + utimbuf.actime = timespec[0].tv_sec; + utimbuf.modtime = timespec[1].tv_sec; + ut = &utimbuf; } + else + ut = NULL; - return -1; + return utime (file, ut); } - -#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 */ } -#endif +#endif /* !HAVE_FUTIMENS */ } /* Set the access and modification time stamps of FILE to be diff --git a/m4/utimens.m4 b/m4/utimens.m4 index 9ac9c3ea1..01a3184ce 100644 --- a/m4/utimens.m4 +++ b/m4/utimens.m4 @@ -1,8 +1,11 @@ -dnl Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +dnl Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software +dnl Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. +dnl serial 2 + AC_DEFUN([gl_UTIMENS], [ AC_LIBOBJ([utimens]) @@ -11,5 +14,5 @@ AC_DEFUN([gl_UTIMENS], AC_REQUIRE([gl_FUNC_UTIMES]) AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC]) AC_REQUIRE([gl_CHECK_TYPE_STRUCT_UTIMBUF]) - AC_CHECK_FUNCS_ONCE([futimes futimesat]) + AC_CHECK_FUNCS_ONCE([futimes futimesat futimens utimensat]) ]) -- 2.11.0