From 223be714a9077de8f18e0344407bf5c13d49b2b1 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 4 Nov 2016 20:15:42 -0700 Subject: [PATCH 3/3] gzip: minor time stamp cleanups * NEWS: Document this. * gzip.c (get_method): Do not warn about MTIME out of range. This should avoid useless chatter on hosts with 32-bit time_t after the year 2038 (!). (do_list): Do not pass junk time stamp to localtime. (copy_stat): Do not report "time stamp restored" if restoration fails. --- NEWS | 11 ++++++----- gzip.c | 40 +++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/NEWS b/NEWS index 6532550..8d0e100 100644 --- a/NEWS +++ b/NEWS @@ -4,11 +4,12 @@ GNU gzip NEWS -*- outline -*- ** Bug fixes - gzip now warns about file time stamps out of gzip range, or out of - time_t range, instead of silently continuing, sometimes with - undefined behavior. This affects time stamps before 1970 or after - 2106, and time stamps after 2038 on 32-bit platforms. - [bug present since the beginning] + When converting time stamps to gzip file format (32-bit unsigned) or + to time_t format (system-dependent), gzip now ignores out-of-range + values instead of shoehorning them into the destination format, + sometimes with undefined behavior. This affects time stamps before + 1970 and after 2106, and time stamps after 2038 on platforms with + 32-bit signed time_t. [bug present since the beginning] Support for VMS and Amiga has been removed. It was not working anyway, and it reportedly caused file name glitches on MS-Windowsish platforms. diff --git a/gzip.c b/gzip.c index dccdb89..17f5709 100644 --- a/gzip.c +++ b/gzip.c @@ -189,12 +189,17 @@ static int foreground = 0; /* set if program run in foreground */ int save_orig_name; /* set if original name must be saved */ static int last_member; /* set for .zip and .Z files */ static int part_nb; /* number of parts in .gz file */ - struct timespec time_stamp; /* original time stamp (modification time) */ off_t ifile_size; /* input file size, -1 for devices (debug only) */ static char *env; /* contents of GZIP env variable */ static char const *z_suffix; /* default suffix (can be set with --suffix) */ static size_t z_len; /* strlen(z_suffix) */ +/* The original time stamp (modification time). Its tv_nsec component + is negative if the original time is unknown or is out of time_t + range; the latter can happen on hosts with 32-bit signed time_t + because the gzip format's MTIME is 32-bit unsigned. */ +struct timespec time_stamp; + /* The set of signals that are caught. */ static sigset_t caught_signals; @@ -1534,17 +1539,10 @@ local int get_method(in) stamp |= ((ulg)get_byte()) << 8; stamp |= ((ulg)get_byte()) << 16; stamp |= ((ulg)get_byte()) << 24; - if (stamp != 0 && !no_time) + if (!no_time && 0 < stamp && stamp <= TYPE_MAXIMUM (time_t)) { - if (stamp <= TYPE_MAXIMUM (time_t)) - { - time_stamp.tv_sec = stamp; - time_stamp.tv_nsec = 0; - } - else - WARN ((stderr, - "%s: %s: MTIME %lu out of range for this platform\n", - program_name, ifname, stamp)); + time_stamp.tv_sec = stamp; + time_stamp.tv_nsec = 0; } magic[8] = get_byte (); /* Ignore extra flags. */ @@ -1773,7 +1771,9 @@ local void do_list(ifd, method) static char const month_abbr[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - struct tm *tm = localtime (&time_stamp.tv_sec); + struct tm *tm = (time_stamp.tv_nsec < 0 + ? NULL + : localtime (&time_stamp.tv_sec)); printf ("%5s %08lx ", methods[method], crc); if (tm) printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon], @@ -1919,21 +1919,23 @@ local void copy_stat(ifstat) int r; #ifndef NO_UTIME + bool restoring; struct timespec timespec[2]; timespec[0] = get_stat_atime (ifstat); timespec[1] = get_stat_mtime (ifstat); + restoring = (decompress && 0 <= time_stamp.tv_nsec + && ! (timespec[1].tv_sec == time_stamp.tv_sec + && timespec[1].tv_nsec == time_stamp.tv_nsec)); + if (restoring) + timespec[1] = time_stamp; - if (decompress && 0 <= time_stamp.tv_nsec - && ! (timespec[1].tv_sec == time_stamp.tv_sec - && timespec[1].tv_nsec == time_stamp.tv_nsec)) + if (fdutimens (ofd, ofname, timespec) == 0) { - timespec[1] = time_stamp; - if (verbose > 1) { + if (restoring && 1 < verbose) { fprintf(stderr, "%s: time stamp restored\n", ofname); } } - - if (fdutimens (ofd, ofname, timespec) != 0) + else { int e = errno; WARN ((stderr, "%s: ", program_name)); -- 2.7.4