- int result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
+ int result;
+# if __linux__
+ /* 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
+ UTIME_NOW. Work around it with a preparatory lstat prior to
+ calling utimensat; fortunately, there is not much timing
+ impact due to the extra syscall even on file systems where
+ UTIME_OMIT would have worked. FIXME: Simplify this in 2012,
+ when file system bugs are no longer common. */
+ if (adjustment_needed == 2)
+ {
+ if (lstat (file, &st))
+ return -1;
+ if (ts[0].tv_nsec == UTIME_OMIT)
+ 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);