programs/gzip: add support for the '-t' option (test file integrity)

The '-t' option of GNU gzip allows checking whether a gzip file is valid
without writing the data anywhere.  It's relatively straightforward to
support in libdeflate-gzip too, so add support for it.

Resolves https://github.com/ebiggers/libdeflate/issues/125

[EB - updated commit message]
This commit is contained in:
tansy 2021-04-07 16:19:00 +02:00 committed by Eric Biggers
parent fbada10aa9
commit 72c81b3332
2 changed files with 43 additions and 6 deletions

View File

@ -43,11 +43,12 @@ struct options {
bool decompress;
bool force;
bool keep;
bool test;
int compression_level;
const tchar *suffix;
};
static const tchar *const optstring = T("1::2::3::4::5::6::7::8::9::cdfhknS:V");
static const tchar *const optstring = T("1::2::3::4::5::6::7::8::9::cdfhknS:tV");
static void
show_usage(FILE *fp)
@ -66,6 +67,7 @@ show_usage(FILE *fp)
" -h print this help\n"
" -k don't delete input files\n"
" -S SUF use suffix SUF instead of .gz\n"
" -t test file integrity\n"
" -V show version and legal information\n",
prog_invocation_name);
}
@ -183,7 +185,8 @@ load_u32_gzip(const u8 *p)
static int
do_decompress(struct libdeflate_decompressor *decompressor,
struct file_stream *in, struct file_stream *out)
struct file_stream *in, struct file_stream *out,
const struct options *options)
{
const u8 *compressed_data = in->mmap_mem;
size_t compressed_size = in->mmap_size;
@ -258,9 +261,11 @@ do_decompress(struct libdeflate_decompressor *decompressor,
goto out;
}
ret = full_write(out, uncompressed_data, actual_out_nbytes);
if (ret != 0)
goto out;
if (!options->test) {
ret = full_write(out, uncompressed_data, actual_out_nbytes);
if (ret != 0)
goto out;
}
compressed_data += actual_in_nbytes;
compressed_size -= actual_in_nbytes;
@ -425,7 +430,7 @@ decompress_file(struct libdeflate_decompressor *decompressor, const tchar *path,
if (ret != 0)
goto out_close_out;
ret = do_decompress(decompressor, &in, &out);
ret = do_decompress(decompressor, &in, &out, options);
if (ret != 0)
goto out_close_out;
@ -534,6 +539,7 @@ tmain(int argc, tchar *argv[])
options.decompress = is_gunzip();
options.force = false;
options.keep = false;
options.test = false;
options.compression_level = 6;
options.suffix = T(".gz");
@ -583,6 +589,17 @@ tmain(int argc, tchar *argv[])
return 1;
}
break;
case 't':
options.test = true;
options.decompress = true;
options.to_stdout = true;
/*
* -t behaves just like the more commonly used -c
* option, except that -t doesn't actually write
* anything. For ease of implementation, just pretend
* that -c was specified too.
*/
break;
case 'V':
show_version();
return 0;

View File

@ -463,6 +463,26 @@ for prog in gzip gunzip; do
done
begin_test '-t (test) option works'
good_files=(
'H4sIAAAAAAAAA3PMSVTITVTIzi9JVABTIJ5jzpGZelwAX+86ehsAAAA='
'H4sIAAAAAAAAAwvJSFUoLM1MzlZIKsovz1NIy69QyCrNLShWyC9LLVIoAUrnJFZVKqTkp+txAQBqzFDrLQAAAA==')
bad_files=(
'H4sIAO1YYmAAA3PMSVTITVTIzi9JVABTIJ5jzpGZelwAX+46ehsAAAA='
'H4sIAO1YYmAAA3PMSVTITVTIzi85VABTIJ5jzpGZelwAX+86ehsAAAA='
'H4sIAAAAAAAAA3PMSVTITVTIzi9JVABTIJ5jzpGZelwAX+86ehsBAAA='
'H4sIAAAAAAAAAwvJSFUoLM1MzlZIKsovz1NIy69QyCrNLShWyC9LLVIogUrnJFZVKqTkp+txAQBqzFDrLQAAAA=='
'H4sIAAAAAAAAAwvJSFUoLM1MzlZIKsovz1NIy69QyCrNLShWyC9L')
for contents in "${good_files[@]}"; do
echo "$contents" | base64 -d | gzip -t
done
for contents in "${bad_files[@]}"; do
echo "$contents" | base64 -d > file
assert_error '\<invalid compressed data|file corrupt|unexpected end of file|Out of memory\>' \
gzip -t file
done
begin_test 'Version information'
gzip -V | grep -q Copyright
gunzip -V | grep -q Copyright