Handle enormous record sizes better
Formerly the code could misbehave when the user specified a record size greater than min (INT_MAX * 512 + 511, PTRDIFF_MAX, SSIZE_MAX). * src/delete.c (new_blocks, delete_archive_members): * src/system.c (sys_exec_info_script): * src/tar.c (blocking_factor, record_size): Don’t limit blocking factor to INT_MAX. Prefer signed type for record_size. Do not exceed IDX_MAX or SSIZE_MAX for record_size; the SSIZE_MAX limit is needed so that ‘read’ and ‘write’ calls behave sensibly.
This commit is contained in:
@@ -985,11 +985,11 @@ short_read (size_t status)
|
||||
|
||||
if (! read_full_records)
|
||||
{
|
||||
unsigned long rest = record_size - left;
|
||||
idx_t rest = record_size - left;
|
||||
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("Unaligned block (%lu byte) in archive",
|
||||
"Unaligned block (%lu bytes) in archive",
|
||||
ngettext ("Unaligned block (%td byte) in archive",
|
||||
"Unaligned block (%td bytes) in archive",
|
||||
rest),
|
||||
rest));
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ extern enum archive_format archive_format;
|
||||
are always related, the second being BLOCKSIZE times the first. They do
|
||||
not have _option in their name, even if their values is derived from
|
||||
option decoding, as these are especially important in tar. */
|
||||
extern int blocking_factor;
|
||||
extern size_t record_size;
|
||||
extern idx_t blocking_factor;
|
||||
extern idx_t record_size;
|
||||
|
||||
extern bool absolute_names_option;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <rmt.h>
|
||||
|
||||
static union block *new_record;
|
||||
static int new_blocks;
|
||||
static idx_t new_blocks;
|
||||
static bool acting_as_filter;
|
||||
|
||||
/* The number of records skipped at the start of the archive, when
|
||||
@@ -363,11 +363,11 @@ delete_archive_members (void)
|
||||
/* Write the end of tape. FIXME: we can't use write_eot here,
|
||||
as it gets confused when the input is at end of file. */
|
||||
|
||||
int total_zero_blocks = 0;
|
||||
idx_t total_zero_blocks = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int zero_blocks = blocking_factor - new_blocks;
|
||||
idx_t zero_blocks = blocking_factor - new_blocks;
|
||||
memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
|
||||
total_zero_blocks += zero_blocks;
|
||||
write_record (total_zero_blocks < 2);
|
||||
|
||||
@@ -875,10 +875,10 @@ sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
/* Child */
|
||||
setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
|
||||
setenv ("TAR_ARCHIVE", *archive_name, 1);
|
||||
char intbuf[INT_BUFSIZE_BOUND (int)];
|
||||
char intbuf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
sprintf (intbuf, "%d", volume_number);
|
||||
setenv ("TAR_VOLUME", intbuf, 1);
|
||||
sprintf (intbuf, "%d", blocking_factor);
|
||||
sprintf (intbuf, "%jd", blocking_factor);
|
||||
setenv ("TAR_BLOCKING_FACTOR", intbuf, 1);
|
||||
setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
|
||||
setenv ("TAR_FORMAT",
|
||||
@@ -922,7 +922,7 @@ sys_exec_checkpoint_script (const char *script_name,
|
||||
char intbuf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
sprintf (intbuf, "%jd", checkpoint_number);
|
||||
setenv ("TAR_CHECKPOINT", intbuf, 1);
|
||||
sprintf (intbuf, "%d", blocking_factor);
|
||||
sprintf (intbuf, "%td", blocking_factor);
|
||||
setenv ("TAR_BLOCKING_FACTOR", intbuf, 1);
|
||||
setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
|
||||
setenv ("TAR_FORMAT",
|
||||
|
||||
10
src/tar.c
10
src/tar.c
@@ -34,8 +34,8 @@
|
||||
/* Define variables declared in common.h that belong to tar.c. */
|
||||
enum subcommand subcommand_option;
|
||||
enum archive_format archive_format;
|
||||
int blocking_factor;
|
||||
size_t record_size;
|
||||
idx_t blocking_factor;
|
||||
idx_t record_size;
|
||||
bool absolute_names_option;
|
||||
bool utc_option;
|
||||
bool full_time_option;
|
||||
@@ -1502,7 +1502,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
if (! (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK
|
||||
&& !ckd_add (&blocking_factor, u, 0)
|
||||
&& 0 < blocking_factor
|
||||
&& !ckd_mul (&record_size, u, BLOCKSIZE)))
|
||||
&& !ckd_mul (&record_size, u, BLOCKSIZE)
|
||||
&& record_size <= min (SSIZE_MAX, SIZE_MAX)))
|
||||
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
|
||||
_("Invalid blocking factor")));
|
||||
}
|
||||
@@ -2124,7 +2125,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
uintmax_t u;
|
||||
|
||||
if (! (xstrtoumax (arg, NULL, 10, &u, TAR_SIZE_SUFFIXES) == LONGINT_OK
|
||||
&& !ckd_add (&record_size, u, 0)))
|
||||
&& !ckd_add (&record_size, u, 0)
|
||||
&& record_size <= min (SSIZE_MAX, SIZE_MAX)))
|
||||
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
|
||||
_("Invalid record size")));
|
||||
if (record_size % BLOCKSIZE != 0)
|
||||
|
||||
Reference in New Issue
Block a user