Fix test-dirent link error.
[gnulib.git] / lib / utimens.c
index cc0d1e8..bdb5a25 100644 (file)
@@ -1,6 +1,6 @@
 /* Set file access and modification times.
 
-   Copyright (C) 2003-2009 Free Software Foundation, Inc.
+   Copyright (C) 2003-2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -169,6 +169,7 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
   struct timespec adjusted_timespec[2];
   struct timespec *ts = timespec ? adjusted_timespec : NULL;
   int adjustment_needed = 0;
+  struct stat st;
 
   if (ts)
     {
@@ -220,7 +221,6 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
     {
       int result;
 # if __linux__
-      struct stat st;
       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
          but work if both times are either explicitly specified or
@@ -237,6 +237,8 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
             ts[0] = get_stat_atime (&st);
           else if (ts[1].tv_nsec == UTIME_OMIT)
             ts[1] = get_stat_mtime (&st);
+          /* Note that st is good, in case utimensat gives ENOSYS.  */
+          adjustment_needed++;
         }
 # endif /* __linux__ */
 # if HAVE_UTIMENSAT
@@ -262,19 +264,20 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
         }
 # endif /* HAVE_UTIMENSAT */
 # if HAVE_FUTIMENS
-      {
-        result = futimens (fd, ts);
+      if (0 <= fd)
+        {
+          result = futimens (fd, ts);
 #  ifdef __linux__
-        /* Work around the same bug as above.  */
-        if (0 < result)
-          errno = ENOSYS;
+          /* Work around the same bug as above.  */
+          if (0 < result)
+            errno = ENOSYS;
 #  endif /* __linux__ */
-        if (result == 0 || errno != ENOSYS)
-          {
-            utimensat_works_really = 1;
-            return result;
-          }
-      }
+          if (result == 0 || errno != ENOSYS)
+            {
+              utimensat_works_really = 1;
+              return result;
+            }
+        }
 # endif /* HAVE_FUTIMENS */
     }
   utimensat_works_really = -1;
@@ -287,8 +290,8 @@ fdutimens (char const *file, int fd, struct timespec const timespec[2])
 
   if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
     {
-      struct stat st;
-      if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
+      if (adjustment_needed != 3
+          && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
         return -1;
       if (ts && update_timespec (&st, &ts))
         return 0;
@@ -422,7 +425,6 @@ lutimens (char const *file, struct timespec const timespec[2])
     {
       int result;
 # if __linux__
-      struct stat st;
       /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
          systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
          but work if both times are either explicitly specified or
@@ -439,6 +441,8 @@ lutimens (char const *file, struct timespec const timespec[2])
             ts[0] = get_stat_atime (&st);
           else if (ts[1].tv_nsec == UTIME_OMIT)
             ts[1] = get_stat_mtime (&st);
+          /* Note that st is good, in case utimensat gives ENOSYS.  */
+          adjustment_needed++;
         }
 # endif /* __linux__ */
       result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
@@ -469,7 +473,7 @@ lutimens (char const *file, struct timespec const timespec[2])
 
   if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
     {
-      if (lstat (file, &st))
+      if (adjustment_needed != 3 && lstat (file, &st))
         return -1;
       if (ts && update_timespec (&st, &ts))
         return 0;