Merging upstream version 0.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e39d8907e0
commit
f4329ad86e
13 changed files with 378 additions and 275 deletions
178
main.c
178
main.c
|
@ -1,24 +1,24 @@
|
|||
/* Xlunzip - Test tool for the lzip_decompress linux module
|
||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
||||
/* Xlunzip - Test tool for the lzip_decompress linux module
|
||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file, 3 for an internal consistency error
|
||||
(eg, bug) which caused xlunzip to panic.
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file, 3 for an internal consistency error
|
||||
(eg, bug) which caused xlunzip to panic.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
@ -94,21 +94,20 @@ static bool delete_output_on_interrupt = false;
|
|||
|
||||
static void show_help( void )
|
||||
{
|
||||
printf( "Xlunzip is a test tool for the lzip decompression code of my lzip patch\n"
|
||||
"for linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress\n"
|
||||
"linux module as a backend. Xlunzip tests the module for stream,\n"
|
||||
"buffer-to-buffer and mixed decompression modes, including in-place\n"
|
||||
"decompression (using the same buffer for input and output). You can use\n"
|
||||
"xlunzip to verify that the module produces correct results when\n"
|
||||
"decompressing single member files, multimember files, or the\n"
|
||||
"concatenation of two or more compressed files. Xlunzip can be used with\n"
|
||||
"unzcrash to test the robustness of the module to the decompression of\n"
|
||||
"corrupted data.\n"
|
||||
"\nNote that the in-place decompression of concatenated files can't be\n"
|
||||
"guaranteed to work because an arbitrarily low compression ratio of the\n"
|
||||
"last part of the data can be achieved by appending enough empty\n"
|
||||
"compressed members to a file, masking a high compression ratio at the\n"
|
||||
"beginning of the data.\n"
|
||||
printf( "Xlunzip is a test tool for the lzip decompression code of my lzip patch for\n"
|
||||
"linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux\n"
|
||||
"module as a backend. Xlunzip tests the module for stream, buffer-to-buffer,\n"
|
||||
"and mixed decompression modes, including in-place decompression (using the\n"
|
||||
"same buffer for input and output). You can use xlunzip to verify that the\n"
|
||||
"module produces correct results when decompressing single member files,\n"
|
||||
"multimember files, or the concatenation of two or more compressed files.\n"
|
||||
"Xlunzip can be used with unzcrash to test the robustness of the module to\n"
|
||||
"the decompression of corrupted data.\n"
|
||||
"\nThe distributed index feature of the lzip format allows xlunzip to\n"
|
||||
"decompress concatenated files in place. This can't be guaranteed to work\n"
|
||||
"with formats like gzip or bzip2 because they can't detect whether a high\n"
|
||||
"compression ratio in the first members of the multimember data is being\n"
|
||||
"masked by a low compression ratio in the last members.\n"
|
||||
"\nUsage: %s [options] [files]\n", invocation_name );
|
||||
printf( "\nOptions:\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
|
@ -118,7 +117,7 @@ static void show_help( void )
|
|||
" -f, --force overwrite existing output files\n"
|
||||
" -I, --in-place decompress or test using only one buffer\n"
|
||||
" -k, --keep keep (don't delete) input files\n"
|
||||
" -o, --output=<file> if reading standard input, write to <file>\n"
|
||||
" -o, --output=<file> write to <file>, keep input files\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -t, --test test compressed file integrity\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
|
@ -157,11 +156,7 @@ static void * resize_buffer( void * buf, const unsigned min_size )
|
|||
{
|
||||
if( buf ) buf = realloc( buf, min_size );
|
||||
else buf = malloc( min_size );
|
||||
if( !buf )
|
||||
{
|
||||
show_error( "Not enough memory.", 0, false );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
if( !buf ) { show_error( mem_msg, 0, false ); cleanup_and_fail( 1 ); }
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -316,7 +311,7 @@ static void set_d_outname( const char * const name, const int eindex )
|
|||
|
||||
|
||||
static int open_instream( const char * const name, struct stat * const in_statsp,
|
||||
const bool no_ofile )
|
||||
const bool one_to_one )
|
||||
{
|
||||
int infd = open( name, O_RDONLY | O_BINARY );
|
||||
if( infd < 0 )
|
||||
|
@ -328,13 +323,12 @@ static int open_instream( const char * const name, struct stat * const in_statsp
|
|||
const bool can_read = ( i == 0 &&
|
||||
( S_ISBLK( mode ) || S_ISCHR( mode ) ||
|
||||
S_ISFIFO( mode ) || S_ISSOCK( mode ) ) );
|
||||
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) )
|
||||
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
|
||||
program_name, name,
|
||||
( can_read && !no_ofile ) ?
|
||||
",\n and '--stdout' was not specified" : "" );
|
||||
program_name, name, ( can_read && one_to_one ) ?
|
||||
",\n and neither '-c' nor '-o' were specified" : "" );
|
||||
close( infd );
|
||||
infd = -1;
|
||||
}
|
||||
|
@ -343,11 +337,11 @@ static int open_instream( const char * const name, struct stat * const in_statsp
|
|||
}
|
||||
|
||||
|
||||
static bool open_outstream( const bool force, const bool from_stdin )
|
||||
static bool open_outstream( const bool force, const bool protect )
|
||||
{
|
||||
const mode_t usr_rw = S_IRUSR | S_IWUSR;
|
||||
const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
const mode_t outfd_mode = from_stdin ? all_rw : usr_rw;
|
||||
const mode_t outfd_mode = protect ? usr_rw : all_rw;
|
||||
int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
|
||||
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
||||
|
||||
|
@ -399,7 +393,7 @@ static void signal_handler( int sig )
|
|||
}
|
||||
|
||||
|
||||
/* Set permissions, owner, and times. */
|
||||
/* Set permissions, owner, and times. */
|
||||
static void close_and_set_permissions( const struct stat * const in_statsp )
|
||||
{
|
||||
bool warning = false;
|
||||
|
@ -499,7 +493,7 @@ static int decompress( struct Pretty_print * const pp, const long cl_insize,
|
|||
long in_pos, out_pos;
|
||||
int retval;
|
||||
if( ( in_len > 0 && !inbuf ) || ( out_size > 0 && !outbuf ) )
|
||||
{ show_error( "Not enough memory.", 0, false ); return 1; }
|
||||
{ show_error( mem_msg, 0, false ); return 1; }
|
||||
|
||||
if( inbuf )
|
||||
{
|
||||
|
@ -544,6 +538,9 @@ void show_results( struct Pretty_print * const pp, const long in_pos,
|
|||
}
|
||||
|
||||
|
||||
static inline void set_retval( int * retval, const int new_val )
|
||||
{ if( *retval < new_val ) *retval = new_val; }
|
||||
|
||||
static void show_error( const char * const msg, const int errcode,
|
||||
const bool help )
|
||||
{
|
||||
|
@ -623,7 +620,7 @@ int main( const int argc, const char * const argv[] )
|
|||
if( argc > 0 ) invocation_name = argv[0];
|
||||
|
||||
if( !ap_init( &parser, argc, argv, options, 0 ) )
|
||||
{ show_error( "Not enough memory.", 0, false ); return 1; }
|
||||
{ show_error( mem_msg, 0, false ); return 1; }
|
||||
if( ap_error( &parser ) ) /* bad option */
|
||||
{ show_error( ap_error( &parser ), 0, true ); return 1; }
|
||||
|
||||
|
@ -641,7 +638,8 @@ int main( const int argc, const char * const argv[] )
|
|||
case 'I': in_place = true; break;
|
||||
case 'k': keep_input_files = true; break;
|
||||
case 'n': break;
|
||||
case 'o': default_output_filename = arg; break;
|
||||
case 'o': if( strcmp( arg, "-" ) == 0 ) to_stdout = true;
|
||||
else { default_output_filename = arg; } break;
|
||||
case 'q': verbosity = -1; break;
|
||||
case 't': testing = true; break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
|
@ -672,64 +670,44 @@ int main( const int argc, const char * const argv[] )
|
|||
if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true;
|
||||
}
|
||||
|
||||
if( testing )
|
||||
outfd = -1;
|
||||
if( testing ) to_stdout = false; /* apply overrides */
|
||||
if( testing || to_stdout ) default_output_filename = "";
|
||||
|
||||
if( !to_stdout && !testing &&
|
||||
( filenames_given || default_output_filename[0] ) )
|
||||
output_filename = resize_buffer( output_filename, 1 );
|
||||
output_filename[0] = 0;
|
||||
if( to_stdout && !testing ) outfd = STDOUT_FILENO;
|
||||
else outfd = -1;
|
||||
|
||||
const bool to_file = !to_stdout && !testing && default_output_filename[0];
|
||||
if( !to_stdout && !testing && ( filenames_given || to_file ) )
|
||||
set_signals( signal_handler );
|
||||
|
||||
Pp_init( &pp, filenames, num_filenames );
|
||||
|
||||
output_filename = resize_buffer( output_filename, 1 );
|
||||
const bool one_to_one = !to_stdout && !testing && !to_file;
|
||||
for( i = 0; i < num_filenames; ++i )
|
||||
{
|
||||
const char * input_filename = "";
|
||||
int tmp;
|
||||
struct stat in_stats;
|
||||
const struct stat * in_statsp;
|
||||
output_filename[0] = 0;
|
||||
|
||||
if( strcmp( filenames[i], "-" ) == 0 )
|
||||
{
|
||||
if( stdin_used ) continue; else stdin_used = true;
|
||||
infd = STDIN_FILENO;
|
||||
if( !testing )
|
||||
{
|
||||
if( to_stdout || !default_output_filename[0] )
|
||||
outfd = STDOUT_FILENO;
|
||||
else
|
||||
{
|
||||
output_filename = resize_buffer( output_filename,
|
||||
strlen( default_output_filename ) + 1 );
|
||||
strcpy( output_filename, default_output_filename );
|
||||
if( !open_outstream( force, true ) )
|
||||
{
|
||||
if( retval < 1 ) retval = 1;
|
||||
close( infd ); infd = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( one_to_one ) { outfd = STDOUT_FILENO; output_filename[0] = 0; }
|
||||
}
|
||||
else
|
||||
{
|
||||
input_filename = filenames[i];
|
||||
infd = open_instream( input_filename, &in_stats, to_stdout || testing );
|
||||
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
|
||||
if( !testing )
|
||||
infd = open_instream( input_filename, &in_stats, one_to_one );
|
||||
if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
|
||||
if( one_to_one )
|
||||
{
|
||||
if( to_stdout ) outfd = STDOUT_FILENO;
|
||||
else
|
||||
{
|
||||
set_d_outname( input_filename, extension_index( input_filename ) );
|
||||
if( !open_outstream( force, false ) )
|
||||
{
|
||||
if( retval < 1 ) retval = 1;
|
||||
close( infd ); infd = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
set_d_outname( input_filename, extension_index( input_filename ) );
|
||||
if( !open_outstream( force, true ) )
|
||||
{ set_retval( &retval, 1 ); close( infd ); infd = -1; continue; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -738,37 +716,43 @@ int main( const int argc, const char * const argv[] )
|
|||
{
|
||||
show_file_error( pp.name,
|
||||
"I won't read compressed data from a terminal.", 0 );
|
||||
if( retval < 1 ) retval = 1;
|
||||
set_retval( &retval, 1 );
|
||||
if( testing ) { close( infd ); infd = -1; continue; }
|
||||
cleanup_and_fail( retval );
|
||||
}
|
||||
|
||||
in_statsp = input_filename[0] ? &in_stats : 0;
|
||||
if( to_file && outfd < 0 ) /* open outfd after verifying infd */
|
||||
{
|
||||
output_filename = resize_buffer( output_filename,
|
||||
strlen( default_output_filename ) + 1 );
|
||||
strcpy( output_filename, default_output_filename );
|
||||
if( !open_outstream( force, false ) ) return 1;
|
||||
}
|
||||
|
||||
in_statsp = ( input_filename[0] && one_to_one ) ? &in_stats : 0;
|
||||
if( in_place )
|
||||
tmp = decompress_in_place( infd, &pp, testing );
|
||||
else
|
||||
tmp = decompress( &pp, cl_insize, cl_outsize, nofill, noflush, testing );
|
||||
if( close( infd ) != 0 )
|
||||
{
|
||||
show_error( input_filename[0] ? "Error closing input file" :
|
||||
"Error closing stdin", errno, false );
|
||||
if( tmp < 1 ) tmp = 1;
|
||||
}
|
||||
{ show_file_error( pp.name, "Error closing input file", errno );
|
||||
set_retval( &tmp, 1 ); }
|
||||
infd = -1;
|
||||
if( tmp > retval ) retval = tmp;
|
||||
set_retval( &retval, tmp );
|
||||
if( tmp )
|
||||
{ if( !testing ) cleanup_and_fail( retval );
|
||||
else ++failed_tests; }
|
||||
|
||||
if( delete_output_on_interrupt )
|
||||
if( delete_output_on_interrupt && one_to_one )
|
||||
close_and_set_permissions( in_statsp );
|
||||
if( input_filename[0] && !keep_input_files && !to_stdout && !testing )
|
||||
if( input_filename[0] && !keep_input_files && one_to_one )
|
||||
remove( input_filename );
|
||||
}
|
||||
if( outfd >= 0 && close( outfd ) != 0 )
|
||||
if( delete_output_on_interrupt ) close_and_set_permissions( 0 ); /* -o */
|
||||
else if( outfd >= 0 && close( outfd ) != 0 ) /* -c */
|
||||
{
|
||||
show_error( "Error closing stdout", errno, false );
|
||||
if( retval < 1 ) retval = 1;
|
||||
set_retval( &retval, 1 );
|
||||
}
|
||||
if( failed_tests > 0 && verbosity >= 1 && num_filenames > 1 )
|
||||
fprintf( stderr, "%s: warning: %d %s failed the test.\n",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue