1
0
Fork 0

Merging upstream version 0.8.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 22:53:16 +01:00
parent 4279a1e7bc
commit d24e3d2e19
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
16 changed files with 487 additions and 362 deletions

View file

@ -1,3 +1,14 @@
2024-01-18 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.8 released.
* main.c: Reformat file diagnostics as 'PROGRAM: FILE: MESSAGE'.
(getnum): Show option name and valid range if error.
(show_option_error): New function showing argument and option name.
(main): Make -o preserve date/mode/owner if 1 input file.
* lzip.h: Rename verify_* to check_*.
* configure, Makefile.in: New variable 'MAKEINFO'.
* INSTALL: Document use of CFLAGS+='--std=c99 -D_XOPEN_SOURCE=500'.
2021-01-01 Antonio Diaz Diaz <antonio@gnu.org> 2021-01-01 Antonio Diaz Diaz <antonio@gnu.org>
* Version 0.7 released. * Version 0.7 released.
@ -22,7 +33,7 @@
* main.c: Set a valid invocation_name even if argc == 0. * main.c: Set a valid invocation_name even if argc == 0.
* Document extraction from tar.lz in '--help' output and man page. * Document extraction from tar.lz in '--help' output and man page.
* main.c: Compile on DOS with DJGPP. * main.c: Compile on DOS with DJGPP.
* configure: Accept appending to CFLAGS, 'CFLAGS+=OPTIONS'. * configure: Accept appending to CFLAGS; 'CFLAGS+=OPTIONS'.
* testsuite: Add 9 new test files. * testsuite: Add 9 new test files.
2018-09-18 Antonio Diaz Diaz <antonio@gnu.org> 2018-09-18 Antonio Diaz Diaz <antonio@gnu.org>
@ -56,7 +67,7 @@
* Tests the code shipped in linux patches before june 2018. * Tests the code shipped in linux patches before june 2018.
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This file is a collection of facts, and thus it is not copyrightable, This file is a collection of facts, and thus it is not copyrightable,
but just in case, you have unlimited permission to copy, distribute, and but just in case, you have unlimited permission to copy, distribute, and

19
INSTALL
View file

@ -1,7 +1,7 @@
Requirements Requirements
------------ ------------
You will need a C99 compiler. (gcc 3.3.6 or newer is recommended). You will need a C99 compiler. (gcc 3.3.6 or newer is recommended).
I use gcc 6.1.0 and 4.1.2, but the code should compile with any standards I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards
compliant compiler. compliant compiler.
Gcc is available at http://gcc.gnu.org. Gcc is available at http://gcc.gnu.org.
@ -18,8 +18,8 @@ Procedure
or or
lzip -cd xlunzip[version].tar.lz | tar -xf - lzip -cd xlunzip[version].tar.lz | tar -xf -
This creates the directory ./xlunzip[version] containing the source from This creates the directory ./xlunzip[version] containing the source code
the main archive. extracted from the archive.
2. Change to xlunzip directory and run configure. 2. Change to xlunzip directory and run configure.
(Try 'configure --help' for usage instructions). (Try 'configure --help' for usage instructions).
@ -27,6 +27,10 @@ the main archive.
cd xlunzip[version] cd xlunzip[version]
./configure ./configure
If you choose a C standard, enable the POSIX features explicitly:
./configure CFLAGS+='--std=c99 -D_XOPEN_SOURCE=500'
If you are compiling on MinGW, use: If you are compiling on MinGW, use:
./configure CFLAGS+='-D __USE_MINGW_ANSI_STDIO' ./configure CFLAGS+='-D __USE_MINGW_ANSI_STDIO'
@ -38,7 +42,8 @@ the main archive.
4. Optionally, type 'make check' to run the tests that come with xlunzip. 4. Optionally, type 'make check' to run the tests that come with xlunzip.
5. Type 'make install' to install the program and any data files and 5. Type 'make install' to install the program and any data files and
documentation. documentation. You need root privileges to install into a prefix owned
by root.
Or type 'make install-compress', which additionally compresses the Or type 'make install-compress', which additionally compresses the
man page after installation. man page after installation.
@ -61,15 +66,15 @@ object files and executables to go and run the 'configure' script.
'configure' automatically checks for the source code in '.', in '..', and 'configure' automatically checks for the source code in '.', in '..', and
in the directory that 'configure' is in. in the directory that 'configure' is in.
'configure' recognizes the option '--srcdir=DIR' to control where to 'configure' recognizes the option '--srcdir=DIR' to control where to look
look for the sources. Usually 'configure' can determine that directory for the source code. Usually 'configure' can determine that directory
automatically. automatically.
After running 'configure', you can run 'make' and 'make install' as After running 'configure', you can run 'make' and 'make install' as
explained above. explained above.
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.

View file

@ -20,7 +20,7 @@ objs = carg_parser.o decompress_lunzip.o in_place.o lzip_decompress.o main.o
all : $(progname) all : $(progname)
$(progname) : $(objs) $(progname) : $(objs)
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(objs) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(objs)
main.o : main.c main.o : main.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $< $(CC) $(CPPFLAGS) $(CFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
@ -28,6 +28,10 @@ main.o : main.c
%.o : %.c %.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
# prevent 'make' from trying to remake source files
$(VPATH)/configure $(VPATH)/Makefile.in $(VPATH)/doc/$(pkgname).texi : ;
%.h %.c : ;
$(objs) : Makefile $(objs) : Makefile
carg_parser.o : carg_parser.h carg_parser.o : carg_parser.h
decompress_lunzip.o : linux_lzip.h linux_lunzip.h linux_mm.h lzip_decompress.c decompress_lunzip.o : linux_lzip.h linux_lunzip.h linux_mm.h lzip_decompress.c
@ -35,13 +39,12 @@ in_place.o : linux_lunzip.h lzip.h
lzip_decompress.o : linux_module.h linux_lzip.h linux_mm.h lzip_decompress.o : linux_module.h linux_lzip.h linux_mm.h
main.o : carg_parser.h linux_lzip.h linux_lunzip.h lzip.h main.o : carg_parser.h linux_lzip.h linux_lunzip.h lzip.h
doc : man doc : man
info : $(VPATH)/doc/$(pkgname).info info : $(VPATH)/doc/$(pkgname).info
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi
cd $(VPATH)/doc && makeinfo $(pkgname).texi cd $(VPATH)/doc && $(MAKEINFO) $(pkgname).texi
man : $(VPATH)/doc/$(progname).1 man : $(VPATH)/doc/$(progname).1

19
NEWS
View file

@ -1,3 +1,18 @@
Changes in version 0.7: Changes in version 0.8:
Xlunzip now does not even open the output file if the input file is a terminal. File diagnostics have been reformatted as 'PROGRAM: FILE: MESSAGE'.
In case of error in a numerical argument to a command line option, lunzip
now shows the name of the option and the range of valid values.
Diagnostics caused by invalid arguments to command-line options now show the
argument and the name of the option.
The option '-o, --output' now preserves dates, permissions, and ownership of
the file, when decompressing exactly one file.
The variable MAKEINFO has been added to configure and Makefile.in.
It has been documented in INSTALL that when choosing a C standard, the POSIX
features need to be enabled explicitly:
./configure CFLAGS+='--std=c99 -D_XOPEN_SOURCE=500'

21
README
View file

@ -4,7 +4,7 @@ Xlunzip is a test tool for the lzip decompression code of my lzip patch for
linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux
module as a backend. Xlunzip tests the module for stream, buffer-to-buffer, module as a backend. Xlunzip tests the module for stream, buffer-to-buffer,
and mixed decompression modes, including in-place decompression (using the and mixed decompression modes, including in-place decompression (using the
same buffer for input and output). You can use xlunzip to verify that the same buffer for input and output). You can use xlunzip to check that the
module produces correct results when decompressing single member files, module produces correct results when decompressing single member files,
multimember files, or the concatenation of two or more compressed files. multimember files, or the concatenation of two or more compressed files.
Xlunzip can be used with unzcrash to test the robustness of the module to Xlunzip can be used with unzcrash to test the robustness of the module to
@ -26,7 +26,7 @@ Lzip related components in the kernel
===================================== =====================================
The lzip_decompress module in lib/lzip_decompress.c provides a versatile The lzip_decompress module in lib/lzip_decompress.c provides a versatile
lzip decompression function able to do buffer to buffer decompression or lzip decompression function able to do buffer-to-buffer decompression or
stream decompression with fill and flush callback functions. The usage of stream decompression with fill and flush callback functions. The usage of
the function is documented in include/linux/lzip.h. the function is documented in include/linux/lzip.h.
@ -76,7 +76,7 @@ address | * ,'
All we need to know to calculate the minimum required extra space is: All we need to know to calculate the minimum required extra space is:
The maximum expansion ratio. The maximum expansion ratio.
The size of the last part of a member required to verify integrity. The size of the last part of a member required to check integrity.
For multimember data, the overhead per member. (36 bytes for lzip). For multimember data, the overhead per member. (36 bytes for lzip).
The maximum expansion ratio of LZMA data is of about 1.4%. Rounding this up The maximum expansion ratio of LZMA data is of about 1.4%. Rounding this up
@ -87,22 +87,21 @@ required to decompress lzip data in place is:
Using the compressed size to calculate the extra_bytes (as in the formula Using the compressed size to calculate the extra_bytes (as in the formula
above) may slightly overestimate the amount of space required in the worst above) may slightly overestimate the amount of space required in the worst
case. But calculating the extra_bytes from the uncompressed size (as does case (maximum expansion). But calculating the extra_bytes from the
linux currently) is wrong (and inefficient for high compression ratios). The uncompressed size (as does linux currently) is wrong (and inefficient for
formula used in arch/x86/boot/header.S high compression ratios). The formula used in arch/x86/boot/header.S:
extra_bytes = ( uncompressed_size >> 8 ) + 65536 extra_bytes = ( uncompressed_size >> 8 ) + 131072
fails to decompress 1 MB of zeros followed by 8 MB of random data, wastes fails to decompress 1 MB of zeros followed by 8 MB of random data, wastes
memory for compression ratios larger than 4:1, and does not even consider memory for compression ratios larger than 4:1, and does not even consider
multimember data. multimember data.
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.
The file Makefile.in is a data file used by configure to produce the The file Makefile.in is a data file used by configure to produce the Makefile.
Makefile. It has the same copyright owner and permissions that configure It has the same copyright owner and permissions that configure itself.
itself.

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C version) /* Arg_parser - POSIX/GNU command-line argument parser. (C version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2024 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -32,10 +32,10 @@ static void * ap_resize_buffer( void * buf, const int min_size )
} }
static char push_back_record( struct Arg_parser * const ap, static char push_back_record( struct Arg_parser * const ap, const int code,
const int code, const char * const argument ) const char * const long_name,
const char * const argument )
{ {
const int len = strlen( argument );
struct ap_Record * p; struct ap_Record * p;
void * tmp = ap_resize_buffer( ap->data, void * tmp = ap_resize_buffer( ap->data,
( ap->data_size + 1 ) * sizeof (struct ap_Record) ); ( ap->data_size + 1 ) * sizeof (struct ap_Record) );
@ -43,11 +43,29 @@ static char push_back_record( struct Arg_parser * const ap,
ap->data = (struct ap_Record *)tmp; ap->data = (struct ap_Record *)tmp;
p = &(ap->data[ap->data_size]); p = &(ap->data[ap->data_size]);
p->code = code; p->code = code;
p->argument = 0; if( long_name )
tmp = ap_resize_buffer( p->argument, len + 1 ); {
if( !tmp ) return 0; const int len = strlen( long_name );
p->argument = (char *)tmp; p->parsed_name = (char *)malloc( len + 2 + 1 );
strncpy( p->argument, argument, len + 1 ); if( !p->parsed_name ) return 0;
p->parsed_name[0] = p->parsed_name[1] = '-';
strncpy( p->parsed_name + 2, long_name, len + 1 );
}
else if( code > 0 && code < 256 )
{
p->parsed_name = (char *)malloc( 2 + 1 );
if( !p->parsed_name ) return 0;
p->parsed_name[0] = '-'; p->parsed_name[1] = code; p->parsed_name[2] = 0;
}
else p->parsed_name = 0;
if( argument )
{
const int len = strlen( argument );
p->argument = (char *)malloc( len + 1 );
if( !p->argument ) { free( p->parsed_name ); return 0; }
strncpy( p->argument, argument, len + 1 );
}
else p->argument = 0;
++ap->data_size; ++ap->data_size;
return 1; return 1;
} }
@ -68,12 +86,14 @@ static char add_error( struct Arg_parser * const ap, const char * const msg )
static void free_data( struct Arg_parser * const ap ) static void free_data( struct Arg_parser * const ap )
{ {
int i; int i;
for( i = 0; i < ap->data_size; ++i ) free( ap->data[i].argument ); for( i = 0; i < ap->data_size; ++i )
{ free( ap->data[i].argument ); free( ap->data[i].parsed_name ); }
if( ap->data ) { free( ap->data ); ap->data = 0; } if( ap->data ) { free( ap->data ); ap->data = 0; }
ap->data_size = 0; ap->data_size = 0;
} }
/* Return 0 only if out of memory. */
static char parse_long_option( struct Arg_parser * const ap, static char parse_long_option( struct Arg_parser * const ap,
const char * const opt, const char * const arg, const char * const opt, const char * const arg,
const struct ap_Option options[], const struct ap_Option options[],
@ -87,9 +107,10 @@ static char parse_long_option( struct Arg_parser * const ap,
/* Test all long options for either exact match or abbreviated matches. */ /* Test all long options for either exact match or abbreviated matches. */
for( i = 0; options[i].code != 0; ++i ) for( i = 0; options[i].code != 0; ++i )
if( options[i].name && strncmp( options[i].name, &opt[2], len ) == 0 ) if( options[i].long_name &&
strncmp( options[i].long_name, &opt[2], len ) == 0 )
{ {
if( strlen( options[i].name ) == len ) /* Exact match found */ if( strlen( options[i].long_name ) == len ) /* Exact match found */
{ index = i; exact = 1; break; } { index = i; exact = 1; break; }
else if( index < 0 ) index = i; /* First nonexact match found */ else if( index < 0 ) index = i; /* First nonexact match found */
else if( options[index].code != options[i].code || else if( options[index].code != options[i].code ||
@ -117,35 +138,39 @@ static char parse_long_option( struct Arg_parser * const ap,
{ {
if( options[index].has_arg == ap_no ) if( options[index].has_arg == ap_no )
{ {
add_error( ap, "option '--" ); add_error( ap, options[index].name ); add_error( ap, "option '--" ); add_error( ap, options[index].long_name );
add_error( ap, "' doesn't allow an argument" ); add_error( ap, "' doesn't allow an argument" );
return 1; return 1;
} }
if( options[index].has_arg == ap_yes && !opt[len+3] ) if( options[index].has_arg == ap_yes && !opt[len+3] )
{ {
add_error( ap, "option '--" ); add_error( ap, options[index].name ); add_error( ap, "option '--" ); add_error( ap, options[index].long_name );
add_error( ap, "' requires an argument" ); add_error( ap, "' requires an argument" );
return 1; return 1;
} }
return push_back_record( ap, options[index].code, &opt[len+3] ); return push_back_record( ap, options[index].code,
options[index].long_name, &opt[len+3] );
} }
if( options[index].has_arg == ap_yes ) if( options[index].has_arg == ap_yes )
{ {
if( !arg || !arg[0] ) if( !arg || !arg[0] )
{ {
add_error( ap, "option '--" ); add_error( ap, options[index].name ); add_error( ap, "option '--" ); add_error( ap, options[index].long_name );
add_error( ap, "' requires an argument" ); add_error( ap, "' requires an argument" );
return 1; return 1;
} }
++*argindp; ++*argindp;
return push_back_record( ap, options[index].code, arg ); return push_back_record( ap, options[index].code,
options[index].long_name, arg );
} }
return push_back_record( ap, options[index].code, "" ); return push_back_record( ap, options[index].code,
options[index].long_name, 0 );
} }
/* Return 0 only if out of memory. */
static char parse_short_option( struct Arg_parser * const ap, static char parse_short_option( struct Arg_parser * const ap,
const char * const opt, const char * const arg, const char * const opt, const char * const arg,
const struct ap_Option options[], const struct ap_Option options[],
@ -156,13 +181,13 @@ static char parse_short_option( struct Arg_parser * const ap,
while( cind > 0 ) while( cind > 0 )
{ {
int index = -1, i; int index = -1, i;
const unsigned char code = opt[cind]; const unsigned char c = opt[cind];
char code_str[2]; char code_str[2];
code_str[0] = code; code_str[1] = 0; code_str[0] = c; code_str[1] = 0;
if( code != 0 ) if( c != 0 )
for( i = 0; options[i].code; ++i ) for( i = 0; options[i].code; ++i )
if( code == options[i].code ) if( c == options[i].code )
{ index = i; break; } { index = i; break; }
if( index < 0 ) if( index < 0 )
@ -176,7 +201,7 @@ static char parse_short_option( struct Arg_parser * const ap,
if( options[index].has_arg != ap_no && cind > 0 && opt[cind] ) if( options[index].has_arg != ap_no && cind > 0 && opt[cind] )
{ {
if( !push_back_record( ap, code, &opt[cind] ) ) return 0; if( !push_back_record( ap, c, 0, &opt[cind] ) ) return 0;
++*argindp; cind = 0; ++*argindp; cind = 0;
} }
else if( options[index].has_arg == ap_yes ) else if( options[index].has_arg == ap_yes )
@ -188,9 +213,9 @@ static char parse_short_option( struct Arg_parser * const ap,
return 1; return 1;
} }
++*argindp; cind = 0; ++*argindp; cind = 0;
if( !push_back_record( ap, code, arg ) ) return 0; if( !push_back_record( ap, c, 0, arg ) ) return 0;
} }
else if( !push_back_record( ap, code, "" ) ) return 0; else if( !push_back_record( ap, c, 0, 0 ) ) return 0;
} }
return 1; return 1;
} }
@ -203,7 +228,7 @@ char ap_init( struct Arg_parser * const ap,
const char ** non_options = 0; /* skipped non-options */ const char ** non_options = 0; /* skipped non-options */
int non_options_size = 0; /* number of skipped non-options */ int non_options_size = 0; /* number of skipped non-options */
int argind = 1; /* index in argv */ int argind = 1; /* index in argv */
int i; char done = 0; /* false until success */
ap->data = 0; ap->data = 0;
ap->error = 0; ap->error = 0;
@ -223,20 +248,20 @@ char ap_init( struct Arg_parser * const ap,
if( ch2 == '-' ) if( ch2 == '-' )
{ {
if( !argv[argind][2] ) { ++argind; break; } /* we found "--" */ if( !argv[argind][2] ) { ++argind; break; } /* we found "--" */
else if( !parse_long_option( ap, opt, arg, options, &argind ) ) return 0; else if( !parse_long_option( ap, opt, arg, options, &argind ) ) goto out;
} }
else if( !parse_short_option( ap, opt, arg, options, &argind ) ) return 0; else if( !parse_short_option( ap, opt, arg, options, &argind ) ) goto out;
if( ap->error ) break; if( ap->error ) break;
} }
else else
{ {
if( in_order ) if( in_order )
{ if( !push_back_record( ap, 0, argv[argind++] ) ) return 0; } { if( !push_back_record( ap, 0, 0, argv[argind++] ) ) goto out; }
else else
{ {
void * tmp = ap_resize_buffer( non_options, void * tmp = ap_resize_buffer( non_options,
( non_options_size + 1 ) * sizeof *non_options ); ( non_options_size + 1 ) * sizeof *non_options );
if( !tmp ) return 0; if( !tmp ) goto out;
non_options = (const char **)tmp; non_options = (const char **)tmp;
non_options[non_options_size++] = argv[argind++]; non_options[non_options_size++] = argv[argind++];
} }
@ -245,13 +270,15 @@ char ap_init( struct Arg_parser * const ap,
if( ap->error ) free_data( ap ); if( ap->error ) free_data( ap );
else else
{ {
int i;
for( i = 0; i < non_options_size; ++i ) for( i = 0; i < non_options_size; ++i )
if( !push_back_record( ap, 0, non_options[i] ) ) return 0; if( !push_back_record( ap, 0, 0, non_options[i] ) ) goto out;
while( argind < argc ) while( argind < argc )
if( !push_back_record( ap, 0, argv[argind++] ) ) return 0; if( !push_back_record( ap, 0, 0, argv[argind++] ) ) goto out;
} }
if( non_options ) free( non_options ); done = 1;
return 1; out: if( non_options ) free( non_options );
return done;
} }
@ -273,13 +300,20 @@ int ap_arguments( const struct Arg_parser * const ap )
int ap_code( const struct Arg_parser * const ap, const int i ) int ap_code( const struct Arg_parser * const ap, const int i )
{ {
if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].code; if( i < 0 || i >= ap_arguments( ap ) ) return 0;
else return 0; return ap->data[i].code;
}
const char * ap_parsed_name( const struct Arg_parser * const ap, const int i )
{
if( i < 0 || i >= ap_arguments( ap ) || !ap->data[i].parsed_name ) return "";
return ap->data[i].parsed_name;
} }
const char * ap_argument( const struct Arg_parser * const ap, const int i ) const char * ap_argument( const struct Arg_parser * const ap, const int i )
{ {
if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].argument; if( i < 0 || i >= ap_arguments( ap ) || !ap->data[i].argument ) return "";
else return ""; return ap->data[i].argument;
} }

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C version) /* Arg_parser - POSIX/GNU command-line argument parser. (C version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2024 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -24,9 +24,9 @@
message. message.
'options' is an array of 'struct ap_Option' terminated by an element 'options' is an array of 'struct ap_Option' terminated by an element
containing a code which is zero. A null name means a short-only containing a code which is zero. A null long_name means a short-only
option. A code value outside the unsigned char range means a option. A code value outside the unsigned char range means a long-only
long-only option. option.
Arg_parser normally makes it appear as if all the option arguments Arg_parser normally makes it appear as if all the option arguments
were specified before all the non-option arguments for the purposes were specified before all the non-option arguments for the purposes
@ -50,7 +50,7 @@ enum ap_Has_arg { ap_no, ap_yes, ap_maybe };
struct ap_Option struct ap_Option
{ {
int code; /* Short option letter or code ( code != 0 ) */ int code; /* Short option letter or code ( code != 0 ) */
const char * name; /* Long option name (maybe null) */ const char * long_name; /* Long option name (maybe null) */
enum ap_Has_arg has_arg; enum ap_Has_arg has_arg;
}; };
@ -58,6 +58,7 @@ struct ap_Option
struct ap_Record struct ap_Record
{ {
int code; int code;
char * parsed_name;
char * argument; char * argument;
}; };
@ -86,6 +87,9 @@ int ap_arguments( const struct Arg_parser * const ap );
Else ap_argument( i ) is the option's argument (or empty). */ Else ap_argument( i ) is the option's argument (or empty). */
int ap_code( const struct Arg_parser * const ap, const int i ); int ap_code( const struct Arg_parser * const ap, const int i );
/* Full name of the option parsed (short or long). */
const char * ap_parsed_name( const struct Arg_parser * const ap, const int i );
const char * ap_argument( const struct Arg_parser * const ap, const int i ); const char * ap_argument( const struct Arg_parser * const ap, const int i );
#ifdef __cplusplus #ifdef __cplusplus

25
configure vendored
View file

@ -1,12 +1,12 @@
#! /bin/sh #! /bin/sh
# configure script for Xlunzip - Test tool for the lzip_decompress linux module # configure script for Xlunzip - Test tool for the lzip_decompress linux module
# Copyright (C) 2016-2021 Antonio Diaz Diaz. # Copyright (C) 2016-2024 Antonio Diaz Diaz.
# #
# This configure script is free software: you have unlimited permission # This configure script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
pkgname=xlunzip pkgname=xlunzip
pkgversion=0.7 pkgversion=0.8
progname=xlunzip progname=xlunzip
srctrigger=doc/${progname}.1 srctrigger=doc/${progname}.1
@ -24,6 +24,7 @@ CC=gcc
CPPFLAGS= CPPFLAGS=
CFLAGS='-Wall -W -O2' CFLAGS='-Wall -W -O2'
LDFLAGS= LDFLAGS=
MAKEINFO=makeinfo
# checking whether we are using GNU C. # checking whether we are using GNU C.
/bin/sh -c "${CC} --version" > /dev/null 2>&1 || { CC=cc ; CFLAGS=-O2 ; } /bin/sh -c "${CC} --version" > /dev/null 2>&1 || { CC=cc ; CFLAGS=-O2 ; }
@ -57,7 +58,7 @@ while [ $# != 0 ] ; do
echo "Options and variables: [defaults in brackets]" echo "Options and variables: [defaults in brackets]"
echo " -h, --help display this help and exit" echo " -h, --help display this help and exit"
echo " -V, --version output version information and exit" echo " -V, --version output version information and exit"
echo " --srcdir=DIR find the sources in DIR [. or ..]" echo " --srcdir=DIR find the source code in DIR [. or ..]"
echo " --prefix=DIR install into DIR [${prefix}]" echo " --prefix=DIR install into DIR [${prefix}]"
echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]" echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]"
echo " --bindir=DIR user executables directory [${bindir}]" echo " --bindir=DIR user executables directory [${bindir}]"
@ -65,10 +66,11 @@ while [ $# != 0 ] ; do
echo " --infodir=DIR info files directory [${infodir}]" echo " --infodir=DIR info files directory [${infodir}]"
echo " --mandir=DIR man pages directory [${mandir}]" echo " --mandir=DIR man pages directory [${mandir}]"
echo " CC=COMPILER C compiler to use [${CC}]" echo " CC=COMPILER C compiler to use [${CC}]"
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]" echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]"
echo " CFLAGS=OPTIONS command line options for the C compiler [${CFLAGS}]" echo " CFLAGS=OPTIONS command-line options for the C compiler [${CFLAGS}]"
echo " CFLAGS+=OPTIONS append options to the current value of CFLAGS" echo " CFLAGS+=OPTIONS append options to the current value of CFLAGS"
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]" echo " LDFLAGS=OPTIONS command-line options for the linker [${LDFLAGS}]"
echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]"
echo echo
exit 0 ;; exit 0 ;;
--version | -V) --version | -V)
@ -96,6 +98,7 @@ while [ $# != 0 ] ; do
CFLAGS=*) CFLAGS=${optarg} ;; CFLAGS=*) CFLAGS=${optarg} ;;
CFLAGS+=*) CFLAGS="${CFLAGS} ${optarg}" ;; CFLAGS+=*) CFLAGS="${CFLAGS} ${optarg}" ;;
LDFLAGS=*) LDFLAGS=${optarg} ;; LDFLAGS=*) LDFLAGS=${optarg} ;;
MAKEINFO=*) MAKEINFO=${optarg} ;;
--*) --*)
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;; echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
@ -115,7 +118,7 @@ while [ $# != 0 ] ; do
fi fi
done done
# Find the source files, if location was not specified. # Find the source code, if location was not specified.
srcdirtext= srcdirtext=
if [ -z "${srcdir}" ] ; then if [ -z "${srcdir}" ] ; then
srcdirtext="or . or .." ; srcdir=. srcdirtext="or . or .." ; srcdir=.
@ -127,7 +130,7 @@ if [ -z "${srcdir}" ] ; then
fi fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then if [ ! -r "${srcdir}/${srctrigger}" ] ; then
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2 echo "configure: Can't find source code in ${srcdir} ${srcdirtext}" 1>&2
echo "configure: (At least ${srctrigger} is missing)." 1>&2 echo "configure: (At least ${srctrigger} is missing)." 1>&2
exit 1 exit 1
fi fi
@ -147,7 +150,7 @@ if [ -z "${no_create}" ] ; then
# This script is free software: you have unlimited permission # This script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
exec /bin/sh $0 ${args} --no-create exec /bin/sh "$0" ${args} --no-create
EOF EOF
chmod +x config.status chmod +x config.status
fi fi
@ -164,10 +167,11 @@ echo "CC = ${CC}"
echo "CPPFLAGS = ${CPPFLAGS}" echo "CPPFLAGS = ${CPPFLAGS}"
echo "CFLAGS = ${CFLAGS}" echo "CFLAGS = ${CFLAGS}"
echo "LDFLAGS = ${LDFLAGS}" echo "LDFLAGS = ${LDFLAGS}"
echo "MAKEINFO = ${MAKEINFO}"
rm -f Makefile rm -f Makefile
cat > Makefile << EOF cat > Makefile << EOF
# Makefile for Xlunzip - Test tool for the lzip_decompress linux module # Makefile for Xlunzip - Test tool for the lzip_decompress linux module
# Copyright (C) 2016-2021 Antonio Diaz Diaz. # Copyright (C) 2016-2024 Antonio Diaz Diaz.
# This file was generated automatically by configure. Don't edit. # This file was generated automatically by configure. Don't edit.
# #
# This Makefile is free software: you have unlimited permission # This Makefile is free software: you have unlimited permission
@ -187,6 +191,7 @@ CC = ${CC}
CPPFLAGS = ${CPPFLAGS} CPPFLAGS = ${CPPFLAGS}
CFLAGS = ${CFLAGS} CFLAGS = ${CFLAGS}
LDFLAGS = ${LDFLAGS} LDFLAGS = ${LDFLAGS}
MAKEINFO = ${MAKEINFO}
EOF EOF
cat "${srcdir}/Makefile.in" >> Makefile cat "${srcdir}/Makefile.in" >> Makefile

View file

@ -1,7 +1,7 @@
/* /*
* Wrapper for decompressing LZIP-compressed kernel, initramfs, and initrd * Wrapper for decompressing LZIP-compressed kernel, initramfs, and initrd
* *
* Copyright (C) 2016-2021 Antonio Diaz Diaz. * Copyright (C) 2016-2024 Antonio Diaz Diaz.
* *
* Licensed under GPLv2 or later, see file LICENSE in this source tree. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/ */
@ -62,8 +62,7 @@ STATIC int INIT __lunzip(unsigned char *inbuf, long in_len,
case LZIP_BAD_CRC: case LZIP_BAD_CRC:
error("CRC mismatch in LZIP-compressed data."); error("CRC mismatch in LZIP-compressed data.");
break; break;
default: default: error("Bug in the LZIP decompressor.");
error("Bug in the LZIP decompressor.");
} }
return retval; return retval;
} }

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH XLUNZIP "1" "January 2021" "xlunzip 0.7" "User Commands" .TH XLUNZIP "1" "January 2024" "xlunzip 0.8" "User Commands"
.SH NAME .SH NAME
xlunzip \- test tool for the lzip_decompress linux module xlunzip \- test tool for the lzip_decompress linux module
.SH SYNOPSIS .SH SYNOPSIS
@ -10,7 +10,7 @@ Xlunzip is a test tool for the lzip decompression code of my lzip patch for
linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux
module as a backend. Xlunzip tests the module for stream, buffer\-to\-buffer, module as a backend. Xlunzip tests the module for stream, buffer\-to\-buffer,
and mixed decompression modes, including in\-place decompression (using the and mixed decompression modes, including in\-place decompression (using the
same buffer for input and output). You can use xlunzip to verify that the same buffer for input and output). You can use xlunzip to check that the
module produces correct results when decompressing single member files, module produces correct results when decompressing single member files,
multimember files, or the concatenation of two or more compressed files. multimember files, or the concatenation of two or more compressed files.
Xlunzip can be used with unzcrash to test the robustness of the module to Xlunzip can be used with unzcrash to test the robustness of the module to
@ -77,16 +77,16 @@ Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
To extract all the files from archive 'foo.tar.lz', use the commands To extract all the files from archive 'foo.tar.lz', use the commands
\&'tar \fB\-xf\fR foo.tar.lz' or 'xlunzip \fB\-cd\fR foo.tar.lz | tar \fB\-xf\fR \-'. \&'tar \fB\-xf\fR foo.tar.lz' or 'xlunzip \fB\-cd\fR foo.tar.lz | tar \fB\-xf\fR \-'.
.PP .PP
Exit status: 0 for a normal exit, 1 for environmental problems (file Exit status: 0 for a normal exit, 1 for environmental problems
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or (file not found, invalid command\-line options, I/O errors, etc), 2 to
invalid input file, 3 for an internal consistency error (eg, bug) which indicate a corrupt or invalid input file, 3 for an internal consistency
caused xlunzip to panic. error (e.g., bug) which caused xlunzip to panic.
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
Report bugs to lzip\-bug@nongnu.org Report bugs to lzip\-bug@nongnu.org
.br .br
Xlunzip home page: http://www.nongnu.org/lzip/xlunzip.html Xlunzip home page: http://www.nongnu.org/lzip/xlunzip.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2024 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.

View file

@ -1,5 +1,5 @@
/* Xlunzip - Test tool for the lzip_decompress linux module /* Xlunzip - Test tool for the lzip_decompress linux module
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -30,8 +30,8 @@
#include "lzip.h" #include "lzip.h"
/* Returns the number of bytes really read. /* Return the number of bytes really read.
If (returned value < size) and (errno == 0), means EOF was reached. If (value returned < size) and (errno == 0), means EOF was reached.
*/ */
static long readblock( const int fd, uint8_t * const buf, const long size ) static long readblock( const int fd, uint8_t * const buf, const long size )
{ {
@ -49,9 +49,9 @@ static long readblock( const int fd, uint8_t * const buf, const long size )
} }
/* Returns the address of a malloc'd buffer containing the file data and /* Return the address of a malloc'd buffer containing the file data and
the buffer and file sizes in '*buffer_sizep' and '*file_sizep'. the buffer and file sizes in '*buffer_sizep' and '*file_sizep'.
In case of error, returns 0 and does not modify '*size'. In case of error, return 0 and do not modify '*sizep'.
*/ */
static uint8_t * read_file( const int infd, long * const buffer_sizep, static uint8_t * read_file( const int infd, long * const buffer_sizep,
long * const file_sizep, const char * const filename ) long * const file_sizep, const char * const filename )
@ -64,8 +64,8 @@ static uint8_t * read_file( const int infd, long * const buffer_sizep,
while( file_size >= buffer_size && !errno ) while( file_size >= buffer_size && !errno )
{ {
if( buffer_size >= LONG_MAX ) if( buffer_size >= LONG_MAX )
{ show_file_error( filename, "File is too large.", 0 ); free( buffer ); { show_file_error( filename, "Input file is too large.", 0 );
return 0; } free( buffer ); return 0; }
buffer_size = ( buffer_size <= LONG_MAX / 2 ) ? 2 * buffer_size : LONG_MAX; buffer_size = ( buffer_size <= LONG_MAX / 2 ) ? 2 * buffer_size : LONG_MAX;
uint8_t * const tmp = (uint8_t *)realloc( buffer, buffer_size ); uint8_t * const tmp = (uint8_t *)realloc( buffer, buffer_size );
if( !tmp ) if( !tmp )
@ -97,9 +97,9 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes,
if( file_size <= Lh_size ) return "File ends unexpectedly at member header."; if( file_size <= Lh_size ) return "File ends unexpectedly at member header.";
if( file_size < min_member_size ) return "Input file is too short."; if( file_size < min_member_size ) return "Input file is too short.";
const Lzip_header * header = (const Lzip_header *)buffer; const Lzip_header * header = (const Lzip_header *)buffer;
if( !Lh_verify_magic( *header ) ) if( !Lh_check_magic( *header ) )
return "Bad magic number (file not in lzip format)."; return "Bad magic number (file not in lzip format).";
if( !Lh_verify_version( *header ) ) if( !Lh_check_version( *header ) )
return "Version of lzip member format not supported."; return "Version of lzip member format not supported.";
file_sizes->csize = file_sizes->dsize = file_sizes->tsize = 0; file_sizes->csize = file_sizes->dsize = file_sizes->tsize = 0;
@ -122,7 +122,7 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes,
return "Member size in trailer is corrupt."; return "Member size in trailer is corrupt.";
} }
header = (const Lzip_header *)( buffer + pos - member_size ); header = (const Lzip_header *)( buffer + pos - member_size );
if( !Lh_verify_magic( *header ) || !Lh_verify_version( *header ) ) if( !Lh_check_magic( *header ) || !Lh_check_version( *header ) )
{ {
if( file_sizes->csize == 0 ) { --pos; continue; } /* maybe trailing data */ if( file_sizes->csize == 0 ) { --pos; continue; } /* maybe trailing data */
return "Bad member header inside file."; return "Bad member header inside file.";
@ -132,7 +132,7 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes,
file_sizes->tsize = file_size - pos; file_sizes->tsize = file_size - pos;
header = (const Lzip_header *)( buffer + pos ); header = (const Lzip_header *)( buffer + pos );
if( file_size - pos > Lh_size && if( file_size - pos > Lh_size &&
Lh_verify_magic( *header ) && Lh_verify_version( *header ) ) Lh_check_magic( *header ) && Lh_check_version( *header ) )
return "Last member in input file is truncated or corrupt."; return "Last member in input file is truncated or corrupt.";
} }
pos -= member_size; pos -= member_size;
@ -155,7 +155,7 @@ static void error(char *x) { show_file_error( global_name, x, 0 ); }
/* /*
* Load the compressed file at the end of the buffer used to hold the * Load the compressed file at the end of the buffer used to hold the
* decompressed data. Verify that the in-place decompression does not * decompressed data. Check that the in-place decompression does not
* overwrite the compressed data. The buffer must be large enough to contain * overwrite the compressed data. The buffer must be large enough to contain
* after the decompressed data extra space for a marker, a trailer, the * after the decompressed data extra space for a marker, a trailer, the
* maximum possible data expansion, and (if multimember) N-1 empty members. * maximum possible data expansion, and (if multimember) N-1 empty members.
@ -180,7 +180,7 @@ int decompress_in_place( const int infd, struct Pretty_print * const pp,
const long csize = file_sizes.csize; const long csize = file_sizes.csize;
const long dsize = file_sizes.dsize; const long dsize = file_sizes.dsize;
/* const long extra_bytes = ( dsize >> 8 ) + 65536; wrong linux formula */ /* const long extra_bytes = ( dsize >> 8 ) + 65536; wrong linux formula */
const long extra_bytes = ( csize >> 6 ) + file_sizes.members * 36; const long extra_bytes = ( csize >> 6 ) + file_sizes.members * min_member_size;
const long long target_buffer_size = max( dsize, csize ) + extra_bytes; const long long target_buffer_size = max( dsize, csize ) + extra_bytes;
if( target_buffer_size > LONG_MAX ) if( target_buffer_size > LONG_MAX )
{ show_file_error( pp->name, "Buffer is larger than LONG_MAX.", 0 ); { show_file_error( pp->name, "Buffer is larger than LONG_MAX.", 0 );

View file

@ -4,7 +4,7 @@
/* /*
* LZIP decompressor * LZIP decompressor
* *
* Copyright (C) 2016-2021 Antonio Diaz Diaz. * Copyright (C) 2016-2024 Antonio Diaz Diaz.
*/ */
/* Return values (< 0 = Error) */ /* Return values (< 0 = Error) */

18
lzip.h
View file

@ -1,5 +1,5 @@
/* Xlunzip - Test tool for the lzip_decompress linux module /* Xlunzip - Test tool for the lzip_decompress linux module
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -42,23 +42,23 @@ struct Pretty_print
static const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */ static const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */
typedef uint8_t Lzip_header[6]; /* 0-3 magic bytes */ enum { Lh_size = 6 };
typedef uint8_t Lzip_header[Lh_size]; /* 0-3 magic bytes */
/* 4 version */ /* 4 version */
/* 5 coded dictionary size */ /* 5 coded dictionary size */
enum { Lh_size = 6 };
static inline bool Lh_verify_magic( const Lzip_header data ) static inline bool Lh_check_magic( const Lzip_header data )
{ return ( memcmp( data, lzip_magic, 4 ) == 0 ); } { return memcmp( data, lzip_magic, 4 ) == 0; }
static inline bool Lh_verify_version( const Lzip_header data ) static inline bool Lh_check_version( const Lzip_header data )
{ return ( data[4] == 1 ); } { return data[4] == 1; }
typedef uint8_t Lzip_trailer[20]; enum { Lt_size = 20 };
typedef uint8_t Lzip_trailer[Lt_size];
/* 0-3 CRC32 of the uncompressed data */ /* 0-3 CRC32 of the uncompressed data */
/* 4-11 size of the uncompressed data */ /* 4-11 size of the uncompressed data */
/* 12-19 member size including header and trailer */ /* 12-19 member size including header and trailer */
enum { Lt_size = 20 };
static inline unsigned long long Lt_get_data_size( const Lzip_trailer data ) static inline unsigned long long Lt_get_data_size( const Lzip_trailer data )
{ {

View file

@ -1,7 +1,7 @@
/* /*
* LZIP decompressor * LZIP decompressor
* *
* Copyright (C) 2016-2021 Antonio Diaz Diaz. * Copyright (C) 2016-2024 Antonio Diaz Diaz.
* *
* Licensed under GPLv2 or later, see file LICENSE in this source tree. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/ */
@ -32,17 +32,17 @@ static inline State St_set_char(const State st)
static inline State St_set_match(const State st) static inline State St_set_match(const State st)
{ {
return ((st < 7) ? 7 : 10); return (st < 7) ? 7 : 10;
} }
static inline State St_set_rep(const State st) static inline State St_set_rep(const State st)
{ {
return ((st < 7) ? 8 : 11); return (st < 7) ? 8 : 11;
} }
static inline State St_set_short_rep(const State st) static inline State St_set_short_rep(const State st)
{ {
return ((st < 7) ? 9 : 11); return (st < 7) ? 9 : 11;
} }
@ -189,12 +189,12 @@ static inline void CRC32_update_buf(uint32_t * const crc,
STATIC_RW_DATA const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */ STATIC_RW_DATA const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */
typedef uint8_t Lzip_header[6]; /* 0-3 magic bytes */ enum { Lh_size = 6 };
typedef uint8_t Lzip_header[Lh_size]; /* 0-3 magic bytes */
/* 4 version */ /* 4 version */
/* 5 coded dictionary size */ /* 5 coded dictionary size */
enum { Lh_size = 6 };
static inline bool Lh_verify_magic(const Lzip_header data) static inline bool Lh_check_magic(const Lzip_header data)
{ {
int i; int i;
@ -205,34 +205,34 @@ static inline bool Lh_verify_magic(const Lzip_header data)
} }
/* detect (truncated) header */ /* detect (truncated) header */
static inline bool Lh_verify_prefix(const Lzip_header data, const int sz) static inline bool Lh_check_prefix(const Lzip_header data, const int sz)
{ {
int i; int i;
for (i = 0; i < sz && i < 4; ++i) for (i = 0; i < sz && i < 4; ++i)
if (data[i] != lzip_magic[i]) if (data[i] != lzip_magic[i])
return false; return false;
return (sz > 0); return sz > 0;
} }
/* detect corrupt header */ /* detect corrupt header */
static inline bool Lh_verify_corrupt(const Lzip_header data) static inline bool Lh_check_corrupt(const Lzip_header data)
{ {
int matches = 0; int matches = 0;
int i; int i;
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
if (data[i] == lzip_magic[i]) if (data[i] == lzip_magic[i])
++matches; ++matches;
return (matches > 1 && matches < 4); return matches > 1 && matches < 4;
} }
static inline bool Lh_verify_version(const Lzip_header data) static inline bool Lh_check_version(const Lzip_header data)
{ {
return (data[4] == 1); return data[4] == 1;
} }
static inline unsigned Lh_get_dictionary_size(const Lzip_header data) static inline unsigned Lh_get_dictionary_size(const Lzip_header data)
{ {
unsigned sz = (1 << (data[5] & 0x1F)); unsigned sz = 1 << (data[5] & 0x1F);
if (sz > min_dictionary_size) if (sz > min_dictionary_size)
sz -= (sz / 16) * ((data[5] >> 5) & 7); sz -= (sz / 16) * ((data[5] >> 5) & 7);
@ -240,11 +240,11 @@ static inline unsigned Lh_get_dictionary_size(const Lzip_header data)
} }
typedef uint8_t Lzip_trailer[20]; enum { Lt_size = 20 };
typedef uint8_t Lzip_trailer[Lt_size];
/* 0-3 CRC32 of the uncompressed data */ /* 0-3 CRC32 of the uncompressed data */
/* 4-11 size of the uncompressed data */ /* 4-11 size of the uncompressed data */
/* 12-19 member size including header and trailer */ /* 12-19 member size including header and trailer */
enum { Lt_size = 20 };
static inline unsigned Lt_get_data_crc(const Lzip_trailer data) static inline unsigned Lt_get_data_crc(const Lzip_trailer data)
{ {
@ -364,9 +364,9 @@ static inline void Rd_load(struct Range_decoder * const rdec)
int i; int i;
rdec->code = 0; rdec->code = 0;
for (i = 0; i < 5; ++i)
rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
rdec->range = 0xFFFFFFFFU; rdec->range = 0xFFFFFFFFU;
Rd_get_byte(rdec); /* discard first byte of the LZMA stream */
for (i = 0; i < 4; ++i) rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
} }
static inline void Rd_normalize(struct Range_decoder * const rdec) static inline void Rd_normalize(struct Range_decoder * const rdec)
@ -500,11 +500,12 @@ static inline unsigned Rd_decode_len(struct Range_decoder * const rdec,
const int pos_state) const int pos_state)
{ {
if (Rd_decode_bit(rdec, &lm->choice1) == 0) if (Rd_decode_bit(rdec, &lm->choice1) == 0)
return Rd_decode_tree3(rdec, lm->bm_low[pos_state]); return min_match_len +
Rd_decode_tree3(rdec, lm->bm_low[pos_state]);
if (Rd_decode_bit(rdec, &lm->choice2) == 0) if (Rd_decode_bit(rdec, &lm->choice2) == 0)
return len_low_symbols + return min_match_len + len_low_symbols +
Rd_decode_tree3(rdec, lm->bm_mid[pos_state]); Rd_decode_tree3(rdec, lm->bm_mid[pos_state]);
return len_low_symbols + len_mid_symbols + return min_match_len + len_low_symbols + len_mid_symbols +
Rd_decode_tree8(rdec, lm->bm_high); Rd_decode_tree8(rdec, lm->bm_high);
} }
@ -668,7 +669,7 @@ LZd_data_position(const struct LZ_decoder * const d)
} }
static bool LZd_verify_trailer(struct LZ_decoder * const d) static bool LZd_check_trailer(struct LZ_decoder * const d)
{ {
Lzip_trailer trailer; Lzip_trailer trailer;
int i = 0; int i = 0;
@ -676,9 +677,9 @@ static bool LZd_verify_trailer(struct LZ_decoder * const d)
while (i < Lt_size) while (i < Lt_size)
trailer[i++] = Rd_get_byte(d->rdec); trailer[i++] = Rd_get_byte(d->rdec);
return (Lt_get_data_crc(trailer) == LZd_crc(d) && return Lt_get_data_crc(trailer) == LZd_crc(d) &&
Lt_get_data_size(trailer) == LZd_data_position(d) && Lt_get_data_size(trailer) == LZd_data_position(d) &&
Lt_get_member_size(trailer) == Rd_member_position(d->rdec)); Lt_get_member_size(trailer) == Rd_member_position(d->rdec);
} }
@ -736,11 +737,11 @@ static int LZd_decode_member(struct LZ_decoder * const d)
rep0 = distance; rep0 = distance;
} }
state = St_set_rep(state); state = St_set_rep(state);
len = min_match_len + Rd_decode_len(rdec, &d->rep_len_model, pos_state); len = Rd_decode_len(rdec, &d->rep_len_model, pos_state);
} else { /* match */ } else { /* match */
unsigned distance; unsigned distance;
len = min_match_len + Rd_decode_len(rdec, &d->match_len_model, pos_state); len = Rd_decode_len(rdec, &d->match_len_model, pos_state);
distance = Rd_decode_tree6(rdec, d->bm_dis_slot[get_len_state(len)]); distance = Rd_decode_tree6(rdec, d->bm_dis_slot[get_len_state(len)]);
if (distance >= start_dis_model) { if (distance >= start_dis_model) {
const unsigned dis_slot = distance; const unsigned dis_slot = distance;
@ -760,15 +761,11 @@ static int LZd_decode_member(struct LZ_decoder * const d)
if (d->write_error) if (d->write_error)
return LZIP_WRITE_ERROR; return LZIP_WRITE_ERROR;
if (len == min_match_len) { /* End Of Stream marker */ if (len == min_match_len) { /* End Of Stream marker */
if (LZd_verify_trailer(d)) if (LZd_check_trailer(d))
return 0; return 0;
else else
return LZIP_BAD_CRC; return LZIP_BAD_CRC;
} }
if (len == min_match_len + 1) { /* Sync Flush marker */
Rd_load(rdec);
continue;
}
return LZIP_BAD_DATA; /* unknown marker */ return LZIP_BAD_DATA; /* unknown marker */
} }
} }
@ -820,18 +817,18 @@ int lzip_decompress(unsigned char *inbuf, long in_len,
if (Rd_finished(&rdec)) { /* End Of File */ if (Rd_finished(&rdec)) { /* End Of File */
if (first_member) if (first_member)
retval = LZIP_HEADER1_EOF; retval = LZIP_HEADER1_EOF;
else if (Lh_verify_prefix(header, size)) else if (Lh_check_prefix(header, size))
retval = LZIP_HEADER2_EOF; retval = LZIP_HEADER2_EOF;
break; break;
} }
if (!Lh_verify_magic(header)) { if (!Lh_check_magic(header)) {
if (first_member) if (first_member)
retval = LZIP_BAD_MAGIC1; retval = LZIP_BAD_MAGIC1;
else if (Lh_verify_corrupt(header)) else if (Lh_check_corrupt(header))
retval = LZIP_BAD_MAGIC2; retval = LZIP_BAD_MAGIC2;
break; break;
} }
if (!Lh_verify_version(header)) { if (!Lh_check_version(header)) {
retval = LZIP_BAD_VERSION; retval = LZIP_BAD_VERSION;
break; break;
} }

245
main.c
View file

@ -1,5 +1,5 @@
/* Xlunzip - Test tool for the lzip_decompress linux module /* Xlunzip - Test tool for the lzip_decompress linux module
Copyright (C) 2016-2021 Antonio Diaz Diaz. Copyright (C) 2016-2024 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -16,9 +16,9 @@
*/ */
/* /*
Exit status: 0 for a normal exit, 1 for environmental problems Exit status: 0 for a normal exit, 1 for environmental problems
(file not found, invalid flags, I/O errors, etc), 2 to indicate a (file not found, invalid command-line options, I/O errors, etc), 2 to
corrupt or invalid input file, 3 for an internal consistency error indicate a corrupt or invalid input file, 3 for an internal consistency
(eg, bug) which caused xlunzip to panic. error (e.g., bug) which caused xlunzip to panic.
*/ */
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
@ -26,19 +26,19 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h> /* SSIZE_MAX */
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h> /* SIZE_MAX */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h> #include <utime.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) || defined(__DJGPP__) #if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
#include <io.h> #include <io.h>
#if defined(__MSVCRT__) #if defined __MSVCRT__
#define fchmod(x,y) 0 #define fchmod(x,y) 0
#define fchown(x,y,z) 0 #define fchown(x,y,z) 0
#define SIGHUP SIGTERM #define SIGHUP SIGTERM
@ -50,7 +50,7 @@
#define S_IWOTH 0 #define S_IWOTH 0
#endif #endif
#endif #endif
#if defined(__DJGPP__) #if defined __DJGPP__
#define S_ISSOCK(x) 0 #define S_ISSOCK(x) 0
#define S_ISVTX 0 #define S_ISVTX 0
#endif #endif
@ -69,13 +69,18 @@
#error "Environments where CHAR_BIT != 8 are not supported." #error "Environments where CHAR_BIT != 8 are not supported."
#endif #endif
#if ( defined SIZE_MAX && SIZE_MAX < ULONG_MAX ) || \
( defined SSIZE_MAX && SSIZE_MAX < LONG_MAX )
#error "Environments where 'size_t' is narrower than 'long' are not supported."
#endif
static int verbosity = 0; static int verbosity = 0;
static void cleanup_and_fail( const int retval ); static void cleanup_and_fail( const int retval );
static void show_error( const char * const msg, const int errcode, static void show_error( const char * const msg, const int errcode,
const bool help ); const bool help );
static const char * const program_name = "xlunzip"; static const char * const program_name = "xlunzip";
static const char * const program_year = "2021"; static const char * const program_year = "2024";
static const char * invocation_name = "xlunzip"; /* default value */ static const char * invocation_name = "xlunzip"; /* default value */
static const struct { const char * from; const char * to; } known_extensions[] = { static const struct { const char * from; const char * to; } known_extensions[] = {
@ -83,8 +88,6 @@ static const struct { const char * from; const char * to; } known_extensions[] =
{ ".tlz", ".tar" }, { ".tlz", ".tar" },
{ 0, 0 } }; { 0, 0 } };
static int infd = -1; /* needed by the fill function */
/* Variables used in signal handler context. /* Variables used in signal handler context.
They are not declared volatile because the handler never returns. */ They are not declared volatile because the handler never returns. */
static char * output_filename = 0; static char * output_filename = 0;
@ -98,7 +101,7 @@ static void show_help( void )
"linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux\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" "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" "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" "same buffer for input and output). You can use xlunzip to check that the\n"
"module produces correct results when decompressing single member files,\n" "module produces correct results when decompressing single member files,\n"
"multimember files, or the concatenation of two or more compressed 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" "Xlunzip can be used with unzcrash to test the robustness of the module to\n"
@ -132,10 +135,10 @@ static void show_help( void )
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
"\nTo extract all the files from archive 'foo.tar.lz', use the commands\n" "\nTo extract all the files from archive 'foo.tar.lz', use the commands\n"
"'tar -xf foo.tar.lz' or 'xlunzip -cd foo.tar.lz | tar -xf -'.\n" "'tar -xf foo.tar.lz' or 'xlunzip -cd foo.tar.lz | tar -xf -'.\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n" "\nExit status: 0 for a normal exit, 1 for environmental problems\n"
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n" "(file not found, invalid command-line options, I/O errors, etc), 2 to\n"
"invalid input file, 3 for an internal consistency error (eg, bug) which\n" "indicate a corrupt or invalid input file, 3 for an internal consistency\n"
"caused xlunzip to panic.\n" "error (e.g., bug) which caused xlunzip to panic.\n"
"\nReport bugs to lzip-bug@nongnu.org\n" "\nReport bugs to lzip-bug@nongnu.org\n"
"Xlunzip home page: http://www.nongnu.org/lzip/xlunzip.html\n" ); "Xlunzip home page: http://www.nongnu.org/lzip/xlunzip.html\n" );
} }
@ -164,8 +167,6 @@ static void * resize_buffer( void * buf, const unsigned min_size )
static void Pp_init( struct Pretty_print * const pp, static void Pp_init( struct Pretty_print * const pp,
const char * const filenames[], const int num_filenames ) const char * const filenames[], const int num_filenames )
{ {
unsigned stdin_name_len;
int i;
pp->name = 0; pp->name = 0;
pp->padded_name = 0; pp->padded_name = 0;
pp->stdin_name = "(stdin)"; pp->stdin_name = "(stdin)";
@ -173,7 +174,8 @@ static void Pp_init( struct Pretty_print * const pp,
pp->first_post = false; pp->first_post = false;
if( verbosity <= 0 ) return; if( verbosity <= 0 ) return;
stdin_name_len = strlen( pp->stdin_name ); const unsigned stdin_name_len = strlen( pp->stdin_name );
int i;
for( i = 0; i < num_filenames; ++i ) for( i = 0; i < num_filenames; ++i )
{ {
const char * const s = filenames[i]; const char * const s = filenames[i];
@ -204,32 +206,72 @@ static void Pp_set_name( struct Pretty_print * const pp,
static void Pp_show_msg( struct Pretty_print * const pp, const char * const msg ) static void Pp_show_msg( struct Pretty_print * const pp, const char * const msg )
{ {
if( verbosity >= 0 ) if( verbosity < 0 ) return;
if( pp->first_post )
{ {
if( pp->first_post ) pp->first_post = false;
{ fputs( pp->padded_name, stderr );
pp->first_post = false; if( !msg ) fflush( stderr );
fputs( pp->padded_name, stderr );
if( !msg ) fflush( stderr );
}
if( msg ) fprintf( stderr, "%s\n", msg );
} }
if( msg ) fprintf( stderr, "%s\n", msg );
} }
static unsigned long getnum( const char * const ptr, /* separate numbers of 5 or more digits in groups of 3 digits using '_' */
static const char * format_num3( unsigned long long num )
{
enum { buffers = 8, bufsize = 4 * sizeof num, n = 10 };
const char * const si_prefix = "kMGTPEZYRQ";
const char * const binary_prefix = "KMGTPEZYRQ";
static char buffer[buffers][bufsize]; /* circle of static buffers for printf */
static int current = 0;
int i;
char * const buf = buffer[current++]; current %= buffers;
char * p = buf + bufsize - 1; /* fill the buffer backwards */
*p = 0; /* terminator */
if( num > 1024 )
{
char prefix = 0; /* try binary first, then si */
for( i = 0; i < n && num != 0 && num % 1024 == 0; ++i )
{ num /= 1024; prefix = binary_prefix[i]; }
if( prefix ) *(--p) = 'i';
else
for( i = 0; i < n && num != 0 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
}
const bool split = num >= 10000;
for( i = 0; ; )
{
*(--p) = num % 10 + '0'; num /= 10; if( num == 0 ) break;
if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; }
}
return p;
}
void show_option_error( const char * const arg, const char * const msg,
const char * const option_name )
{
if( verbosity >= 0 )
fprintf( stderr, "%s: '%s': %s option '%s'.\n",
program_name, arg, msg, option_name );
}
/* Recognized formats: <num>k, <num>Ki, <num>[MGTPEZYRQ][i] */
static unsigned long getnum( const char * const arg,
const char * const option_name,
const unsigned long llimit, const unsigned long llimit,
const unsigned long ulimit ) const unsigned long ulimit )
{ {
unsigned long result;
char * tail; char * tail;
errno = 0; errno = 0;
result = strtoul( ptr, &tail, 0 ); unsigned long result = strtoul( arg, &tail, 0 );
if( tail == ptr ) if( tail == arg )
{ { show_option_error( arg, "Bad or missing numerical argument in",
show_error( "Bad or missing numerical argument.", 0, true ); option_name ); exit( 1 ); }
exit( 1 );
}
if( !errno && tail[0] ) if( !errno && tail[0] )
{ {
@ -238,6 +280,8 @@ static unsigned long getnum( const char * const ptr,
int i; int i;
switch( tail[0] ) switch( tail[0] )
{ {
case 'Q': exponent = 10; break;
case 'R': exponent = 9; break;
case 'Y': exponent = 8; break; case 'Y': exponent = 8; break;
case 'Z': exponent = 7; break; case 'Z': exponent = 7; break;
case 'E': exponent = 6; break; case 'E': exponent = 6; break;
@ -249,10 +293,8 @@ static unsigned long getnum( const char * const ptr,
case 'k': if( factor == 1000 ) exponent = 1; break; case 'k': if( factor == 1000 ) exponent = 1; break;
} }
if( exponent <= 0 ) if( exponent <= 0 )
{ { show_option_error( arg, "Bad multiplier in numerical argument of",
show_error( "Bad multiplier in numerical argument.", 0, true ); option_name ); exit( 1 ); }
exit( 1 );
}
for( i = 0; i < exponent; ++i ) for( i = 0; i < exponent; ++i )
{ {
if( ulimit / factor >= result ) result *= factor; if( ulimit / factor >= result ) result *= factor;
@ -262,7 +304,10 @@ static unsigned long getnum( const char * const ptr,
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE; if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno ) if( errno )
{ {
show_error( "Numerical argument out of limits.", 0, false ); if( verbosity >= 0 )
fprintf( stderr, "%s: '%s': Value out of limits [%s,%s] in "
"option '%s'.\n", program_name, arg, format_num3( llimit ),
format_num3( ulimit ), option_name );
exit( 1 ); exit( 1 );
} }
return result; return result;
@ -305,7 +350,7 @@ static void set_d_outname( const char * const name, const int eindex )
strcpy( output_filename, name ); strcpy( output_filename, name );
strcat( output_filename, ".out" ); strcat( output_filename, ".out" );
if( verbosity >= 1 ) if( verbosity >= 1 )
fprintf( stderr, "%s: Can't guess original name for '%s' -- using '%s'\n", fprintf( stderr, "%s: %s: Can't guess original name -- using '%s'\n",
program_name, name, output_filename ); program_name, name, output_filename );
} }
@ -326,9 +371,9 @@ static int open_instream( const char * const name, struct stat * const in_statsp
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) ) if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n", fprintf( stderr, "%s: %s: Input file is not a regular file%s.\n",
program_name, name, ( can_read && one_to_one ) ? program_name, name, ( can_read && one_to_one ) ?
",\n and neither '-c' nor '-o' were specified" : "" ); ",\n and neither '-c' nor '-o' were specified" : "" );
close( infd ); close( infd );
infd = -1; infd = -1;
} }
@ -347,16 +392,12 @@ static bool open_outstream( const bool force, const bool protect )
outfd = open( output_filename, flags, outfd_mode ); outfd = open( output_filename, flags, outfd_mode );
if( outfd >= 0 ) delete_output_on_interrupt = true; if( outfd >= 0 ) delete_output_on_interrupt = true;
else if( verbosity >= 0 ) else if( errno == EEXIST )
{ show_file_error( output_filename,
if( errno == EEXIST ) "Output file already exists, skipping.", 0 );
fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n", else
program_name, output_filename ); show_file_error( output_filename, "Can't create output file", errno );
else return outfd >= 0;
fprintf( stderr, "%s: Can't create output file '%s': %s\n",
program_name, output_filename, strerror( errno ) );
}
return ( outfd >= 0 );
} }
@ -374,12 +415,10 @@ static void cleanup_and_fail( const int retval )
if( delete_output_on_interrupt ) if( delete_output_on_interrupt )
{ {
delete_output_on_interrupt = false; delete_output_on_interrupt = false;
if( verbosity >= 0 ) show_file_error( output_filename, "Deleting output file, if it exists.", 0 );
fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n",
program_name, output_filename );
if( outfd >= 0 ) { close( outfd ); outfd = -1; } if( outfd >= 0 ) { close( outfd ); outfd = -1; }
if( remove( output_filename ) != 0 && errno != ENOENT ) if( remove( output_filename ) != 0 && errno != ENOENT )
show_error( "WARNING: deletion of output file (apparently) failed.", 0, false ); show_error( "warning: deletion of output file failed", errno, false );
} }
exit( retval ); exit( retval );
} }
@ -399,7 +438,7 @@ static bool check_tty_in( const char * const input_filename, const int infd,
if( isatty( infd ) ) /* for example /dev/tty */ if( isatty( infd ) ) /* for example /dev/tty */
{ show_file_error( input_filename, { show_file_error( input_filename,
"I won't read compressed data from a terminal.", 0 ); "I won't read compressed data from a terminal.", 0 );
close( infd ); set_retval( retval, 1 ); close( infd ); set_retval( retval, 2 );
if( !testing ) cleanup_and_fail( *retval ); if( !testing ) cleanup_and_fail( *retval );
return false; } return false; }
return true; return true;
@ -413,7 +452,7 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
if( in_statsp ) if( in_statsp )
{ {
const mode_t mode = in_statsp->st_mode; const mode_t mode = in_statsp->st_mode;
/* fchown will in many cases return with EPERM, which can be safely ignored. */ /* fchown in many cases returns with EPERM, which can be safely ignored. */
if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 ) if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 )
{ if( fchmod( outfd, mode ) != 0 ) warning = true; } { if( fchmod( outfd, mode ) != 0 ) warning = true; }
else else
@ -422,10 +461,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
warning = true; warning = true;
} }
if( close( outfd ) != 0 ) if( close( outfd ) != 0 )
{ { show_file_error( output_filename, "Error closing output file", errno );
show_error( "Error closing output file", errno, false ); cleanup_and_fail( 1 ); }
cleanup_and_fail( 1 );
}
outfd = -1; outfd = -1;
delete_output_on_interrupt = false; delete_output_on_interrupt = false;
if( in_statsp ) if( in_statsp )
@ -436,7 +473,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
if( utime( output_filename, &t ) != 0 ) warning = true; if( utime( output_filename, &t ) != 0 ) warning = true;
} }
if( warning && verbosity >= 1 ) if( warning && verbosity >= 1 )
show_error( "Can't change output file attributes.", 0, false ); show_file_error( output_filename,
"warning: can't change output file attributes", errno );
} }
@ -462,13 +500,15 @@ int convert_retval( const int retval )
} }
static int global_infd = -1; /* needed by the fill function */
static long fill( void * buf, unsigned long size ) static long fill( void * buf, unsigned long size )
{ {
unsigned long sz = 0; unsigned long sz = 0;
errno = 0; errno = 0;
while( sz < size ) while( sz < size )
{ {
const int n = read( infd, (uint8_t *)buf + sz, min( 1UL << 20, size - sz ) ); const int n = read( global_infd, (uint8_t *)buf + sz, min( 1UL << 20, size - sz ) );
if( n > 0 ) sz += n; if( n > 0 ) sz += n;
else if( n == 0 ) break; /* EOF */ else if( n == 0 ) break; /* EOF */
else if( errno != EINTR ) break; else if( errno != EINTR ) break;
@ -495,9 +535,9 @@ static const char * global_name; /* copy of filename for 'error' */
static void error(char *x) { show_file_error( global_name, x, 0 ); } static void error(char *x) { show_file_error( global_name, x, 0 ); }
static int decompress( struct Pretty_print * const pp, const long cl_insize, static int decompress( const int infd, struct Pretty_print * const pp,
const long cl_outsize, const bool nofill, const long cl_insize, const long cl_outsize,
const bool noflush, const bool testing ) const bool nofill, const bool noflush, const bool testing )
{ {
long in_len = cl_insize; long in_len = cl_insize;
uint8_t * const inbuf = (in_len > 0) ? malloc( in_len ) : 0; uint8_t * const inbuf = (in_len > 0) ? malloc( in_len ) : 0;
@ -508,17 +548,20 @@ static int decompress( struct Pretty_print * const pp, const long cl_insize,
if( ( in_len > 0 && !inbuf ) || ( out_size > 0 && !outbuf ) ) if( ( in_len > 0 && !inbuf ) || ( out_size > 0 && !outbuf ) )
{ show_error( mem_msg, 0, false ); return 1; } { show_error( mem_msg, 0, false ); return 1; }
global_infd = infd;
if( inbuf ) if( inbuf )
{ {
const long len = fill( inbuf, in_len ); const long len = fill( inbuf, in_len );
if( len < in_len ) if( len < in_len )
{ if( errno ) { show_file_error( pp->name, "Read error", errno ); return 1; } { if( errno ) { show_file_error( pp->name, "Read error", errno );
global_infd = -1; return 1; }
in_len = len; } in_len = len; }
} }
global_name = pp->name; global_name = pp->name;
retval = convert_retval( __lunzip( inbuf, in_len, nofill ? 0 : fill, retval = convert_retval( __lunzip( inbuf, in_len, nofill ? 0 : fill,
noflush ? 0 : flush, outbuf, out_size, noflush ? 0 : flush, outbuf, out_size,
&in_pos, &out_pos, error ) ); &in_pos, &out_pos, error ) );
global_infd = -1;
if( retval ) return retval; if( retval ) return retval;
if( outbuf && noflush ) if( outbuf && noflush )
{ {
@ -586,25 +629,17 @@ static void internal_error( const char * const msg )
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
const char * default_output_filename = ""; const char * default_output_filename = "";
static struct Arg_parser parser; /* static because valgrind complains */
static struct Pretty_print pp; /* and memory management in C sucks */
static const char ** filenames = 0;
long cl_insize = 0; long cl_insize = 0;
long cl_outsize = 0; long cl_outsize = 0;
int num_filenames = 0;
int argind = 0;
int failed_tests = 0;
int retval = 0;
int i; int i;
bool filenames_given = false;
bool force = false; bool force = false;
bool in_place = false; bool in_place = false;
bool keep_input_files = false; bool keep_input_files = false;
bool nofill = false; bool nofill = false;
bool noflush = false; bool noflush = false;
bool stdin_used = false;
bool testing = false; bool testing = false;
bool to_stdout = false; bool to_stdout = false;
if( argc > 0 ) invocation_name = argv[0];
enum { opt_insize = 256, opt_outsize, opt_nofill, opt_noflush }; enum { opt_insize = 256, opt_outsize, opt_nofill, opt_noflush };
const struct ap_Option options[] = const struct ap_Option options[] =
@ -621,24 +656,26 @@ int main( const int argc, const char * const argv[] )
{ 't', "test", ap_no }, { 't', "test", ap_no },
{ 'v', "verbose", ap_no }, { 'v', "verbose", ap_no },
{ 'V', "version", ap_no }, { 'V', "version", ap_no },
{ opt_insize, "insize", ap_maybe }, { opt_insize, "insize", ap_maybe },
{ opt_outsize, "outsize", ap_maybe }, { opt_outsize, "outsize", ap_maybe },
{ opt_nofill, "nofill", ap_no }, { opt_nofill, "nofill", ap_no },
{ opt_noflush, "noflush", ap_no }, { opt_noflush, "noflush", ap_no },
{ 0 , 0, ap_no } }; { 0, 0, ap_no } };
if( argc > 0 ) invocation_name = argv[0];
/* static because valgrind complains and memory management in C sucks */
static struct Arg_parser parser;
if( !ap_init( &parser, argc, argv, options, 0 ) ) if( !ap_init( &parser, argc, argv, options, 0 ) )
{ show_error( mem_msg, 0, false ); return 1; } { show_error( mem_msg, 0, false ); return 1; }
if( ap_error( &parser ) ) /* bad option */ if( ap_error( &parser ) ) /* bad option */
{ show_error( ap_error( &parser ), 0, true ); return 1; } { show_error( ap_error( &parser ), 0, true ); return 1; }
int argind = 0;
for( ; argind < ap_arguments( &parser ); ++argind ) for( ; argind < ap_arguments( &parser ); ++argind )
{ {
const int code = ap_code( &parser, argind ); const int code = ap_code( &parser, argind );
const char * const arg = ap_argument( &parser, argind );
if( !code ) break; /* no more options */ if( !code ) break; /* no more options */
const char * const pn = ap_parsed_name( &parser, argind );
const char * const arg = ap_argument( &parser, argind );
switch( code ) switch( code )
{ {
case 'c': to_stdout = true; break; case 'c': to_stdout = true; break;
@ -655,25 +692,27 @@ int main( const int argc, const char * const argv[] )
case 'v': if( verbosity < 4 ) ++verbosity; break; case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0; case 'V': show_version(); return 0;
case opt_insize: case opt_insize:
cl_insize = arg[0] ? getnum( arg, 1, LONG_MAX ) : 16384; break; cl_insize = arg[0] ? getnum( arg, pn, 1, LONG_MAX ) : 16384; break;
case opt_outsize: cl_outsize = arg[0] ? case opt_outsize: cl_outsize = arg[0] ?
getnum( arg, min_dictionary_size, LONG_MAX ) : max_dictionary_size; getnum( arg, pn, min_dictionary_size, LONG_MAX ) : max_dictionary_size;
break; break;
case opt_nofill: nofill = true; break; case opt_nofill: nofill = true; break;
case opt_noflush: noflush = true; break; case opt_noflush: noflush = true; break;
default : internal_error( "uncaught option." ); default: internal_error( "uncaught option." );
} }
} /* end process options */ } /* end process options */
#if defined(__MSVCRT__) || defined(__OS2__) || defined(__DJGPP__) #if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif
num_filenames = max( 1, ap_arguments( &parser ) - argind ); static const char ** filenames = 0;
int num_filenames = max( 1, ap_arguments( &parser ) - argind );
filenames = resize_buffer( filenames, num_filenames * sizeof filenames[0] ); filenames = resize_buffer( filenames, num_filenames * sizeof filenames[0] );
filenames[0] = "-"; filenames[0] = "-";
bool filenames_given = false;
for( i = 0; argind + i < ap_arguments( &parser ); ++i ) for( i = 0; argind + i < ap_arguments( &parser ); ++i )
{ {
filenames[i] = ap_argument( &parser, argind + i ); filenames[i] = ap_argument( &parser, argind + i );
@ -692,15 +731,18 @@ int main( const int argc, const char * const argv[] )
if( !to_stdout && !testing && ( filenames_given || to_file ) ) if( !to_stdout && !testing && ( filenames_given || to_file ) )
set_signals( signal_handler ); set_signals( signal_handler );
static struct Pretty_print pp;
Pp_init( &pp, filenames, num_filenames ); Pp_init( &pp, filenames, num_filenames );
int failed_tests = 0;
int retval = 0;
const bool one_to_one = !to_stdout && !testing && !to_file; const bool one_to_one = !to_stdout && !testing && !to_file;
bool stdin_used = false;
struct stat in_stats;
for( i = 0; i < num_filenames; ++i ) for( i = 0; i < num_filenames; ++i )
{ {
const char * input_filename = ""; const char * input_filename = "";
int tmp; int infd;
struct stat in_stats;
const struct stat * in_statsp;
Pp_set_name( &pp, filenames[i] ); Pp_set_name( &pp, filenames[i] );
if( strcmp( filenames[i], "-" ) == 0 ) if( strcmp( filenames[i], "-" ) == 0 )
@ -716,15 +758,15 @@ int main( const int argc, const char * const argv[] )
infd = open_instream( input_filename, &in_stats, one_to_one ); infd = open_instream( input_filename, &in_stats, one_to_one );
if( infd < 0 ) { set_retval( &retval, 1 ); continue; } if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
if( !check_tty_in( pp.name, infd, testing, &retval ) ) continue; if( !check_tty_in( pp.name, infd, testing, &retval ) ) continue;
if( one_to_one ) /* open outfd after verifying infd */ if( one_to_one ) /* open outfd after checking infd */
{ {
set_d_outname( input_filename, extension_index( input_filename ) ); set_d_outname( input_filename, extension_index( input_filename ) );
if( !open_outstream( force, true ) ) if( !open_outstream( force, true ) )
{ close( infd ); infd = -1; set_retval( &retval, 1 ); continue; } { close( infd ); set_retval( &retval, 1 ); continue; }
} }
} }
if( to_file && outfd < 0 ) /* open outfd after verifying infd */ if( to_file && outfd < 0 ) /* open outfd after checking infd */
{ {
output_filename = resize_buffer( output_filename, output_filename = resize_buffer( output_filename,
strlen( default_output_filename ) + 1 ); strlen( default_output_filename ) + 1 );
@ -732,15 +774,16 @@ int main( const int argc, const char * const argv[] )
if( !open_outstream( force, false ) ) return 1; if( !open_outstream( force, false ) ) return 1;
} }
in_statsp = ( input_filename[0] && one_to_one ) ? &in_stats : 0; const struct stat * const in_statsp =
( input_filename[0] && one_to_one ) ? &in_stats : 0;
int tmp;
if( in_place ) if( in_place )
tmp = decompress_in_place( infd, &pp, testing ); tmp = decompress_in_place( infd, &pp, testing );
else else
tmp = decompress( &pp, cl_insize, cl_outsize, nofill, noflush, testing ); tmp = decompress( infd, &pp, cl_insize, cl_outsize, nofill, noflush, testing );
if( close( infd ) != 0 ) if( close( infd ) != 0 )
{ show_file_error( pp.name, "Error closing input file", errno ); { show_file_error( pp.name, "Error closing input file", errno );
set_retval( &tmp, 1 ); } set_retval( &tmp, 1 ); }
infd = -1;
set_retval( &retval, tmp ); set_retval( &retval, tmp );
if( tmp ) if( tmp )
{ if( !testing ) cleanup_and_fail( retval ); { if( !testing ) cleanup_and_fail( retval );
@ -751,7 +794,9 @@ int main( const int argc, const char * const argv[] )
if( input_filename[0] && !keep_input_files && one_to_one ) if( input_filename[0] && !keep_input_files && one_to_one )
remove( input_filename ); remove( input_filename );
} }
if( delete_output_on_interrupt ) close_and_set_permissions( 0 ); /* -o */ if( delete_output_on_interrupt ) /* -o */
close_and_set_permissions( ( retval == 0 && !stdin_used &&
filenames_given && num_filenames == 1 ) ? &in_stats : 0 );
else if( outfd >= 0 && close( outfd ) != 0 ) /* -c */ else if( outfd >= 0 && close( outfd ) != 0 ) /* -c */
{ {
show_error( "Error closing stdout", errno, false ); show_error( "Error closing stdout", errno, false );

View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# check script for Xlunzip - Test tool for the lzip_decompress linux module # check script for Xlunzip - Test tool for the lzip_decompress linux module
# Copyright (C) 2016-2021 Antonio Diaz Diaz. # Copyright (C) 2016-2024 Antonio Diaz Diaz.
# #
# This script is free software: you have unlimited permission # This script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
@ -82,33 +82,41 @@ printf "\ntesting decompression..."
for i in "${in_lz}" "${in_em}" ; do for i in "${in_lz}" "${in_em}" ; do
"${LZIP}" -t "$i" || test_failed $LINENO "$i" "${LZIP}" -t "$i" || test_failed $LINENO "$i"
"${LZIP}" -d "$i" -o copy || test_failed $LINENO "$i" "${LZIP}" -d "$i" -o out || test_failed $LINENO "$i"
cmp in copy || test_failed $LINENO "$i" cmp in out || test_failed $LINENO "$i"
"${LZIP}" -cd "$i" > copy || test_failed $LINENO "$i" "${LZIP}" -cd "$i" > out || test_failed $LINENO "$i"
cmp in copy || test_failed $LINENO "$i" cmp in out || test_failed $LINENO "$i"
"${LZIP}" -d "$i" -o - > copy || test_failed $LINENO "$i" "${LZIP}" -d "$i" -o - > out || test_failed $LINENO "$i"
cmp in copy || test_failed $LINENO "$i" cmp in out || test_failed $LINENO "$i"
"${LZIP}" -d < "$i" > copy || test_failed $LINENO "$i" "${LZIP}" -d < "$i" > out || test_failed $LINENO "$i"
cmp in copy || test_failed $LINENO "$i" cmp in out || test_failed $LINENO "$i"
rm -f copy || framework_failure rm -f out || framework_failure
done done
lines=`"${LZIP}" -tvv "${in_em}" 2>&1 | wc -l` || test_failed $LINENO
[ "${lines}" -eq 1 ] || test_failed $LINENO "${lines}"
cat "${in_lz}" > out.lz || framework_failure
"${LZIP}" -dk out.lz || test_failed $LINENO
cmp in out || test_failed $LINENO
rm -f out || framework_failure
"${LZIP}" -cd "${fox_lz}" > fox || test_failed $LINENO
cat fox > copy || framework_failure
cat "${in_lz}" > copy.lz || framework_failure cat "${in_lz}" > copy.lz || framework_failure
"${LZIP}" -dk copy.lz || test_failed $LINENO "${LZIP}" -d copy.lz out.lz 2> /dev/null # skip copy, decompress out
cmp in copy || test_failed $LINENO
printf "to be overwritten" > copy || framework_failure
"${LZIP}" -d copy.lz 2> /dev/null
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
[ ! -e out.lz ] || test_failed $LINENO
cmp fox copy || test_failed $LINENO
cmp in out || test_failed $LINENO
"${LZIP}" -df copy.lz || test_failed $LINENO "${LZIP}" -df copy.lz || test_failed $LINENO
[ ! -e copy.lz ] || test_failed $LINENO [ ! -e copy.lz ] || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in copy || test_failed $LINENO
rm -f copy out || framework_failure
printf "to be overwritten" > copy || framework_failure printf "to be overwritten" > out || framework_failure
"${LZIP}" -d -o copy < "${in_lz}" 2> /dev/null "${LZIP}" -df -o out < "${in_lz}" || test_failed $LINENO
[ $? = 1 ] || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -df -o copy < "${in_lz}" || test_failed $LINENO rm -f out || framework_failure
cmp in copy || test_failed $LINENO
rm -f out copy || framework_failure
"${LZIP}" -d -o ./- "${in_lz}" || test_failed $LINENO "${LZIP}" -d -o ./- "${in_lz}" || test_failed $LINENO
cmp in ./- || test_failed $LINENO cmp in ./- || test_failed $LINENO
rm -f ./- || framework_failure rm -f ./- || framework_failure
@ -117,70 +125,71 @@ cmp in ./- || test_failed $LINENO
rm -f ./- || framework_failure rm -f ./- || framework_failure
cat "${in_lz}" > anyothername || framework_failure cat "${in_lz}" > anyothername || framework_failure
"${LZIP}" -dv - anyothername - < "${in_lz}" > copy 2> /dev/null || "${LZIP}" -dv - anyothername - < "${in_lz}" > out 2> /dev/null ||
test_failed $LINENO test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
cmp in anyothername.out || test_failed $LINENO cmp in anyothername.out || test_failed $LINENO
rm -f copy anyothername.out || framework_failure rm -f out anyothername.out || framework_failure
"${LZIP}" -tq in "${in_lz}" "${LZIP}" -tq in "${in_lz}"
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${LZIP}" -tq nx_file.lz "${in_lz}" "${LZIP}" -tq nx_file.lz "${in_lz}"
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${LZIP}" -cdq in "${in_lz}" > copy "${LZIP}" -cdq in "${in_lz}" > out
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
cat copy in | cmp in - || test_failed $LINENO cat out in | cmp in - || test_failed $LINENO # out must be empty
"${LZIP}" -cdq nx_file.lz "${in_lz}" > copy "${LZIP}" -cdq nx_file.lz "${in_lz}" > out # skip nx_file, decompress in
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
rm -f copy || framework_failure rm -f out || framework_failure
cat "${in_lz}" > copy.lz || framework_failure cat "${in_lz}" > out.lz || framework_failure
"${LZIP}" -dq in copy.lz "${LZIP}" -dq in out.lz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
[ -e copy.lz ] || test_failed $LINENO [ -e out.lz ] || test_failed $LINENO
[ ! -e copy ] || test_failed $LINENO [ ! -e out ] || test_failed $LINENO
[ ! -e in.out ] || test_failed $LINENO [ ! -e in.out ] || test_failed $LINENO
"${LZIP}" -dq nx_file.lz copy.lz "${LZIP}" -dq nx_file.lz out.lz
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
[ ! -e copy.lz ] || test_failed $LINENO [ ! -e out.lz ] || test_failed $LINENO
[ ! -e nx_file ] || test_failed $LINENO [ ! -e nx_file ] || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
rm -f out || framework_failure
cat in in > in2 || framework_failure cat in in > in2 || framework_failure
"${LZIP}" -t "${in_lz}" "${in_lz}" || test_failed $LINENO "${LZIP}" -t "${in_lz}" "${in_lz}" || test_failed $LINENO
"${LZIP}" -cd "${in_lz}" "${in_lz}" -o out > copy2 || test_failed $LINENO "${LZIP}" -cd "${in_lz}" "${in_lz}" -o out > out2 || test_failed $LINENO
[ ! -e out ] || test_failed $LINENO # override -o [ ! -e out ] || test_failed $LINENO # override -o
cmp in2 copy2 || test_failed $LINENO cmp in2 out2 || test_failed $LINENO
rm -f copy2 || framework_failure rm -f out2 || framework_failure
"${LZIP}" -d "${in_lz}" "${in_lz}" -o copy2 || test_failed $LINENO "${LZIP}" -d "${in_lz}" "${in_lz}" -o out2 || test_failed $LINENO
cmp in2 copy2 || test_failed $LINENO cmp in2 out2 || test_failed $LINENO
rm -f copy2 || framework_failure rm -f out2 || framework_failure
cat "${in_lz}" "${in_lz}" > copy2.lz || framework_failure cat "${in_lz}" "${in_lz}" > out2.lz || framework_failure
printf "\ngarbage" >> copy2.lz || framework_failure printf "\ngarbage" >> out2.lz || framework_failure
"${LZIP}" -tvvvv copy2.lz 2> /dev/null || test_failed $LINENO "${LZIP}" -tvvvv out2.lz 2> /dev/null || test_failed $LINENO
printf "to be overwritten" > copy2 || framework_failure printf "to be overwritten" > out2 || framework_failure
"${LZIP}" -df copy2.lz || test_failed $LINENO "${LZIP}" -df out2.lz || test_failed $LINENO
cmp in2 copy2 || test_failed $LINENO cmp in2 out2 || test_failed $LINENO
printf "\ntesting bad input..." printf "\ntesting bad input..."
headers='LZIp LZiP LZip LzIP LzIp LziP lZIP lZIp lZiP lzIP' headers='LZIp LZiP LZip LzIP LzIp LziP lZIP lZIp lZiP lzIP'
body='\001\014\000\203\377\373\377\377\300\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\000\000\000\000' body='\001\014\000\203\377\373\377\377\300\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\000\000\000\000'
cat "${in_lz}" > int.lz cat "${in_lz}" > int.lz || framework_failure
printf "LZIP${body}" >> int.lz printf "LZIP${body}" >> int.lz || framework_failure
if "${LZIP}" -tq int.lz ; then if "${LZIP}" -tq int.lz ; then
for header in ${headers} ; do for header in ${headers} ; do
printf "${header}${body}" > int.lz # first member printf "${header}${body}" > int.lz || framework_failure
"${LZIP}" -tq int.lz "${LZIP}" -tq int.lz # first member
[ $? = 2 ] || test_failed $LINENO ${header} [ $? = 2 ] || test_failed $LINENO ${header}
"${LZIP}" -tq < int.lz "${LZIP}" -tq < int.lz
[ $? = 2 ] || test_failed $LINENO ${header} [ $? = 2 ] || test_failed $LINENO ${header}
"${LZIP}" -cdq int.lz > /dev/null "${LZIP}" -cdq int.lz > /dev/null
[ $? = 2 ] || test_failed $LINENO ${header} [ $? = 2 ] || test_failed $LINENO ${header}
cat "${in_lz}" > int.lz cat "${in_lz}" > int.lz || framework_failure
printf "${header}${body}" >> int.lz # trailing data printf "${header}${body}" >> int.lz || framework_failure
"${LZIP}" -tq int.lz "${LZIP}" -tq int.lz # trailing data
[ $? = 2 ] || test_failed $LINENO ${header} [ $? = 2 ] || test_failed $LINENO ${header}
"${LZIP}" -tq < int.lz "${LZIP}" -tq < int.lz
[ $? = 2 ] || test_failed $LINENO ${header} [ $? = 2 ] || test_failed $LINENO ${header}
@ -198,7 +207,6 @@ for i in fox_v2.lz fox_s11.lz fox_de20.lz \
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
done done
"${LZIP}" -cd "${fox_lz}" > fox || test_failed $LINENO
for i in fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do for i in fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do
"${LZIP}" -cdq "${testdir}"/$i > out "${LZIP}" -cdq "${testdir}"/$i > out
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
@ -216,153 +224,153 @@ if dd if=in3.lz of=trunc.lz bs=14752 count=1 2> /dev/null &&
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${LZIP}" -tq < trunc.lz "${LZIP}" -tq < trunc.lz
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${LZIP}" -cdq trunc.lz > out "${LZIP}" -cdq trunc.lz > /dev/null
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${LZIP}" -dq < trunc.lz > out "${LZIP}" -dq < trunc.lz > /dev/null
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
done done
else else
printf "\nwarning: skipping truncation test: 'dd' does not work on your system." printf "\nwarning: skipping truncation test: 'dd' does not work on your system."
fi fi
rm -f trunc.lz out || framework_failure rm -f trunc.lz || framework_failure
cat "${in_lz}" > ingin.lz || framework_failure cat "${in_lz}" > ingin.lz || framework_failure
printf "g" >> ingin.lz || framework_failure printf "g" >> ingin.lz || framework_failure
cat "${in_lz}" >> ingin.lz || framework_failure cat "${in_lz}" >> ingin.lz || framework_failure
"${LZIP}" -t ingin.lz || test_failed $LINENO "${LZIP}" -t ingin.lz || test_failed $LINENO
"${LZIP}" -t < ingin.lz || test_failed $LINENO "${LZIP}" -t < ingin.lz || test_failed $LINENO
"${LZIP}" -cd ingin.lz > copy || test_failed $LINENO "${LZIP}" -cd ingin.lz > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -d < ingin.lz > copy || test_failed $LINENO "${LZIP}" -d < ingin.lz > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
printf "\ntesting linux options..." printf "\ntesting linux options..."
for i in "" =1 =2 =4 =16 =64 =256 =1024 =4096 =16384 =65536 ; do for i in "" =1 =2 =4 =16 =64 =256 =1024 =4096 =16384 =65536 ; do
"${LZIP}" -t --insize$i "${in_lz}" || test_failed $LINENO $i "${LZIP}" -t --insize$i "${in_lz}" || test_failed $LINENO $i
"${LZIP}" -cd --insize$i "${in_lz}" > copy || test_failed $LINENO $i "${LZIP}" -cd --insize$i "${in_lz}" > out || test_failed $LINENO $i
cmp in copy || test_failed $LINENO $i cmp in out || test_failed $LINENO $i
done done
for i in =1 =2 =4 =16 =64 =256 =1024 =4096 ; do for i in =1 =2 =4 =16 =64 =256 =1024 =4096 ; do
"${LZIP}" -tq --insize$i --nofill "${in_lz}" "${LZIP}" -tq --insize$i --nofill "${in_lz}"
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${LZIP}" -cdq --insize$i --nofill "${in_lz}" > copy "${LZIP}" -cdq --insize$i --nofill "${in_lz}" > out
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
cmp -s in copy && test_failed $LINENO $i cmp -s in out && test_failed $LINENO $i
done done
for i in "" =16384 =65536 ; do for i in "" =16384 =65536 ; do
"${LZIP}" -t --insize$i --nofill "${in_lz}" || test_failed $LINENO $i "${LZIP}" -t --insize$i --nofill "${in_lz}" || test_failed $LINENO $i
"${LZIP}" -cd --insize$i --nofill "${in_lz}" > copy || "${LZIP}" -cd --insize$i --nofill "${in_lz}" > out ||
test_failed $LINENO $i test_failed $LINENO $i
cmp in copy || test_failed $LINENO $i cmp in out || test_failed $LINENO $i
done done
for i in =18KiB =65536 =262144 ; do for i in =18KiB =65536 =262144 ; do
"${LZIP}" -t --outsize$i "${in_lz}" || test_failed $LINENO $i "${LZIP}" -t --outsize$i "${in_lz}" || test_failed $LINENO $i
"${LZIP}" -cd --outsize$i "${in_lz}" > copy || "${LZIP}" -cd --outsize$i "${in_lz}" > out ||
test_failed $LINENO $i test_failed $LINENO $i
cmp in copy || test_failed $LINENO $i cmp in out || test_failed $LINENO $i
done done
for i in =36388 =65536 =262144 ; do for i in =36388 =65536 =262144 ; do
"${LZIP}" -t --outsize$i --noflush "${in_lz}" || "${LZIP}" -t --outsize$i --noflush "${in_lz}" ||
test_failed $LINENO $i test_failed $LINENO $i
"${LZIP}" -cd --outsize$i --noflush "${in_lz}" > copy || "${LZIP}" -cd --outsize$i --noflush "${in_lz}" > out ||
test_failed $LINENO $i test_failed $LINENO $i
cmp in copy || test_failed $LINENO $i cmp in out || test_failed $LINENO $i
done done
for i in =36387 ; do for i in =36387 ; do
"${LZIP}" -tq --outsize$i --noflush "${in_lz}" "${LZIP}" -tq --outsize$i --noflush "${in_lz}"
[ $? = 1 ] || test_failed $LINENO $i [ $? = 1 ] || test_failed $LINENO $i
"${LZIP}" -cdq --outsize$i --noflush "${in_lz}" > copy "${LZIP}" -cdq --outsize$i --noflush "${in_lz}" > out
[ $? = 1 ] || test_failed $LINENO $i [ $? = 1 ] || test_failed $LINENO $i
cmp -s in copy && test_failed $LINENO $i cmp -s in out && test_failed $LINENO $i
done done
for i in =4096 =16384 ; do for i in =4096 =16384 ; do
"${LZIP}" -tq --outsize$i --noflush "${in_lz}" "${LZIP}" -tq --outsize$i --noflush "${in_lz}"
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${LZIP}" -cdq --outsize$i --noflush "${in_lz}" > copy "${LZIP}" -cdq --outsize$i --noflush "${in_lz}" > out
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
cmp -s in copy && test_failed $LINENO $i cmp -s in out && test_failed $LINENO $i
done done
"${LZIP}" -t --insize --outsize=36388 --nofill --noflush "${in_lz}" || "${LZIP}" -t --insize --outsize=36388 --nofill --noflush "${in_lz}" ||
test_failed $LINENO test_failed $LINENO
"${LZIP}" -cd --insize --outsize=36388 --nofill --noflush "${in_lz}" > copy || "${LZIP}" -cd --insize --outsize=36388 --nofill --noflush "${in_lz}" > out ||
test_failed $LINENO test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -tq --nofill "${in_lz}" "${LZIP}" -tq --nofill "${in_lz}"
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${LZIP}" -cdq --nofill "${in_lz}" > copy "${LZIP}" -cdq --nofill "${in_lz}" > out
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
cmp -s in copy && test_failed $LINENO cmp -s in out && test_failed $LINENO
"${LZIP}" -tq --noflush "${in_lz}" "${LZIP}" -tq --noflush "${in_lz}"
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${LZIP}" -cdq --noflush "${in_lz}" > copy "${LZIP}" -cdq --noflush "${in_lz}" > out
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
cmp -s in copy && test_failed $LINENO cmp -s in out && test_failed $LINENO
# decompress in place # decompress in place
rm -f copy copy2 || framework_failure rm -f out out2 || framework_failure
"${LZIP}" -t --in-place "${in_lz}" || test_failed $LINENO "${LZIP}" -t --in-place "${in_lz}" || test_failed $LINENO
"${LZIP}" -t --in-place < "${in_lz}" || test_failed $LINENO "${LZIP}" -t --in-place < "${in_lz}" || test_failed $LINENO
"${LZIP}" -d --in-place "${in_lz}" -o copy || test_failed $LINENO "${LZIP}" -d --in-place "${in_lz}" -o out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
rm -f copy || framework_failure rm -f out || framework_failure
"${LZIP}" -d --in-place < "${in_lz}" -o copy || test_failed $LINENO "${LZIP}" -d --in-place < "${in_lz}" -o out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -cd --in-place "${in_lz}" > copy || test_failed $LINENO "${LZIP}" -cd --in-place "${in_lz}" > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -cd --in-place < "${in_lz}" > copy || test_failed $LINENO "${LZIP}" -cd --in-place < "${in_lz}" > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
"${LZIP}" -t --in-place "${in_lz}" "${in_lz}" || test_failed $LINENO "${LZIP}" -t --in-place "${in_lz}" "${in_lz}" || test_failed $LINENO
"${LZIP}" -d --in-place "${in_lz}" "${in_lz}" -o copy2 || test_failed $LINENO "${LZIP}" -d --in-place "${in_lz}" "${in_lz}" -o out2 || test_failed $LINENO
cmp in2 copy2 || test_failed $LINENO cmp in2 out2 || test_failed $LINENO
"${LZIP}" -cd --in-place "${in_lz}" "${in_lz}" > copy2 || test_failed $LINENO "${LZIP}" -cd --in-place "${in_lz}" "${in_lz}" > out2 || test_failed $LINENO
cmp in2 copy2 || test_failed $LINENO cmp in2 out2 || test_failed $LINENO
# decompress multimember in place # decompress multimember in place
cat in in in > in3 || framework_failure cat in in in > in3 || framework_failure
for i in in2 in3 ; do for i in in2 in3 ; do
"${LZIP}" -t --in-place $i.lz || test_failed $LINENO "${LZIP}" -t --in-place $i.lz || test_failed $LINENO
"${LZIP}" -t --in-place < $i.lz || test_failed $LINENO "${LZIP}" -t --in-place < $i.lz || test_failed $LINENO
rm -f copy || framework_failure rm -f out || framework_failure
"${LZIP}" -d --in-place $i.lz -o copy || test_failed $LINENO "${LZIP}" -d --in-place $i.lz -o out || test_failed $LINENO
cmp $i copy || test_failed $LINENO cmp $i out || test_failed $LINENO
rm -f copy || framework_failure rm -f out || framework_failure
"${LZIP}" -d --in-place < $i.lz -o copy || test_failed $LINENO "${LZIP}" -d --in-place < $i.lz -o out || test_failed $LINENO
cmp $i copy || test_failed $LINENO cmp $i out || test_failed $LINENO
"${LZIP}" -cd --in-place $i.lz > copy || test_failed $LINENO "${LZIP}" -cd --in-place $i.lz > out || test_failed $LINENO
cmp $i copy || test_failed $LINENO cmp $i out || test_failed $LINENO
"${LZIP}" -cd --in-place < $i.lz > copy || test_failed $LINENO "${LZIP}" -cd --in-place < $i.lz > out || test_failed $LINENO
cmp $i copy || test_failed $LINENO cmp $i out || test_failed $LINENO
done done
"${LZIP}" -tq --in-place ingin.lz "${LZIP}" -tq --in-place ingin.lz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
rm -f copy copy2 ingin.lz in2 in2.lz in3 in3.lz || framework_failure rm -f out out2 ingin.lz in2 in2.lz in3 in3.lz || framework_failure
cat "${in_lz}" > inz.lz || framework_failure cat "${in_lz}" > inz.lz || framework_failure
counter=0 counter=0
while [ ${counter} -lt 20 ] ; do while [ ${counter} -lt 20 ] ; do
cat "${zero_lz}" >> inz.lz || framework_failure cat "${zero_lz}" >> inz.lz || framework_failure
"${LZIP}" -t --in-place inz.lz || test_failed $LINENO "${LZIP}" -t --in-place inz.lz || test_failed $LINENO
"${LZIP}" -cd --in-place inz.lz > copy || test_failed $LINENO "${LZIP}" -cd --in-place inz.lz > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
counter=$((counter+1)) counter=$((counter+1))
done done
rm -f copy inz.lz || framework_failure rm -f out inz.lz || framework_failure
# decompress with trailing data in place # decompress with trailing data in place
cat "${in_lz}" in in in in > int.lz || framework_failure cat "${in_lz}" in in in in > int.lz || framework_failure
"${LZIP}" -t --in-place int.lz || test_failed $LINENO "${LZIP}" -t --in-place int.lz || test_failed $LINENO
"${LZIP}" -cd --in-place int.lz > copy || test_failed $LINENO "${LZIP}" -cd --in-place int.lz > out || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in out || test_failed $LINENO
rm -f copy int.lz || framework_failure rm -f out int.lz || framework_failure
echo echo
if [ ${fail} = 0 ] ; then if [ ${fail} = 0 ] ; then