mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-04-28 12:17:07 +00:00
Fix unlikely problems with time overflow
Also, fix some rounding errors while we’re in the neighborhood. * src/buffer.c (duration_ns, compute_duration_ns): Rename from ‘duration’ and ‘compute_duration’, and count ns rather than s, to lessen rounding error. All uses changed. (compute_duration_ns): Work even if the clock moves backward and time_t is unsigned. (print_stats): Don’t worry about null or empty TEXT, as that cannot happen. Compare double to UINTMAX_MAX + 1.0, not to UINTMAX_MAX, so that the comparison is exact. Handle the unlikely case that numbytes >= UINTMAX_MAX. * src/tar.c (parse_opt): Treat -L hugenumber as effectively infinity rather than erroring out. Prefer ckd_add to checking overflow by hand.
This commit is contained in:
55
src/buffer.c
55
src/buffer.c
@@ -249,7 +249,8 @@ clear_read_error_count (void)
|
||||
|
||||
/* Time-related functions */
|
||||
|
||||
static double duration;
|
||||
/* Time consumed during run. It is counted in ns to lessen rounding error. */
|
||||
static double duration_ns;
|
||||
|
||||
void
|
||||
set_start_time (void)
|
||||
@@ -267,14 +268,18 @@ set_volume_start_time (void)
|
||||
}
|
||||
|
||||
double
|
||||
compute_duration (void)
|
||||
compute_duration_ns (void)
|
||||
{
|
||||
struct timespec now;
|
||||
gettime (&now);
|
||||
duration += ((now.tv_sec - last_stat_time.tv_sec)
|
||||
+ (now.tv_nsec - last_stat_time.tv_nsec) / 1e9);
|
||||
gettime (&last_stat_time);
|
||||
return duration;
|
||||
struct timespec now = current_timespec ();
|
||||
|
||||
/* If the clock moves back, treat it as duration 0.
|
||||
This works even if time_t is unsigned. */
|
||||
if (timespec_cmp (last_stat_time, now) < 0)
|
||||
duration_ns += (1e9 * (now.tv_sec - last_stat_time.tv_sec)
|
||||
+ (now.tv_nsec - last_stat_time.tv_nsec));
|
||||
|
||||
last_stat_time = current_timespec ();
|
||||
return duration_ns;
|
||||
}
|
||||
|
||||
|
||||
@@ -491,19 +496,29 @@ static int
|
||||
print_stats (FILE *fp, const char *text, tarlong numbytes)
|
||||
{
|
||||
char abbr[LONGEST_HUMAN_READABLE + 1];
|
||||
char rate[LONGEST_HUMAN_READABLE + 1];
|
||||
int n = 0;
|
||||
|
||||
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
||||
double ulim = UINTMAX_MAX + 1.0;
|
||||
|
||||
if (text && text[0])
|
||||
n += fprintf (fp, "%s: ", gettext (text));
|
||||
return n + fprintf (fp, TARLONG_FORMAT " (%s, %s/s)",
|
||||
numbytes,
|
||||
human_readable (numbytes, abbr, human_opts, 1, 1),
|
||||
(0 < duration && numbytes / duration < (uintmax_t) -1
|
||||
? human_readable (numbytes / duration, rate, human_opts, 1, 1)
|
||||
: "?"));
|
||||
int n = fprintf (fp, "%s: "TARLONG_FORMAT" (", gettext (text), numbytes);
|
||||
|
||||
if (numbytes < ulim)
|
||||
n += fprintf (fp, "%s", human_readable (numbytes, abbr, human_opts, 1, 1));
|
||||
else
|
||||
n += fprintf (fp, "%g", numbytes);
|
||||
|
||||
if (!duration_ns)
|
||||
n += fprintf (fp, ")");
|
||||
else
|
||||
{
|
||||
double rate = 1e9 * numbytes / duration_ns;
|
||||
if (rate < ulim)
|
||||
n += fprintf (fp, ", %s/s)",
|
||||
human_readable (rate, abbr, human_opts, 1, 1));
|
||||
else
|
||||
n += fprintf (fp, ", %g/s)", rate);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Format totals to file FP. FORMATS is an array of strings to output
|
||||
@@ -1121,7 +1136,7 @@ close_archive (void)
|
||||
while (current_block > record_start);
|
||||
}
|
||||
|
||||
compute_duration ();
|
||||
compute_duration_ns ();
|
||||
if (verify_option)
|
||||
verify_volume ();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user