utimens: fix regression on Solaris
authorEric Blake <ebb9@byu.net>
Wed, 18 Nov 2009 13:59:44 +0000 (06:59 -0700)
committerIan Beckwith <ianb@erislabs.net>
Fri, 20 Nov 2009 00:37:34 +0000 (00:37 +0000)
Revert commit 26c5fd742f.  Solaris lacks futimens and futimes, so
futimesat is the only way to change fd timestamps.  But since
FreeBSD futimesat can't change fd timestamps, we need a configure
check to avoid the crash there.

* m4/utimens.m4 (gl_UTIMENS): Check for BSD bug.
* lib/utimens.c (fdutimens): Revert 2009-11-08 change; Solaris 10
can only change fd timestamps via futimesat.  Instead, use an
additional witness macro to avoid BSD bug.
Reported by Jim Meyering.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
lib/utimens.c
m4/utimens.m4

index 2975adc..46dd660 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-11-18  Eric Blake  <ebb9@byu.net>
+
+       utimens: fix regression on Solaris
+       * m4/utimens.m4 (gl_UTIMENS): Check for BSD bug.
+       * lib/utimens.c (fdutimens): Revert 2009-11-08 change; Solaris 10
+       can only change fd timestamps via futimesat.  Instead, use an
+       additional witness macro to avoid BSD bug.
+       Reported by Jim Meyering.
+
 2009-11-17  Simon Josefsson  <simon@josefsson.org>
 
        * gnulib-tool: Support LGPLv3+ licenses in module files.  Tiny
index bd482d7..eb63487 100644 (file)
@@ -280,9 +280,9 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
       }
     else
       {
-        /* If futimesat (above) 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
+        /* 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
@@ -290,7 +290,10 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
            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_FUTIMES
+# if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
+        if (futimesat (fd, NULL, t) == 0)
+          return 0;
+# elif HAVE_FUTIMES
         if (futimes (fd, t) == 0)
           return 0;
 # endif
@@ -299,7 +302,8 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
 
     if (!file)
       {
-#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
+#if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG)          \
+        || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
         errno = ENOSYS;
 #endif
         return -1;
index 381d087..35ef949 100644 (file)
@@ -4,7 +4,7 @@ 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 3
+dnl serial 4
 
 AC_DEFUN([gl_UTIMENS],
 [
@@ -15,4 +15,28 @@ AC_DEFUN([gl_UTIMENS],
   AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
   AC_REQUIRE([gl_CHECK_TYPE_STRUCT_UTIMBUF])
   AC_CHECK_FUNCS_ONCE([futimes futimesat futimens utimensat lutimes])
+
+  if test $ac_cv_func_futimens = no && test $ac_cv_func_futimesat = yes; then
+    dnl FreeBSD 8.0-rc2 mishandles futimesat(fd,NULL,time).  It is not
+    dnl standardized, but Solaris implemented it first and uses it as
+    dnl its only means to set fd time.
+    AC_CACHE_CHECK([whether futimesat handles NULL file],
+      [gl_cv_func_futimesat_works],
+      [touch conftest.file
+       AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stddef.h>
+#include <sys/times.h>
+]], [[    int fd = open ("conftest.file", O_RDWR);
+          if (fd < 0) return 1;
+          if (futimesat (fd, NULL, NULL)) return 2;
+        ]])],
+        [gl_cv_func_futimesat_works=yes],
+        [gl_cv_func_futimesat_works=no],
+        [gl_cv_func_futimesat_works="guessing no"])
+      rm -f conftest.file])
+    if test "$gl_cv_func_futimesat_works" != yes; then
+      AC_DEFINE([FUTIMESAT_NULL_BUG], [1],
+        [Define to 1 if futimesat mishandles a NULL file name.])
+    fi
+  fi
 ])