Submitted By:            Randy McMurchy <randy_at_linuxfromscratch_dot_org>
Date:                    2008-10-05
Initial Package Version: 6.12
Upstream Status:         Unknown
Origin:                  http://bugs.gentoo.org/attachment.cgi?id=155835
Description:             Fixes an issue if using a host with an older kernel


--- coreutils-6.12-orig/lib/utimens.c	2008-05-29 09:21:57.000000000 -0400
+++ coreutils-6.12/lib/utimens.c	2008-06-07 11:36:50.000000000 -0400
@@ -96,20 +96,42 @@
 #endif
 
   /* POSIX 200x added two interfaces to set file timestamps with
-     nanosecond resolution.  */
+     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)
-    return utimensat (AT_FDCWD, file, timespec, 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 0 to indicate success.
+         FIXME: remove in 2010 or whenever the offending kernels
+         are no longer in common use.  */
+      if (0 < result)
+        result = 0;
+#endif
+
+      if (result == 0 || errno != ENOSYS)
+        return result;
+    }
 #endif
 #if HAVE_FUTIMENS
-  return futimens (fd, timespec);
-#else
+  {
+    int result = futimens (fd, timespec);
+    if (result == 0 || errno != ENOSYS)
+      return result;
+  }
+#endif
 
   /* 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
+#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
     struct timeval timeval[2];
     struct timeval const *t;
     if (timespec)
@@ -125,9 +147,9 @@
 
     if (fd < 0)
       {
-#  if HAVE_FUTIMESAT
+# if HAVE_FUTIMESAT
 	return futimesat (AT_FDCWD, file, t);
-#  endif
+# endif
       }
     else
       {
@@ -141,21 +163,21 @@
 	   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 HAVE_FUTIMESAT
 	if (futimesat (fd, NULL, t) == 0)
 	  return 0;
-#  elif HAVE_FUTIMES
+# elif HAVE_FUTIMES
 	if (futimes (fd, t) == 0)
 	  return 0;
-#  endif
+# endif
       }
-# endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
+#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */
 
     if (!file)
       {
-# if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
+#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
 	errno = ENOSYS;
-# endif
+#endif
 
 	/* Prefer EBADF to ENOSYS if both error numbers apply.  */
 	if (errno == ENOSYS)
@@ -170,9 +192,9 @@
 	return -1;
       }
 
-# if HAVE_WORKING_UTIMES
+#if HAVE_WORKING_UTIMES
     return utimes (file, t);
-# else
+#else
     {
       struct utimbuf utimbuf;
       struct utimbuf const *ut;
@@ -187,9 +209,8 @@
 
       return utime (file, ut);
     }
-# endif /* !HAVE_WORKING_UTIMES */
+#endif /* !HAVE_WORKING_UTIMES */
   }
-#endif /* !HAVE_FUTIMENS */
 }
 
 /* Set the access and modification time stamps of FILE to be

