X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=gnu%2Futimens.c;h=6582706e9b69cb9b67fde1bfb6b14734f388f22f;hb=1a44d77d50f4fb37c0410eed04b82303624ea2ec;hp=0cf26714b165dd6d2f41203ee94c69b520c9087a;hpb=dda6367c9eac71da8f2ab1c60b3df60f19ce4755;p=debian%2Ftar diff --git a/gnu/utimens.c b/gnu/utimens.c index 0cf26714..6582706e 100644 --- a/gnu/utimens.c +++ b/gnu/utimens.c @@ -2,7 +2,7 @@ /* DO NOT EDIT! GENERATED AUTOMATICALLY! */ /* Set file access and modification times. - Copyright (C) 2003-2010 Free Software Foundation, Inc. + Copyright (C) 2003-2011 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 @@ -332,12 +332,53 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) 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 && !FUTIMESAT_NULL_BUG - if (futimesat (fd, NULL, t) == 0) - return 0; -# elif HAVE_FUTIMES + +# if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES +# if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG +# undef futimes +# define futimes(fd, t) futimesat (fd, NULL, t) +# endif if (futimes (fd, t) == 0) - return 0; + { +# if __linux__ && __GLIBC__ + /* Work around a longstanding glibc bug, still present as + of 2010-12-27. On older Linux kernels that lack both + utimensat and utimes, glibc's futimes rounds instead of + truncating when falling back on utime. The same bug + occurs in futimesat with a null 2nd arg. */ + if (t) + { + bool abig = 500000 <= t[0].tv_usec; + bool mbig = 500000 <= t[1].tv_usec; + if ((abig | mbig) && fstat (fd, &st) == 0) + { + /* If these two subtractions overflow, they'll + track the overflows inside the buggy glibc. */ + time_t adiff = st.st_atime - t[0].tv_sec; + time_t mdiff = st.st_mtime - t[1].tv_sec; + + struct timeval *tt = NULL; + struct timeval truncated_timeval[2]; + truncated_timeval[0] = t[0]; + truncated_timeval[1] = t[1]; + if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0) + { + tt = truncated_timeval; + tt[0].tv_usec = 0; + } + if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0) + { + tt = truncated_timeval; + tt[1].tv_usec = 0; + } + if (tt) + futimes (fd, tt); + } + } +# endif + + return 0; + } # endif } #endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */