changeset 10133:bbccff5988c3

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 28 May 2008 21:29:02 -0600
parents abb18ea528b5
children e0015ef1cfee
files ChangeLog lib/utimens.c m4/utimens.m4
diffstat 3 files changed, 100 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu May 29 02:07:07 2008 +0200
+++ b/ChangeLog	Wed May 28 21:29:02 2008 -0600
@@ -1,3 +1,11 @@
+2008-05-29  Eric Blake  <ebb9@byu.net>
+
+	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  <bruno@clisp.org>
 
 	* modules/stpcpy (License): Change to LGPLv2+.
--- a/lib/utimens.c	Thu May 29 02:07:07 2008 +0200
+++ b/lib/utimens.c	Wed May 28 21:29:02 2008 -0600
@@ -26,6 +26,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <unistd.h>
 
@@ -94,89 +95,101 @@
     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 (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
-
-      /* 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 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
+      t = NULL;
+
+    if (fd < 0)
+      {
+#  if HAVE_FUTIMESAT
+	return futimesat (AT_FDCWD, file, t);
+#  endif
       }
     else
-      ut = NULL;
+      {
+	/* 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
 
-    return utime (file, ut);
+	/* 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 */
   }
-#endif
+#endif /* !HAVE_FUTIMENS */
 }
 
 /* Set the access and modification time stamps of FILE to be
--- a/m4/utimens.m4	Thu May 29 02:07:07 2008 +0200
+++ b/m4/utimens.m4	Wed May 28 21:29:02 2008 -0600
@@ -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_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])
 ])