diff lib/utimens.c @ 12194:16c7c4fa9754

utimensat: work around Solaris 9 bug utimes("file/",times) mistakenly succeeds. This commit doesn't fix utimes, but does make utimensat be careful before calling utimes. The test is now enhanced to test trailing slashes and directories. Meanwhile, cygwin 1.5 stat() on a directory changes atime (it does a readdir under the hood to populate st_nlink), so only mtime of a directory is reliable enough for testing. Cygwin 1.7 no longer has this problem, because it no longer wastes time on st_nlink. * lib/utimens.c (fdutimens, lutimens): Force a stat if platform has trailing slash bugs. * tests/test-lutimens.h (test_lutimens): Enhance test. * tests/test-utimens.h (test_utimens): Likewise. * doc/posix-functions/utime.texi (utime): Document the bug. * doc/posix-functions/utimes.texi (utimes): Likewise. * doc/posix-functions/utimensat.texi (utimensat): Likewise. * doc/glibc-functions/futimesat.texi (futimesat): Likewise. * doc/glibc-functions/lutimes.texi (lutimes): Mention utimens. * doc/posix-functions/futimens.texi (futimens): Mention limitation. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Tue, 20 Oct 2009 16:47:36 -0600
parents 73f2681e0524
children 993b8355a1cf
line wrap: on
line diff
--- a/lib/utimens.c
+++ b/lib/utimens.c
@@ -60,6 +60,12 @@
 static int utimensat_works_really;
 #endif /* HAVE_UTIMENSAT || HAVE_UTIMENSAT */
 
+/* Solaris 9 mistakenly succeeds when given a non-directory with a
+   trailing slash.  Force the use of rpl_stat for a fix.  */
+#ifndef REPLACE_FUNC_STAT_FILE
+# define REPLACE_FUNC_STAT_FILE 0
+#endif
+
 /* Validate the requested timestamps.  Return 0 if the resulting
    timespec can be used for utimensat (after possibly modifying it to
    work around bugs in utimensat).  Return 1 if the timespec needs
@@ -242,12 +248,12 @@
      nanosecond resolution, so do the best we can, discarding any
      fractional part of the timestamp.  */
 
-  if (adjustment_needed)
+  if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
     {
       struct stat st;
       if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
         return -1;
-      if (update_timespec (&st, &ts))
+      if (ts && update_timespec (&st, &ts))
         return 0;
     }
 
@@ -401,11 +407,11 @@
      nanosecond resolution, so do the best we can, discarding any
      fractional part of the timestamp.  */
 
-  if (adjustment_needed)
+  if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
     {
       if (lstat (file, &st))
         return -1;
-      if (update_timespec (&st, &ts))
+      if (ts && update_timespec (&st, &ts))
         return 0;
     }
 
@@ -429,7 +435,7 @@
 #endif /* HAVE_LUTIMES */
 
   /* Out of luck for symlinks, but we still handle regular files.  */
-  if (!adjustment_needed && lstat (file, &st))
+  if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
     return -1;
   if (!S_ISLNK (st.st_mode))
     return fdutimens (file, -1, ts);