1
0
Fork 0

Adding upstream version 1.5~rc1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 22:13:05 +01:00
parent 44c75e168c
commit df42bf1fa4
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
11 changed files with 245 additions and 43 deletions

140
main.c
View file

@ -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 );