Adding upstream version 1.5~rc1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
44c75e168c
commit
df42bf1fa4
11 changed files with 245 additions and 43 deletions
140
main.c
140
main.c
|
@ -54,6 +54,10 @@
|
|||
#include "lzip.h"
|
||||
#include "decoder.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
#error "Environments where CHAR_BIT != 8 are not supported."
|
||||
#endif
|
||||
|
@ -64,12 +68,6 @@ const char * const program_name = "lunzip";
|
|||
const char * const program_year = "2013";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
#ifdef O_BINARY
|
||||
const int o_binary = O_BINARY;
|
||||
#else
|
||||
const int o_binary = 0;
|
||||
#endif
|
||||
|
||||
struct { const char * from; const char * to; } const known_extensions[] = {
|
||||
{ ".lz", "" },
|
||||
{ ".tlz", ".tar" },
|
||||
|
@ -86,7 +84,18 @@ bool delete_output_on_interrupt = false;
|
|||
|
||||
static void show_help( void )
|
||||
{
|
||||
printf( "%s - Decompressor for lzip files.\n", Program_name );
|
||||
printf( "Lunzip is a decompressor for lzip files. It is written in C and its\n"
|
||||
"small size makes it well suited for embedded devices or software\n"
|
||||
"installers that need to decompress files but do not need compression\n"
|
||||
"capabilities. Lunzip is fully compatible with lzip-1.4 or newer.\n"
|
||||
"\nIf the size of the output buffer is specified with the '--buffer-size'\n"
|
||||
"option, lunzip uses the decompressed file as dictionary for distances\n"
|
||||
"beyond the buffer size and is able to decompress any file using as\n"
|
||||
"little memory as 50 kB, irrespective of the dictionary size used to\n"
|
||||
"compress the file. Of course, the smaller the output buffer size used in\n"
|
||||
"relation to the dictionary size, the more accesses to disk are needed\n"
|
||||
"and the slower the decompression is. This 'low memory' mode only works\n"
|
||||
"when decompressing to a regular file.\n" );
|
||||
printf( "\nUsage: %s [options] [files]\n", invocation_name );
|
||||
printf( "\nOptions:\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
|
@ -98,6 +107,7 @@ static void show_help( void )
|
|||
" -o, --output=<file> if reading stdin, place the output into <file>\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -t, --test test compressed file integrity\n"
|
||||
" -u, --buffer-size=<bytes> set output buffer size in bytes\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
"If no file names are given, lunzip decompresses from standard input to\n"
|
||||
"standard output.\n"
|
||||
|
@ -137,6 +147,73 @@ static void show_header( const File_header header )
|
|||
}
|
||||
|
||||
|
||||
static unsigned long getnum( const char * const ptr,
|
||||
const unsigned long llimit,
|
||||
const unsigned long ulimit )
|
||||
{
|
||||
unsigned long result;
|
||||
char * tail;
|
||||
errno = 0;
|
||||
result = strtoul( ptr, &tail, 0 );
|
||||
if( tail == ptr )
|
||||
{
|
||||
show_error( "Bad or missing numerical argument.", 0, true );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if( !errno && tail[0] )
|
||||
{
|
||||
int factor = ( tail[1] == 'i' ) ? 1024 : 1000;
|
||||
int exponent = 0, i;
|
||||
bool bad_multiplier = false;
|
||||
switch( tail[0] )
|
||||
{
|
||||
case ' ': break;
|
||||
case 'Y': exponent = 8; break;
|
||||
case 'Z': exponent = 7; break;
|
||||
case 'E': exponent = 6; break;
|
||||
case 'P': exponent = 5; break;
|
||||
case 'T': exponent = 4; break;
|
||||
case 'G': exponent = 3; break;
|
||||
case 'M': exponent = 2; break;
|
||||
case 'K': if( factor == 1024 ) exponent = 1; else bad_multiplier = true;
|
||||
break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
|
||||
break;
|
||||
default : bad_multiplier = true;
|
||||
}
|
||||
if( bad_multiplier )
|
||||
{
|
||||
show_error( "Bad multiplier in numerical argument.", 0, true );
|
||||
exit( 1 );
|
||||
}
|
||||
for( i = 0; i < exponent; ++i )
|
||||
{
|
||||
if( ulimit / factor >= result ) result *= factor;
|
||||
else { errno = ERANGE; break; }
|
||||
}
|
||||
}
|
||||
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
|
||||
if( errno )
|
||||
{
|
||||
show_error( "Numerical argument out of limits.", 0, false );
|
||||
exit( 1 );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int get_dict_size( const char * const arg )
|
||||
{
|
||||
char * tail;
|
||||
int bits = strtol( arg, &tail, 0 );
|
||||
if( bits >= min_dictionary_bits &&
|
||||
bits <= max_dictionary_bits && *tail == 0 )
|
||||
return ( 1 << bits );
|
||||
return getnum( arg, min_dictionary_size, max_dictionary_size );
|
||||
}
|
||||
|
||||
|
||||
static int extension_index( const char * const name )
|
||||
{
|
||||
int i;
|
||||
|
@ -152,9 +229,9 @@ static int extension_index( const char * const name )
|
|||
|
||||
|
||||
static int open_instream( const char * const name, struct stat * const in_statsp,
|
||||
const bool testing, const bool to_stdout )
|
||||
const bool no_ofile )
|
||||
{
|
||||
int infd = open( name, O_RDONLY | o_binary );
|
||||
int infd = open( name, O_RDONLY | O_BINARY );
|
||||
if( infd < 0 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
|
@ -168,7 +245,6 @@ 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 ) ) );
|
||||
const bool no_ofile = to_stdout || testing;
|
||||
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
|
@ -224,7 +300,7 @@ static void set_d_outname( const char * const name, const int i )
|
|||
|
||||
static bool open_outstream( const bool force )
|
||||
{
|
||||
int flags = O_CREAT | O_WRONLY | o_binary;
|
||||
int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
|
||||
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
||||
|
||||
outfd = open( output_filename, flags, outfd_mode );
|
||||
|
@ -263,10 +339,14 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
|
|||
bool warning = false;
|
||||
if( in_statsp )
|
||||
{
|
||||
const mode_t mode = in_statsp->st_mode;
|
||||
/* fchown will in many cases return with EPERM, which can be safely ignored. */
|
||||
if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 &&
|
||||
errno != EPERM ) ||
|
||||
fchmod( outfd, in_statsp->st_mode ) != 0 ) warning = true;
|
||||
if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 )
|
||||
{ if( fchmod( outfd, mode ) != 0 ) warning = true; }
|
||||
else
|
||||
if( errno != EPERM ||
|
||||
fchmod( outfd, mode & ~( S_ISUID | S_ISGID | S_ISVTX ) ) != 0 )
|
||||
warning = true;
|
||||
}
|
||||
if( close( outfd ) != 0 ) cleanup_and_fail( 1 );
|
||||
outfd = -1;
|
||||
|
@ -283,8 +363,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
|
|||
}
|
||||
|
||||
|
||||
static int decompress( const int infd, struct Pretty_print * const pp,
|
||||
const bool testing )
|
||||
static int decompress( const int buffer_size, const int infd,
|
||||
struct Pretty_print * const pp, const bool testing )
|
||||
{
|
||||
unsigned long long partial_file_pos = 0;
|
||||
struct Range_decoder rdec;
|
||||
|
@ -292,7 +372,7 @@ static int decompress( const int infd, struct Pretty_print * const pp,
|
|||
bool first_member;
|
||||
if( !Rd_init( &rdec, infd ) )
|
||||
{
|
||||
show_error( "Not enough memory. Find a machine with more memory.", 0, false );
|
||||
show_error( "Not enough memory.", 0, false );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
|
||||
|
@ -332,9 +412,9 @@ static int decompress( const int infd, struct Pretty_print * const pp,
|
|||
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
|
||||
{ Pp_show_msg( pp, 0 ); if( verbosity >= 3 ) show_header( header ); }
|
||||
|
||||
if( !LZd_init( &decoder, header, &rdec, outfd ) )
|
||||
if( !LZd_init( &decoder, header, &rdec, buffer_size, outfd ) )
|
||||
{
|
||||
show_error( "Not enough memory. Find a machine with more memory.", 0, false );
|
||||
show_error( "Not enough memory. Try a smaller output buffer size.", 0, false );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
result = LZd_decode_member( &decoder, pp );
|
||||
|
@ -431,6 +511,7 @@ int main( const int argc, const char * const argv[] )
|
|||
const char * default_output_filename = "";
|
||||
const char ** filenames = 0;
|
||||
int num_filenames = 0;
|
||||
int buffer_size = max_dictionary_size;
|
||||
int infd = -1;
|
||||
int argind = 0;
|
||||
int retval = 0;
|
||||
|
@ -453,6 +534,7 @@ int main( const int argc, const char * const argv[] )
|
|||
{ 'o', "output", ap_yes },
|
||||
{ 'q', "quiet", ap_no },
|
||||
{ 't', "test", ap_no },
|
||||
{ 'u', "buffer-size", ap_yes },
|
||||
{ 'v', "verbose", ap_no },
|
||||
{ 'V', "version", ap_no },
|
||||
{ 0 , 0, ap_no } };
|
||||
|
@ -463,7 +545,7 @@ int main( const int argc, const char * const argv[] )
|
|||
CRC32_init();
|
||||
|
||||
if( !ap_init( &parser, argc, argv, options, 0 ) )
|
||||
{ show_error( "Memory exhausted.", 0, false ); return 1; }
|
||||
{ show_error( "Not enough memory.", 0, false ); return 1; }
|
||||
if( ap_error( &parser ) ) /* bad option */
|
||||
{ show_error( ap_error( &parser ), 0, true ); return 1; }
|
||||
|
||||
|
@ -483,6 +565,7 @@ int main( const int argc, const char * const argv[] )
|
|||
case 'o': default_output_filename = arg; break;
|
||||
case 'q': verbosity = -1; break;
|
||||
case 't': testing = true; break;
|
||||
case 'u': buffer_size = get_dict_size( arg ); break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
case 'V': show_version(); return 0;
|
||||
default : internal_error( "uncaught option" );
|
||||
|
@ -507,6 +590,19 @@ int main( const int argc, const char * const argv[] )
|
|||
if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true;
|
||||
}
|
||||
|
||||
if( buffer_size < max_dictionary_size )
|
||||
{
|
||||
if( to_stdout || testing )
|
||||
{ show_error( "'--buffer-size' is incompatible with '--stdout' and '--test'.", 0, false );
|
||||
return 1; }
|
||||
if( !default_output_filename[0] )
|
||||
for( i = 0; i < num_filenames; ++i )
|
||||
if( !filenames[i][0] || strcmp( filenames[i], "-" ) == 0 )
|
||||
{ show_error( "Output file must be specified when decompressing from stdin with a\n"
|
||||
" reduced buffer size.", 0, false );
|
||||
return 1; }
|
||||
}
|
||||
|
||||
if( !to_stdout && !testing &&
|
||||
( filenames_given || default_output_filename[0] ) )
|
||||
set_signals();
|
||||
|
@ -547,7 +643,7 @@ int main( const int argc, const char * const argv[] )
|
|||
else
|
||||
{
|
||||
input_filename = filenames[i];
|
||||
infd = open_instream( input_filename, &in_stats, testing, to_stdout );
|
||||
infd = open_instream( input_filename, &in_stats, to_stdout || testing );
|
||||
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
|
||||
if( !testing )
|
||||
{
|
||||
|
@ -576,7 +672,7 @@ int main( const int argc, const char * const argv[] )
|
|||
delete_output_on_interrupt = true;
|
||||
in_statsp = input_filename[0] ? &in_stats : 0;
|
||||
Pp_set_name( &pp, input_filename );
|
||||
tmp = decompress( infd, &pp, testing );
|
||||
tmp = decompress( buffer_size, infd, &pp, testing );
|
||||
if( tmp > retval ) retval = tmp;
|
||||
if( tmp && !testing ) cleanup_and_fail( retval );
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue