mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpgtar: Improve error messages.
* tools/gpgtar.h (struct tarinfo_s): New. * tools/gpgtar.c (cmd, skip_crypto, files_from, null_names): Move global vars more to the top. (set_cmd): Rename 'cmd' to 'c'. * tools/gpgtar-list.c (parse_header): Add arg 'info' and improve error messages. (read_header): Add arg 'info' and update counter. (skip_data): Ditto. (gpgtar_list): Pass info object to read functions. (gpgtar_read_header): Add arg 'info'. * tools/gpgtar-extract.c (gpgtar_extract): add arg 'info' and pass on. (extract_regular): Add arg 'info' and update counter. -- This now prints the block number of a header with error. Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 72feb8fa8280aba674573a1afc955a92e8065242)
This commit is contained in:
parent
d2a7f9078a
commit
2e4151a341
@ -36,7 +36,7 @@
|
||||
|
||||
static gpg_error_t
|
||||
extract_regular (estream_t stream, const char *dirname,
|
||||
tar_header_t hdr)
|
||||
tarinfo_t info, tar_header_t hdr)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char record[RECORDSIZE];
|
||||
@ -70,6 +70,7 @@ extract_regular (estream_t stream, const char *dirname,
|
||||
err = read_record (stream, record);
|
||||
if (err)
|
||||
goto leave;
|
||||
info->nblocks++;
|
||||
n++;
|
||||
if (n < hdr->nrecords || (hdr->size && !(hdr->size % RECORDSIZE)))
|
||||
nbytes = RECORDSIZE;
|
||||
@ -163,7 +164,8 @@ extract_directory (const char *dirname, tar_header_t hdr)
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
extract (estream_t stream, const char *dirname, tar_header_t hdr)
|
||||
extract (estream_t stream, const char *dirname, tarinfo_t info,
|
||||
tar_header_t hdr)
|
||||
{
|
||||
gpg_error_t err;
|
||||
size_t n;
|
||||
@ -190,7 +192,7 @@ extract (estream_t stream, const char *dirname, tar_header_t hdr)
|
||||
}
|
||||
|
||||
if (hdr->typeflag == TF_REGULAR || hdr->typeflag == TF_UNKNOWN)
|
||||
err = extract_regular (stream, dirname, hdr);
|
||||
err = extract_regular (stream, dirname, info, hdr);
|
||||
else if (hdr->typeflag == TF_DIRECTORY)
|
||||
err = extract_directory (dirname, hdr);
|
||||
else
|
||||
@ -200,7 +202,11 @@ extract (estream_t stream, const char *dirname, tar_header_t hdr)
|
||||
log_info ("unsupported file type %d for '%s' - skipped\n",
|
||||
(int)hdr->typeflag, hdr->name);
|
||||
for (err = 0, n=0; !err && n < hdr->nrecords; n++)
|
||||
err = read_record (stream, record);
|
||||
{
|
||||
err = read_record (stream, record);
|
||||
if (!err)
|
||||
info->nblocks++;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -282,6 +288,10 @@ gpgtar_extract (const char *filename, int decrypt)
|
||||
tar_header_t header = NULL;
|
||||
const char *dirprefix = NULL;
|
||||
char *dirname = NULL;
|
||||
struct tarinfo_s tarinfo_buffer;
|
||||
tarinfo_t tarinfo = &tarinfo_buffer;
|
||||
|
||||
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
|
||||
|
||||
if (filename)
|
||||
{
|
||||
@ -378,11 +388,11 @@ gpgtar_extract (const char *filename, int decrypt)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
err = gpgtar_read_header (stream, &header);
|
||||
err = gpgtar_read_header (stream, tarinfo, &header);
|
||||
if (err || header == NULL)
|
||||
goto leave;
|
||||
|
||||
err = extract (stream, dirname, header);
|
||||
err = extract (stream, dirname, tarinfo, header);
|
||||
if (err)
|
||||
goto leave;
|
||||
xfree (header);
|
||||
|
@ -77,12 +77,15 @@ parse_xoctal (const void *data, size_t length, const char *filename)
|
||||
|
||||
|
||||
static tar_header_t
|
||||
parse_header (const void *record, const char *filename)
|
||||
parse_header (const void *record, const char *filename, tarinfo_t info)
|
||||
{
|
||||
const struct ustar_raw_header *raw = record;
|
||||
size_t n, namelen, prefixlen;
|
||||
tar_header_t header;
|
||||
int use_prefix;
|
||||
int anyerror = 0;
|
||||
|
||||
info->headerblock = info->nblocks - 1;
|
||||
|
||||
use_prefix = (!memcmp (raw->magic, "ustar", 5)
|
||||
&& (raw->magic[5] == ' ' || !raw->magic[5]));
|
||||
@ -91,27 +94,31 @@ parse_header (const void *record, const char *filename)
|
||||
for (namelen=0; namelen < sizeof raw->name && raw->name[namelen]; namelen++)
|
||||
;
|
||||
if (namelen == sizeof raw->name)
|
||||
log_info ("%s: warning: name not terminated by a nul byte\n", filename);
|
||||
{
|
||||
log_info ("%s: warning: name not terminated by a nul\n", filename);
|
||||
anyerror = 1;
|
||||
}
|
||||
for (n=namelen+1; n < sizeof raw->name; n++)
|
||||
if (raw->name[n])
|
||||
{
|
||||
log_info ("%s: warning: garbage after name\n", filename);
|
||||
anyerror = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (use_prefix && raw->prefix[0])
|
||||
{
|
||||
for (prefixlen=0; (prefixlen < sizeof raw->prefix
|
||||
&& raw->prefix[prefixlen]); prefixlen++)
|
||||
;
|
||||
if (prefixlen == sizeof raw->prefix)
|
||||
log_info ("%s: warning: prefix not terminated by a nul byte\n",
|
||||
filename);
|
||||
log_info ("%s: warning: prefix not terminated by a nul (block %llu)\n",
|
||||
filename, info->headerblock);
|
||||
for (n=prefixlen+1; n < sizeof raw->prefix; n++)
|
||||
if (raw->prefix[n])
|
||||
{
|
||||
log_info ("%s: warning: garbage after prefix\n", filename);
|
||||
anyerror = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -156,25 +163,32 @@ parse_header (const void *record, const char *filename)
|
||||
default: header->typeflag = TF_UNKNOWN; break;
|
||||
}
|
||||
|
||||
|
||||
/* Compute the number of data records following this header. */
|
||||
if (header->typeflag == TF_REGULAR || header->typeflag == TF_UNKNOWN)
|
||||
header->nrecords = (header->size + RECORDSIZE-1)/RECORDSIZE;
|
||||
else
|
||||
header->nrecords = 0;
|
||||
|
||||
if (anyerror)
|
||||
{
|
||||
log_info ("%s: header block %llu is corrupt"
|
||||
" (size=%llu type=%d nrec=%llu)\n",
|
||||
filename, info->headerblock,
|
||||
header->size, header->typeflag, header->nrecords);
|
||||
/* log_printhex (record, RECORDSIZE, " "); */
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read the next block, assming it is a tar header. Returns a header
|
||||
/* Read the next block, assuming it is a tar header. Returns a header
|
||||
object on success in R_HEADER, or an error. If the stream is
|
||||
consumed, R_HEADER is set to NULL. In case of an error an error
|
||||
message has been printed. */
|
||||
static gpg_error_t
|
||||
read_header (estream_t stream, tar_header_t *r_header)
|
||||
read_header (estream_t stream, tarinfo_t info, tar_header_t *r_header)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char record[RECORDSIZE];
|
||||
@ -183,6 +197,7 @@ read_header (estream_t stream, tar_header_t *r_header)
|
||||
err = read_record (stream, record);
|
||||
if (err)
|
||||
return err;
|
||||
info->nblocks++;
|
||||
|
||||
for (i=0; i < RECORDSIZE && !record[i]; i++)
|
||||
;
|
||||
@ -193,6 +208,7 @@ read_header (estream_t stream, tar_header_t *r_header)
|
||||
err = read_record (stream, record);
|
||||
if (err)
|
||||
return err;
|
||||
info->nblocks++;
|
||||
|
||||
for (i=0; i < RECORDSIZE && !record[i]; i++)
|
||||
;
|
||||
@ -207,7 +223,7 @@ read_header (estream_t stream, tar_header_t *r_header)
|
||||
}
|
||||
}
|
||||
|
||||
*r_header = parse_header (record, es_fname_get (stream));
|
||||
*r_header = parse_header (record, es_fname_get (stream), info);
|
||||
return *r_header ? 0 : gpg_error_from_syserror ();
|
||||
}
|
||||
|
||||
@ -215,7 +231,7 @@ read_header (estream_t stream, tar_header_t *r_header)
|
||||
/* Skip the data records according to HEADER. Prints an error message
|
||||
on error and return -1. */
|
||||
static int
|
||||
skip_data (estream_t stream, tar_header_t header)
|
||||
skip_data (estream_t stream, tarinfo_t info, tar_header_t header)
|
||||
{
|
||||
char record[RECORDSIZE];
|
||||
unsigned long long n;
|
||||
@ -224,6 +240,7 @@ skip_data (estream_t stream, tar_header_t header)
|
||||
{
|
||||
if (read_record (stream, record))
|
||||
return -1;
|
||||
info->nblocks++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -278,6 +295,10 @@ gpgtar_list (const char *filename, int decrypt)
|
||||
estream_t stream;
|
||||
estream_t cipher_stream = NULL;
|
||||
tar_header_t header = NULL;
|
||||
struct tarinfo_s tarinfo_buffer;
|
||||
tarinfo_t tarinfo = &tarinfo_buffer;
|
||||
|
||||
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
|
||||
|
||||
if (filename)
|
||||
{
|
||||
@ -339,13 +360,13 @@ gpgtar_list (const char *filename, int decrypt)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
err = read_header (stream, &header);
|
||||
err = read_header (stream, tarinfo, &header);
|
||||
if (err || header == NULL)
|
||||
goto leave;
|
||||
|
||||
print_header (header, es_stdout);
|
||||
|
||||
if (skip_data (stream, header))
|
||||
if (skip_data (stream, tarinfo, header))
|
||||
goto leave;
|
||||
xfree (header);
|
||||
header = NULL;
|
||||
@ -362,9 +383,9 @@ gpgtar_list (const char *filename, int decrypt)
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpgtar_read_header (estream_t stream, tar_header_t *r_header)
|
||||
gpgtar_read_header (estream_t stream, tarinfo_t info, tar_header_t *r_header)
|
||||
{
|
||||
return read_header (stream, r_header);
|
||||
return read_header (stream, info, r_header);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -136,6 +136,14 @@ static ARGPARSE_OPTS tar_opts[] = {
|
||||
};
|
||||
|
||||
|
||||
/* Global flags. */
|
||||
enum cmd_and_opt_values cmd = 0;
|
||||
int skip_crypto = 0;
|
||||
const char *files_from = NULL;
|
||||
int null_names = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
/* Print usage information and provide strings for help. */
|
||||
static const char *
|
||||
@ -169,23 +177,25 @@ my_strusage( int level )
|
||||
static void
|
||||
set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
|
||||
{
|
||||
enum cmd_and_opt_values cmd = *ret_cmd;
|
||||
enum cmd_and_opt_values c = *ret_cmd;
|
||||
|
||||
if (!cmd || cmd == new_cmd)
|
||||
cmd = new_cmd;
|
||||
else if (cmd == aSign && new_cmd == aEncrypt)
|
||||
cmd = aSignEncrypt;
|
||||
else if (cmd == aEncrypt && new_cmd == aSign)
|
||||
cmd = aSignEncrypt;
|
||||
if (!c || c == new_cmd)
|
||||
c = new_cmd;
|
||||
else if (c == aSign && new_cmd == aEncrypt)
|
||||
c = aSignEncrypt;
|
||||
else if (c == aEncrypt && new_cmd == aSign)
|
||||
c = aSignEncrypt;
|
||||
else
|
||||
{
|
||||
log_error (_("conflicting commands\n"));
|
||||
exit (2);
|
||||
}
|
||||
|
||||
*ret_cmd = cmd;
|
||||
*ret_cmd = c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Shell-like argument splitting.
|
||||
|
||||
For compatibility with gpg-zip we accept arguments for GnuPG and
|
||||
@ -287,14 +297,9 @@ shell_parse_argv (const char *s, int *r_argc, char ***r_argv)
|
||||
gpgrt_annotate_leaked_object (*r_argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Global flags. */
|
||||
enum cmd_and_opt_values cmd = 0;
|
||||
int skip_crypto = 0;
|
||||
const char *files_from = NULL;
|
||||
int null_names = 0;
|
||||
|
||||
|
||||
/* Command line parsing. */
|
||||
static void
|
||||
parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
|
||||
|
@ -41,12 +41,21 @@ struct
|
||||
} opt;
|
||||
|
||||
|
||||
/* An info structure to avoid global variables. */
|
||||
struct tarinfo_s
|
||||
{
|
||||
unsigned long long nblocks; /* Count of processed blocks. */
|
||||
unsigned long long headerblock; /* Number of current header block. */
|
||||
};
|
||||
typedef struct tarinfo_s *tarinfo_t;
|
||||
|
||||
|
||||
/* The size of a tar record. All IO is done in chunks of this size.
|
||||
Note that we don't care about blocking because this version of tar
|
||||
is not expected to be used directly on a tape drive in fact it is
|
||||
used in a pipeline with GPG and thus any blocking would be
|
||||
useless. */
|
||||
#define RECORDSIZE 512
|
||||
#define RECORDSIZE 512
|
||||
|
||||
|
||||
/* Description of the USTAR header format. */
|
||||
@ -64,16 +73,16 @@ struct ustar_raw_header
|
||||
char magic[6];
|
||||
char version[2];
|
||||
char uname[32];
|
||||
char gname[32];
|
||||
char devmajor[8];
|
||||
char gname[32];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char prefix[155];
|
||||
char prefix[155];
|
||||
char pad[12];
|
||||
};
|
||||
|
||||
|
||||
/* Filetypes as defined by USTAR. */
|
||||
typedef enum
|
||||
typedef enum
|
||||
{
|
||||
TF_REGULAR,
|
||||
TF_HARDLINK,
|
||||
@ -93,7 +102,7 @@ struct tar_header_s;
|
||||
typedef struct tar_header_s *tar_header_t;
|
||||
struct tar_header_s
|
||||
{
|
||||
tar_header_t next; /* Used to build a linked list iof entries. */
|
||||
tar_header_t next; /* Used to build a linked list of entries. */
|
||||
|
||||
unsigned long mode; /* The file mode. */
|
||||
unsigned long nlink; /* Number of hard links. */
|
||||
@ -106,7 +115,7 @@ struct tar_header_s
|
||||
that 32 bit and thus allows tracking
|
||||
times beyond 2106. */
|
||||
typeflag_t typeflag; /* The type of the file. */
|
||||
|
||||
|
||||
|
||||
unsigned long long nrecords; /* Number of data records. */
|
||||
|
||||
@ -126,7 +135,8 @@ gpg_error_t gpgtar_extract (const char *filename, int decrypt);
|
||||
|
||||
/*-- gpgtar-list.c --*/
|
||||
gpg_error_t gpgtar_list (const char *filename, int decrypt);
|
||||
gpg_error_t gpgtar_read_header (estream_t stream, tar_header_t *r_header);
|
||||
gpg_error_t gpgtar_read_header (estream_t stream, tarinfo_t info,
|
||||
tar_header_t *r_header);
|
||||
void gpgtar_print_header (tar_header_t header, estream_t out);
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user